summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source')
-rw-r--r--vcl/source/app/dbggui.cxx2029
-rw-r--r--vcl/source/app/dndhelp.cxx182
-rw-r--r--vcl/source/app/help.cxx787
-rw-r--r--vcl/source/app/i18nhelp.cxx187
-rw-r--r--vcl/source/app/idlemgr.cxx150
-rw-r--r--vcl/source/app/makefile.mk69
-rw-r--r--vcl/source/app/salvtables.cxx144
-rw-r--r--vcl/source/app/session.cxx369
-rwxr-xr-xvcl/source/app/settings.cxx2081
-rw-r--r--vcl/source/app/sound.cxx55
-rw-r--r--vcl/source/app/stdtext.cxx68
-rw-r--r--vcl/source/app/svapp.cxx2085
-rw-r--r--vcl/source/app/svdata.cxx537
-rw-r--r--vcl/source/app/svmain.cxx638
-rw-r--r--vcl/source/app/svmainhook.cxx116
-rw-r--r--vcl/source/app/timer.cxx380
-rw-r--r--vcl/source/app/unohelp.cxx242
-rw-r--r--vcl/source/app/unohelp2.cxx112
-rw-r--r--vcl/source/app/vclevent.cxx151
-rw-r--r--vcl/source/components/display.cxx345
-rw-r--r--vcl/source/components/dtranscomp.cxx552
-rw-r--r--vcl/source/components/factory.cxx200
-rw-r--r--vcl/source/components/fontident.cxx211
-rw-r--r--vcl/source/components/makefile.mk51
-rw-r--r--vcl/source/control/button.cxx4522
-rw-r--r--vcl/source/control/combobox.cxx1583
-rw-r--r--vcl/source/control/ctrl.cxx587
-rw-r--r--vcl/source/control/edit.cxx3140
-rw-r--r--vcl/source/control/field.cxx2474
-rw-r--r--vcl/source/control/field2.cxx3469
-rw-r--r--vcl/source/control/fixbrd.cxx236
-rw-r--r--vcl/source/control/fixed.cxx1174
-rw-r--r--vcl/source/control/group.cxx324
-rw-r--r--vcl/source/control/ilstbox.cxx3233
-rw-r--r--vcl/source/control/imgctrl.cxx269
-rw-r--r--vcl/source/control/longcurr.cxx859
-rw-r--r--vcl/source/control/lstbox.cxx1644
-rw-r--r--vcl/source/control/makefile.mk79
-rw-r--r--vcl/source/control/menubtn.cxx249
-rw-r--r--vcl/source/control/morebtn.cxx280
-rw-r--r--vcl/source/control/scrbar.cxx1648
-rw-r--r--vcl/source/control/slider.cxx1089
-rw-r--r--vcl/source/control/spinbtn.cxx550
-rw-r--r--vcl/source/control/spinfld.cxx1091
-rw-r--r--vcl/source/control/tabctrl.cxx2356
-rw-r--r--vcl/source/fontsubset/cff.cxx2417
-rw-r--r--vcl/source/fontsubset/fontsubset.cxx185
-rw-r--r--vcl/source/fontsubset/gsub.cxx360
-rw-r--r--vcl/source/fontsubset/gsub.h44
-rw-r--r--vcl/source/fontsubset/list.c541
-rw-r--r--vcl/source/fontsubset/makefile.mk51
-rw-r--r--vcl/source/fontsubset/sft.cxx3359
-rw-r--r--vcl/source/fontsubset/ttcr.cxx1666
-rw-r--r--vcl/source/fontsubset/ttcr.hxx261
-rw-r--r--vcl/source/fontsubset/xlat.cxx221
-rw-r--r--vcl/source/fontsubset/xlat.hxx54
-rw-r--r--vcl/source/gdi/alpha.cxx434
-rw-r--r--vcl/source/gdi/animate.cxx939
-rw-r--r--vcl/source/gdi/base14.cxx687
-rw-r--r--vcl/source/gdi/bitmap.cxx1968
-rw-r--r--vcl/source/gdi/bitmap2.cxx1277
-rw-r--r--vcl/source/gdi/bitmap3.cxx2203
-rw-r--r--vcl/source/gdi/bitmap4.cxx1009
-rw-r--r--vcl/source/gdi/bitmapex.cxx914
-rw-r--r--vcl/source/gdi/bmpacc.cxx447
-rw-r--r--vcl/source/gdi/bmpacc2.cxx331
-rw-r--r--vcl/source/gdi/bmpacc3.cxx410
-rw-r--r--vcl/source/gdi/bmpconv.cxx213
-rw-r--r--vcl/source/gdi/bmpfast.cxx1040
-rw-r--r--vcl/source/gdi/configsettings.cxx205
-rw-r--r--vcl/source/gdi/cvtgrf.cxx175
-rw-r--r--vcl/source/gdi/cvtsvm.cxx2516
-rw-r--r--vcl/source/gdi/extoutdevdata.cxx41
-rw-r--r--vcl/source/gdi/font.cxx1116
-rw-r--r--vcl/source/gdi/gdimtf.cxx2990
-rw-r--r--vcl/source/gdi/gfxlink.cxx469
-rw-r--r--vcl/source/gdi/gradient.cxx344
-rw-r--r--vcl/source/gdi/graph.cxx814
-rw-r--r--vcl/source/gdi/graphictools.cxx759
-rw-r--r--vcl/source/gdi/hatch.cxx222
-rw-r--r--vcl/source/gdi/image.cxx1029
-rw-r--r--vcl/source/gdi/imagerepository.cxx57
-rw-r--r--vcl/source/gdi/impanmvw.cxx355
-rw-r--r--vcl/source/gdi/impanmvw.hxx96
-rw-r--r--vcl/source/gdi/impbmp.cxx134
-rw-r--r--vcl/source/gdi/impgraph.cxx1677
-rw-r--r--vcl/source/gdi/impimage.cxx634
-rw-r--r--vcl/source/gdi/impimagetree.cxx352
-rw-r--r--vcl/source/gdi/impprn.cxx584
-rw-r--r--vcl/source/gdi/impvect.cxx1204
-rw-r--r--vcl/source/gdi/impvect.hxx63
-rw-r--r--vcl/source/gdi/jobset.cxx458
-rw-r--r--vcl/source/gdi/lineinfo.cxx361
-rw-r--r--vcl/source/gdi/makefile.mk121
-rw-r--r--vcl/source/gdi/mapmod.cxx311
-rw-r--r--vcl/source/gdi/metaact.cxx4276
-rw-r--r--vcl/source/gdi/metric.cxx916
-rw-r--r--vcl/source/gdi/octree.cxx369
-rw-r--r--vcl/source/gdi/oldprintadaptor.cxx117
-rw-r--r--vcl/source/gdi/outdev.cxx3493
-rw-r--r--vcl/source/gdi/outdev2.cxx2263
-rw-r--r--vcl/source/gdi/outdev3.cxx8022
-rw-r--r--vcl/source/gdi/outdev4.cxx1421
-rw-r--r--vcl/source/gdi/outdev5.cxx313
-rw-r--r--vcl/source/gdi/outdev6.cxx1247
-rw-r--r--vcl/source/gdi/outdevnative.cxx376
-rw-r--r--vcl/source/gdi/outmap.cxx2507
-rw-r--r--vcl/source/gdi/pdfextoutdevdata.cxx798
-rw-r--r--vcl/source/gdi/pdffontcache.cxx85
-rw-r--r--vcl/source/gdi/pdffontcache.hxx81
-rw-r--r--vcl/source/gdi/pdfwriter.cxx571
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx12305
-rw-r--r--vcl/source/gdi/pdfwriter_impl.hxx1375
-rw-r--r--vcl/source/gdi/pngread.cxx1579
-rw-r--r--vcl/source/gdi/pngwrite.cxx737
-rw-r--r--vcl/source/gdi/polyscan.cxx358
-rw-r--r--vcl/source/gdi/print.cxx1481
-rw-r--r--vcl/source/gdi/print2.cxx1570
-rwxr-xr-xvcl/source/gdi/print3.cxx1882
-rw-r--r--vcl/source/gdi/regband.cxx969
-rw-r--r--vcl/source/gdi/region.cxx2932
-rwxr-xr-xvcl/source/gdi/salgdilayout.cxx820
-rwxr-xr-xvcl/source/gdi/sallayout.cxx2326
-rw-r--r--vcl/source/gdi/salmisc.cxx516
-rw-r--r--vcl/source/gdi/salnativewidgets-none.cxx134
-rw-r--r--vcl/source/gdi/svcompat.cxx78
-rw-r--r--vcl/source/gdi/textlayout.cxx386
-rw-r--r--vcl/source/gdi/virdev.cxx449
-rw-r--r--vcl/source/gdi/wall.cxx639
-rw-r--r--vcl/source/glyphs/gcach_ftyp.cxx2557
-rw-r--r--vcl/source/glyphs/gcach_ftyp.hxx255
-rw-r--r--vcl/source/glyphs/gcach_layout.cxx644
-rw-r--r--vcl/source/glyphs/gcach_rbmp.cxx274
-rw-r--r--vcl/source/glyphs/gcach_vdev.cxx287
-rw-r--r--vcl/source/glyphs/gcach_vdev.hxx57
-rw-r--r--vcl/source/glyphs/glyphcache.cxx596
-rw-r--r--vcl/source/glyphs/graphite_adaptors.cxx336
-rw-r--r--vcl/source/glyphs/graphite_cache.cxx200
-rw-r--r--vcl/source/glyphs/graphite_features.cxx286
-rw-r--r--vcl/source/glyphs/graphite_layout.cxx1516
-rw-r--r--vcl/source/glyphs/graphite_serverfont.cxx85
-rw-r--r--vcl/source/glyphs/graphite_textsrc.cxx169
-rw-r--r--vcl/source/glyphs/graphite_textsrc.hxx131
-rw-r--r--vcl/source/glyphs/makefile.mk80
-rw-r--r--vcl/source/helper/canvasbitmap.cxx1467
-rw-r--r--vcl/source/helper/canvastools.cxx837
-rw-r--r--vcl/source/helper/evntpost.cxx65
-rw-r--r--vcl/source/helper/lazydelete.cxx125
-rw-r--r--vcl/source/helper/makefile.mk56
-rwxr-xr-xvcl/source/helper/smartid.cxx264
-rw-r--r--vcl/source/helper/strhelper.cxx442
-rw-r--r--vcl/source/helper/threadex.cxx127
-rw-r--r--vcl/source/helper/xconnection.cxx178
-rw-r--r--vcl/source/salmain/makefile.mk38
-rw-r--r--vcl/source/salmain/salmain.cxx40
-rw-r--r--vcl/source/src/btntext.src147
-rw-r--r--vcl/source/src/helptext.src163
-rw-r--r--vcl/source/src/images.src852
-rw-r--r--vcl/source/src/makefile.mk56
-rw-r--r--vcl/source/src/menu.src107
-rw-r--r--vcl/source/src/print.src492
-rw-r--r--vcl/source/src/stdtext.src127
-rw-r--r--vcl/source/src/units.src57
-rw-r--r--vcl/source/window/abstdlg.cxx64
-rw-r--r--vcl/source/window/accel.cxx731
-rw-r--r--vcl/source/window/accmgr.cxx290
-rw-r--r--vcl/source/window/arrange.cxx903
-rw-r--r--vcl/source/window/brdwin.cxx2353
-rw-r--r--vcl/source/window/btndlg.cxx551
-rw-r--r--vcl/source/window/cmdevt.cxx101
-rw-r--r--vcl/source/window/cursor.cxx462
-rw-r--r--vcl/source/window/decoview.cxx1388
-rw-r--r--vcl/source/window/dialog.cxx1028
-rw-r--r--vcl/source/window/dlgctrl.cxx1246
-rw-r--r--vcl/source/window/dndevdis.cxx564
-rw-r--r--vcl/source/window/dndlcon.cxx567
-rw-r--r--vcl/source/window/dockingarea.cxx246
-rw-r--r--vcl/source/window/dockmgr.cxx1689
-rw-r--r--vcl/source/window/dockwin.cxx1120
-rw-r--r--vcl/source/window/floatwin.cxx878
-rw-r--r--vcl/source/window/introwin.cxx88
-rw-r--r--vcl/source/window/javachild.cxx207
-rw-r--r--vcl/source/window/keycod.cxx160
-rw-r--r--vcl/source/window/keyevent.cxx116
-rw-r--r--vcl/source/window/makefile.mk104
-rw-r--r--vcl/source/window/menu.cxx6106
-rw-r--r--vcl/source/window/mnemonic.cxx419
-rw-r--r--vcl/source/window/mnemonicengine.cxx130
-rw-r--r--vcl/source/window/mouseevent.cxx92
-rw-r--r--vcl/source/window/msgbox.cxx694
-rw-r--r--vcl/source/window/popupmenuwindow.cxx79
-rw-r--r--vcl/source/window/printdlg.cxx2603
-rw-r--r--vcl/source/window/scrwnd.cxx420
-rw-r--r--vcl/source/window/scrwnd.hxx92
-rw-r--r--vcl/source/window/seleng.cxx491
-rw-r--r--vcl/source/window/split.cxx806
-rw-r--r--vcl/source/window/splitwin.cxx3877
-rw-r--r--vcl/source/window/status.cxx1794
-rw-r--r--vcl/source/window/syschild.cxx192
-rw-r--r--vcl/source/window/syswin.cxx1086
-rw-r--r--vcl/source/window/tabdlg.cxx276
-rw-r--r--vcl/source/window/tabpage.cxx216
-rw-r--r--vcl/source/window/taskpanelist.cxx398
-rw-r--r--vcl/source/window/toolbox.cxx6333
-rw-r--r--vcl/source/window/toolbox2.cxx2437
-rw-r--r--vcl/source/window/window.cxx9972
-rw-r--r--vcl/source/window/window2.cxx2065
-rw-r--r--vcl/source/window/window3.cxx82
-rw-r--r--vcl/source/window/winproc.cxx2618
-rw-r--r--vcl/source/window/wrkwin.cxx323
210 files changed, 209676 insertions, 0 deletions
diff --git a/vcl/source/app/dbggui.cxx b/vcl/source/app/dbggui.cxx
new file mode 100644
index 000000000000..dd9a5b4a15ee
--- /dev/null
+++ b/vcl/source/app/dbggui.cxx
@@ -0,0 +1,2029 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <sal/config.h>
+
+#ifdef DBG_UTIL
+
+#include <cstdio>
+#include <cstring>
+#include <cmath>
+#include <limits.h>
+
+#include <vcl/svdata.hxx>
+#include <svsys.h>
+
+#ifdef WNT
+#undef min
+#endif
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+#include <vcl/lstbox.hxx>
+#include <vcl/button.hxx>
+#include <vcl/edit.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/group.hxx>
+#include <vcl/field.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/sound.hxx>
+#include <vcl/threadex.hxx>
+#include <vcl/dbggui.hxx>
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+
+#include <vcl/unohelp.hxx>
+#include <vcl/unohelp2.hxx>
+#include <vos/mutex.hxx>
+
+#include <map>
+#include <algorithm>
+
+using namespace ::com::sun::star;
+
+// =======================================================================
+
+static const sal_Char* pDbgHelpText[] =
+{
+"Object Test\n",
+"------------------------------------------\n",
+"\n",
+"--- Macros ---\n",
+"DBG_NAME( aName )\n",
+"Defines the administration data for a class. This macro may only be used "
+" in a source file with the same name.\n",
+"\n",
+"DBG_NAMEEX( aName )\n",
+"Like DBG_NAME, only for other source files.\n",
+"\n",
+"DBG_CTOR( aName, fTest )\n",
+"Must be used in all constructors of a class (also in the CopyCtor). "
+"The first parameter must be the registered name (best would be the "
+"class name) and the second parameter the test function or 0.\n",
+"\n",
+"DBG_DTOR( aName, fTest )\n",
+"Must be used in the destructor of the class. The first parameter is "
+"the registered name and the second parameter is the test function or "
+"0.\n",
+"\n",
+"DBG_CHKTHIS( aName, fTest )\n",
+"Can be used in methods of the class when constructors and the "
+"desctructor of the class are equiped with the corresponding macros. "
+"The first parameter is the registered name, the second parameter is "
+"the test function or 0.\n",
+"\n",
+"DBG_CHKOBJ( pObj, aName, fTest )\n",
+"Can be used on instances of a class where the constructors and the "
+"destructor of the class are equiped with the corresponding macros. "
+"The first parameter is the registered name, the second parameter is "
+"the test function or 0.\n",
+"\n",
+"To make the macros work DBG_UTIL must be defined.\n",
+"\n",
+"--- Options ---\n",
+"This\n",
+"The This pointer is validated. This way all objects that are equiped "
+"with it can be tested to make sure one is working with existing objects. "
+"This way it's easier to find bugs in case of multiple inheritence, "
+"alignment or compiler errors. Since almost all standard classes of SV "
+"(String, List, Pen, Brush, Polygon, ...) are equiped with DBG_CHKTHIS() "
+"a lot of errors are found, although this test will impact performance "
+"accordingly.\n",
+"\n",
+"Function\n",
+"When a function is passed with macros, it will be called.\n",
+"\n",
+"Exit\n",
+"This- and Func-Test will also run when exiting the function.\n",
+"\n",
+"Report\n",
+"At the end of the program the number of generated objects is produced "
+"as output. Because all important SV classes have at least DBG_CTOR() / "
+"DBG_DTOR() it can checked so called resource leaks (system objects which "
+" are not freed) exist. These include OutputDevice, Window, VirtualDevice, "
+" Printer and Menu. Note: Dtor calls of static objects are not taken into "
+" account. Therefor each SV program leaves 2 strings and a bitmap behind.\n",
+"\n",
+"Trace\n",
+"Creation, destruction and usage of objects which are equiped with "
+"DBG_XTOR is logged.\n",
+"\n",
+"\n",
+"Memory Test\n",
+"------------------------------------------\n",
+"\n",
+"--- Macros ---\n",
+"DBG_MEMTEST()\n",
+"Run the specified memory tests.\n",
+"\n",
+"DBG_MEMTEST_PTR( p )\n",
+"Runs the specified memory tests and validates the pointer that was "
+"passed if the pointer test is enabled.\n",
+"\n",
+"--- Options ---\n",
+"Initialize\n",
+"Allocated memory is initialized with 0x77 and free or freed memory "
+"is initialized with 0x33. This option has almost no impact on performance "
+"and should thus always be enabled during development. This will also "
+"make crashes more often reproducable.\n",
+"\n",
+"Overwrite\n",
+"This test check whether writes occur before or after the blocks. Before "
+"and after the block memory is initialized with 0x55. This option costs "
+"performance, but should be enabled once in a while to test for common "
+"memory overwrites (+-1 errors). This option should also be enabled if the "
+"program crashes in a new or delete operator.\n",
+"\n",
+"Free\n",
+"This checks whether writes occur in free memory. This option costs lots "
+" of performance and should thus only be used to test memory overwrites. "
+" This option should perhaps also be enabled when the program crashes "
+" in the new or delete operator.\n",
+"\n",
+"Pointer\n",
+"The pointer is tested with delete and DBG_MEMTEST_PTR() to see if it was "
+"created by new or SvMemAlloc(). When this option is enabled errors such as "
+"double deletes, deletes on stack objects or invalid pointers will be found. "
+"This option has an impact on performance and should therefor not be enabled "
+"all the time. However, testing should be done with this option enabled once "
+"in a while, because the memory manager does not always crash with delete and "
+"invalid pointers. This option should also be enabled if the program crashes "
+"in new or delete operators.\n",
+"\n",
+"Report\n",
+"At the end of the program a small statistic and memory that was not freed are "
+"output. Note: memory that is freed by global objects is also included in "
+"the leak list.\n",
+"\n",
+"Trace\n",
+"Allocating and freeing memory is logged.\n",
+"\n",
+"Leak report\n",
+"Produces under WNT at the end of the program a list of memory leaks with "
+"stack trace. Only blocks which were created inside Application::Execute() "
+"are included. When this option and Overwrite are both enabled a memory "
+"overwrite results in an attempt to output the stack where the block was "
+"created. The output is included in the log file after the error message.\n"
+"\n",
+"New/Delete\n",
+"Memory tests are performed on the entire memory with every new/delet. "
+"Warning: this option makes programs very slow and should only be enabled "
+"to track memory overwrites. Otherwise it is sufficient to enable "
+"seperate options because (if no leak is present) every detectable "
+"memory overwrite during run time should be found.\n",
+"\n",
+"Object Test\n",
+"Memory test are performed on the entire memory with every object test. "
+"Warning: this option makes programs very slow and should only be enabled "
+"to track memory overwrite. Otherwise it is sufficient to enable "
+"seperate options because (if no leak is present) every detectable "
+"memory overwrite during run time should be found.\n",
+"\n",
+"Windows 16-bit and debug tests\n",
+"Warning: when memory test are enabled (except for Initialize) memory with "
+"offset 0 is never (even not in case of >= 64KB) returned. If necessary the "
+"tests can be performed with 32-bit versions of the programs. To a certain "
+"extend it is sufficient to create 64KB - 64 bytes instead of 64KB because "
+"it will never come to a segment overflow.\n",
+"Memory and object test should only be enabled when only one SV application "
+"is running at one time. Otherwise uncontrolled errors may occur. In this "
+"case only the use of 32-bit programs can help."
+"\n",
+"\n",
+"\nOther tests and macros\n",
+"------------------------------------------\n",
+"\n",
+"Profiling\n",
+"DBG_PROFSTART() / DBG_PROFSTOP() / DBG_PROFCONTINUE() / DBG_PROFPAUSE() "
+"are evaluated and at the end of the program the number of run throughs "
+"and the time this took (including calls to children) in milliseconds is "
+"output. These macros can be used to check the same function runs over the "
+"entire development period, for example the startup speed. The registered name "
+"which was registered with DBG_NAME() must be passed to the macros.\n",
+"\n",
+"Resources\n",
+"In case of resource errors an error dialog is produced before the "
+"exception handler is called.\n",
+"\n",
+"Dialog\n",
+"FixedTexts, CheckBoxes, TriStateBoxes and RadioButtons are equiped with "
+"a different background color to determine the size of the controls. This "
+"test also shows whether controls overlap, whether the tab order is correct "
+"and whether the mnemonic characters are correctly assigned. With dialogs "
+"it is indicated when no default button or no OK/CancelButton is present. "
+"These tests are not 100% correct (e.g. too many warnings are given) and "
+"do not form any guarantee that all problematic cases are covered. For "
+"example only initial and only visible controls are tested. No errors are "
+"found which will occur during the use of a dialog.\n",
+"\n",
+"Bold AppFont\n",
+"The application font is set to bold to see if the position of texts is "
+"sufficient for other systems or other system settings. With very narrow "
+"fonts the dialogs are made wider because they otherwise appear too narrow.\n",
+"\n",
+"Trace output\n",
+"DBG_TRACE() can be use to produce TRACE output. DBG_TRACEFILE() also outputs "
+"the file and line number where the macro is located. DBG_TRACE1() to "
+"DBG_TRACE5() can be used to produce formatted output (printf format string) "
+"Trace output is enabled when the corresponding option is selected in the "
+"dropdown list.\n"
+"\n",
+"Warnings\n",
+"DBG_WARNING() can be used to output warnings. DBG_WARNINGFILE() also outputs "
+"the file and the line number where the macro is located. DBG_WARNING1() to "
+"DBG_WARNING5() can be used to produce formatted output (printf format string). "
+"In case you want to have conditional warnings DBG_ASSERTWARNING() can be "
+"used. The warning will be produced if the condition was not met. The first "
+"parameter is the condition and the second parameter is the message to be "
+"produced. Warnings are enabled if the corresponding option is selected in the "
+"dropdown box. When none are selected the condition with DBG_ASSERTWARNING() "
+"is not evaluated.\n",
+"\n",
+"Errors\n",
+"DBG_ERROR() can be used to produce error messages. DBG_ERRORFILE() also "
+"produces the file and the line number where the macro is located. "
+"DBG_ERROR1() bis DBG_ERROR5() can be used to produce formatted output "
+"(print format string). "
+"In case you want to have conditional warnings DBG_ASSERT() can be "
+"used. The warning will be produced if the condition was not met. The first "
+"parameter is the condition and the second parameter is the message to be "
+"produced. Warnings are enabled if the corresponding option is selected in the "
+"dropdown box. When none are selected the condition with DBG_ASSERT() "
+"is not evaluated.\n",
+"\n",
+"\n",
+"Output\n",
+"------------------------------------------\n",
+"\n",
+"Overwrite - CheckBox\n",
+"With every new program start the log file is overwritten if output has been "
+"generated.\n",
+"\n",
+"Include ObjectTest filters\n",
+"Only classes which contain one of the indicated filters are evaluated with "
+"the object test. Filters are seperated by ';' and are case sensitive. "
+"Wildcards are not supported. If no text is indicated the filters are not "
+"active.\n",
+"\n",
+"Exclude ObjectTest filters\n",
+"Only classes which do not contain one of the indicated filters are evaluated "
+"with the object test. Filters are seperated by ';' and are case sensitive. "
+"Wildcards are not supported. If no text is indicated the filters are not "
+"active.\n",
+"\n",
+"Include filters\n",
+"Only those texts which include the indicated filters are output. "
+"Filters are seperated by ';' and are case sensitive. "
+"Wildcards are not supported. The filter is used for all output (except for "
+"errors). If no text is indicated the filters are not active.\n",
+"\n",
+"Exclude filters\n",
+"Only those texts which do not include the indicated filters are output. "
+"Filters are seperated by ';' and are case sensitive. "
+"Wildcards are not supported. The filter is used for all output (except for "
+"errors). If no text is indicated the filters are not active.\n",
+"\n",
+"Furthermore you can indicate where the data will be output:\n",
+"\n",
+"None\n",
+"Output is surpressed.\n",
+"\n",
+"File\n",
+"Outputi n debug file. Filename can be entered in the Editfield.\n",
+"\n",
+"Window\n",
+"Output to a small debug window. The window size is stored if the debug "
+"dialog is closed with OK and if the window is visible. Each assertion text can "
+"be copied to the clipboard via the context menu of the respective entry.\n",
+"\n",
+"Shell\n",
+"Output to a debug system (Windows debug window) when available or under "
+"Unix in the shell window. Otherwise the same as Window.\n",
+"\n",
+"MessageBox\n",
+"Output to a MessageBox. In this case you can select whether the program "
+"must be continued, terminated (Application::Abort) or interrupted with "
+"CoreDump. Additionally on some systems you get a \"Copy\" button pressing which "
+"copies the text of the MessageBox to the clipboard. Because a MessageBox allows "
+"further event processing other errors caused by Paint, Activate/Deactivate, "
+"GetFocus/LoseFocus can cause more errors or incorrect errors and messages. "
+"Therefor the message should also be directed to a file/debugger in case of "
+"problems in order to produce the (right) error messages.\n",
+"\n",
+"TestTool\n",
+"When the TestTool runs messages will be redirected inside the TestTool.\n",
+"\n",
+"Debugger\n",
+"Attempt to activate the debugger and produce the message there, in order to "
+"always obtain the corresponding stack trace in the debugger.\n",
+"\n",
+"CoreDump\n",
+"Causes a crash\n",
+"\n",
+"\n",
+"Reroute osl messages - Checkbox\n",
+"OSL_ASSERT and similar messages can be intercepted by the general DBG GUI\n",
+"or handled system specific as per normal handling in the sal library.\n",
+"default is to reroute osl assertions\n",
+"\n",
+"\n",
+"Settings\n",
+"------------------------------------------\n",
+"\n",
+"Where by default the INI and LOG file is read and written the following "
+"can be set:\n",
+"\n",
+"WIN/WNT (WIN.INI, Group SV, Default: dbgsv.ini and dbgsv.log):\n",
+"INI: dbgsv\n",
+"LOG: dbgsvlog\n",
+"\n",
+"OS2 (OS2.INI, Application SV, Default: dbgsv.ini and dbgsv.log):\n",
+"INI: DBGSV\n",
+"LOG: DBGSVLOG\n",
+"\n",
+"UNIX (Environment variable, Default: .dbgsv.init and dbgsv.log):\n",
+"INI: DBGSV_INIT\n",
+"LOG: DBGSV_LOG\n",
+"\n",
+"MAC (Default: dbgsv.ini and dbgsv.log):\n",
+"INI: not possible\n",
+"LOG: only debug dialog settings\n",
+"\n",
+"The path and file name must always be specified. The name of the log "
+"file that was entered in the debug dialog has always priority.\n",
+"\n",
+"\n",
+"Example\n",
+"------------------------------------------\n",
+"\n",
+"DBG_NAME( String );\n",
+"\n",
+"#ifdef DBG_UTIL\n",
+"const sal_Char* DbgCheckString( const void* pString )\n",
+"{\n",
+" String* p = (String*)pString;\n",
+"\n",
+" if ( p->mpData->maStr[p->mpData->mnLen] != 0 )\n",
+" return \"String damaged: aStr[nLen] != 0\";\n",
+"\n",
+" return NULL;\n",
+"}\n",
+"#endif\n",
+"\n",
+"String::String()\n",
+"{\n",
+" DBG_CTOR( String, DbgCheckString );\n",
+" // ...\n",
+"}\n",
+"\n",
+"String::~String()\n",
+"{\n",
+" DBG_DTOR( String, DbgCheckString );\n",
+" //...\n",
+"}\n",
+"\n",
+"char& String::operator [] ( USHORT nIndex )\n",
+"{\n",
+" DBG_CHKTHIS( String, DbgCheckString );\n",
+" DBG_ASSERT( nIndex <= pData->nLen, \"String::[] : nIndex > Len\" );\n",
+"\n",
+" //...\n",
+"}\n",
+"\n",
+"USHORT String::Search( const String& rStr, USHORT nIndex ) const\n",
+"{\n",
+" DBG_CHKTHIS( String, DbgCheckString );\n",
+" DBG_CHKOBJ( &rStr, String, DbgCheckString );\n",
+"\n",
+" //...\n",
+"}",
+"\n",
+NULL
+};
+
+// =======================================================================
+
+namespace
+{
+ // -------------------------------------------------------------------
+ typedef ::std::map< XubString, DbgChannelId > UserDefinedChannels;
+ UserDefinedChannels& ImplDbgGetUserDefinedChannels()
+ {
+ static UserDefinedChannels s_aChannels;
+ return s_aChannels;
+ }
+
+ // -------------------------------------------------------------------
+ void ImplAppendUserDefinedChannels( ListBox& rList )
+ {
+ const UserDefinedChannels& rChannels = ImplDbgGetUserDefinedChannels();
+ for ( UserDefinedChannels::const_iterator channel = rChannels.begin();
+ channel != rChannels.end();
+ ++channel
+ )
+ {
+ USHORT nEntryPos = rList.InsertEntry( channel->first );
+ rList.SetEntryData( nEntryPos, reinterpret_cast< void* >( channel->second ) );
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void ImplSelectChannel( ListBox& rList, ULONG nChannelToSelect, USHORT nPositionOffset )
+ {
+ if ( nChannelToSelect < DBG_OUT_USER_CHANNEL_0 )
+ rList.SelectEntryPos( (USHORT)( nChannelToSelect - nPositionOffset ) );
+ else
+ {
+ for ( USHORT pos = 0; pos < rList.GetEntryCount(); ++pos )
+ {
+ DbgChannelId nChannelId = static_cast< DbgChannelId >( reinterpret_cast<sal_IntPtr>(rList.GetEntryData( pos )) );
+ if ( nChannelId == nChannelToSelect )
+ {
+ rList.SelectEntryPos( pos );
+ return;
+ }
+ }
+ }
+ }
+ // -------------------------------------------------------------------
+ DbgChannelId ImplGetChannelId( const ListBox& rList, USHORT nPositionOffset )
+ {
+ USHORT nSelectedChannelPos = rList.GetSelectEntryPos();
+ DbgChannelId nSelectedChannel = static_cast< DbgChannelId >( reinterpret_cast<sal_IntPtr>(rList.GetEntryData( nSelectedChannelPos )) );
+ if ( nSelectedChannel == 0)
+ return (DbgChannelId)( nSelectedChannelPos + nPositionOffset );
+ return nSelectedChannel;
+ }
+}
+
+// =======================================================================
+
+// -------------
+// - DbgWindow -
+// -------------
+
+#define DBGWIN_MAXLINES 100
+
+class DbgWindow : public WorkWindow
+{
+private:
+ ListBox maLstBox;
+
+public:
+ DbgWindow();
+
+ virtual BOOL Close();
+ virtual void Resize();
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ void InsertLine( const XubString& rLine );
+ void Update() { WorkWindow::Update(); maLstBox.Update(); }
+
+private:
+ void GetAssertionEntryRange( USHORT nInbetweenEntry, USHORT& nFirst, USHORT& nLast );
+};
+
+// -----------------
+// - DbgInfoDialog -
+// -----------------
+
+class DbgInfoDialog : public ModalDialog
+{
+private:
+ ListBox maListBox;
+ OKButton maOKButton;
+ BOOL mbHelpText;
+
+public:
+ DbgInfoDialog( Window* pParent, BOOL bHelpText = FALSE );
+
+ void SetInfoText( const XubString& rStr );
+};
+
+// -------------
+// - DbgDialog -
+// -------------
+
+class DbgDialog : public ModalDialog
+{
+private:
+ CheckBox maXtorThis;
+ CheckBox maXtorFunc;
+ CheckBox maXtorExit;
+ CheckBox maXtorReport;
+ CheckBox maXtorTrace;
+ GroupBox maBox1;
+
+ CheckBox maMemInit;
+ CheckBox maMemOverwrite;
+ CheckBox maMemOverwriteFree;
+ CheckBox maMemPtr;
+ CheckBox maMemReport;
+ CheckBox maMemTrace;
+ CheckBox maMemLeakReport;
+ CheckBox maMemNewDel;
+ CheckBox maMemXtor;
+ GroupBox maBox2;
+
+ CheckBox maProf;
+ CheckBox maRes;
+ CheckBox maDialog;
+ CheckBox maBoldAppFont;
+ GroupBox maBox3;
+
+ Edit maDebugName;
+ CheckBox maOverwrite;
+ FixedText maInclClassText;
+ Edit maInclClassFilter;
+ FixedText maExclClassText;
+ Edit maExclClassFilter;
+ FixedText maInclText;
+ Edit maInclFilter;
+ FixedText maExclText;
+ Edit maExclFilter;
+ FixedText maTraceText;
+ ListBox maTraceBox;
+ FixedText maWarningText;
+ ListBox maWarningBox;
+ FixedText maErrorText;
+ ListBox maErrorBox;
+ CheckBox maHookOSLBox;
+ GroupBox maBox4;
+
+ OKButton maOKButton;
+ CancelButton maCancelButton;
+ PushButton maInfoButton;
+ HelpButton maHelpButton;
+ USHORT mnErrorOff;
+
+public:
+ DbgDialog();
+
+ DECL_LINK( ClickHdl, Button* );
+ void RequestHelp( const HelpEvent& rHEvt );
+};
+
+// =======================================================================
+
+static sal_Char aDbgInfoBuf[12288];
+static sal_Char aDbgOutBuf[DBG_BUF_MAXLEN];
+
+// =======================================================================
+
+DbgWindow::DbgWindow() :
+ WorkWindow( NULL, WB_STDWORK ),
+ maLstBox( this, WB_AUTOHSCROLL )
+{
+ DbgData* pData = DbgGetData();
+
+ maLstBox.Show();
+ maLstBox.SetPosPixel( Point( 0, 0 ) );
+
+ SetOutputSizePixel( Size( 600, 480 ) );
+ if ( pData->aDbgWinState )
+ {
+ ByteString aState( pData->aDbgWinState );
+ SetWindowState( aState );
+ }
+
+ SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "StarView Debug Window" ) ) );
+ Show();
+ Update();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DbgWindow::Close()
+{
+ // remember window position
+ ByteString aState( GetWindowState() );
+ DbgData* pData = DbgGetData();
+ strncpy( pData->aDbgWinState,
+ aState.GetBuffer(),
+ std::min( sizeof( pData->aDbgWinState ),
+ size_t(aState.Len() + 1U )) );
+ pData->aDbgWinState[ sizeof( pData->aDbgWinState ) - 1 ] = 0;
+ // and save for next session
+ DbgSaveData( *pData );
+
+ delete this;
+ ImplGetSVData()->maWinData.mpDbgWin = NULL;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void DbgWindow::Resize()
+{
+ maLstBox.SetSizePixel( GetOutputSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+void DbgWindow::GetAssertionEntryRange( USHORT nInbetweenEntry, USHORT& nFirst, USHORT& nLast )
+{
+ nFirst = nInbetweenEntry;
+ while ( nFirst > 0 )
+ {
+ if ( maLstBox.GetEntryData( nFirst ) != NULL )
+ break;
+ --nFirst;
+ }
+ USHORT nEntryCount = maLstBox.GetEntryCount();
+ nLast = nInbetweenEntry + 1;
+ while ( nLast < nEntryCount )
+ {
+ if ( maLstBox.GetEntryData( nLast ) != NULL )
+ break;
+ ++nLast;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long DbgWindow::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ if ( maLstBox.IsWindowOrChild( rNEvt.GetWindow() ) )
+ {
+ const CommandEvent& rCommand = *rNEvt.GetCommandEvent();
+ if ( rCommand.GetCommand() == COMMAND_CONTEXTMENU )
+ {
+ PopupMenu aMenu;
+ aMenu.InsertItem( 1, String::CreateFromAscii( "copy to clipboard" ) );
+
+ Point aPos;
+ if ( rCommand.IsMouseEvent() )
+ aPos = rCommand.GetMousePosPixel();
+ else
+ {
+ Rectangle aEntryRect( maLstBox.GetBoundingRectangle( maLstBox.GetSelectEntryPos() ) );
+ aPos = aEntryRect.Center();
+ }
+ USHORT nSelected = aMenu.Execute( rNEvt.GetWindow(), aPos );
+ if ( nSelected == 1 )
+ {
+ // search all entries which belong to this assertion
+ USHORT nAssertionFirst = 0;
+ USHORT nAssertionLast = 0;
+ GetAssertionEntryRange( maLstBox.GetSelectEntryPos(), nAssertionFirst, nAssertionLast );
+
+ // build the string to copy to the clipboard
+ String sAssertion;
+ String sLineFeed = String::CreateFromAscii( "\n" );
+ sLineFeed.ConvertLineEnd( GetSystemLineEnd() );
+ while ( nAssertionFirst < nAssertionLast )
+ {
+ sAssertion += maLstBox.GetEntry( nAssertionFirst++ );
+ sAssertion += sLineFeed;
+ }
+
+ ::vcl::unohelper::TextDataObject::CopyStringTo( sAssertion, GetClipboard() );
+ }
+ }
+ return 1; // handled
+ }
+ }
+ return WorkWindow::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void DbgWindow::InsertLine( const XubString& rLine )
+{
+ XubString aStr = rLine;
+ aStr.ConvertLineEnd( LINEEND_LF );
+ xub_StrLen nPos = aStr.Search( _LF );
+ BOOL bFirstEntry = TRUE;
+ while ( nPos != STRING_NOTFOUND )
+ {
+ if ( maLstBox.GetEntryCount() >= DBGWIN_MAXLINES )
+ maLstBox.RemoveEntry( 0 );
+
+ USHORT nInsertionPos = maLstBox.InsertEntry( aStr.Copy( 0, nPos ) );
+ if ( bFirstEntry )
+ maLstBox.SetEntryData( nInsertionPos, reinterpret_cast< void* >( 0x00000001 ) );
+ bFirstEntry = FALSE;
+
+ aStr.Erase( 0, nPos+1 );
+ nPos = aStr.Search( _LF );
+ }
+ if ( maLstBox.GetEntryCount() >= DBGWIN_MAXLINES )
+ maLstBox.RemoveEntry( 0 );
+ USHORT nInsertionPos = maLstBox.InsertEntry( aStr );
+ if ( bFirstEntry )
+ maLstBox.SetEntryData( nInsertionPos, reinterpret_cast< void* >( 0x00000001 ) );
+ maLstBox.SetTopEntry( DBGWIN_MAXLINES-1 );
+ maLstBox.Update();
+}
+
+// =======================================================================
+
+DbgDialog::DbgDialog() :
+ ModalDialog( NULL, WB_STDMODAL | WB_SYSTEMWINDOW ),
+ maXtorThis( this ),
+ maXtorFunc( this ),
+ maXtorExit( this ),
+ maXtorReport( this ),
+ maXtorTrace( this ),
+ maBox1( this ),
+ maMemInit( this ),
+ maMemOverwrite( this ),
+ maMemOverwriteFree( this ),
+ maMemPtr( this ),
+ maMemReport( this ),
+ maMemTrace( this ),
+ maMemLeakReport( this ),
+ maMemNewDel( this ),
+ maMemXtor( this ),
+ maBox2( this ),
+ maProf( this ),
+ maRes( this ),
+ maDialog( this ),
+ maBoldAppFont( this ),
+ maBox3( this ),
+ maDebugName( this ),
+ maOverwrite( this ),
+ maInclClassText( this ),
+ maInclClassFilter( this ),
+ maExclClassText( this ),
+ maExclClassFilter( this ),
+ maInclText( this ),
+ maInclFilter( this ),
+ maExclText( this ),
+ maExclFilter( this ),
+ maTraceText( this ),
+ maTraceBox( this, WB_DROPDOWN ),
+ maWarningText( this ),
+ maWarningBox( this, WB_DROPDOWN ),
+ maErrorText( this ),
+ maErrorBox( this, WB_DROPDOWN ),
+ maHookOSLBox( this ),
+ maBox4( this ),
+ maOKButton( this, WB_DEFBUTTON ),
+ maCancelButton( this ),
+ maInfoButton( this ),
+ maHelpButton( this )
+{
+ DbgData* pData = DbgGetData();
+ MapMode aAppMap( MAP_APPFONT );
+ Size aButtonSize = LogicToPixel( Size( 60, 12 ), aAppMap );
+
+ {
+ maXtorThis.Show();
+ maXtorThis.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "T~his" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_XTOR_THIS )
+ maXtorThis.Check( TRUE );
+ maXtorThis.SetPosSizePixel( LogicToPixel( Point( 10, 15 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maXtorFunc.Show();
+ maXtorFunc.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Function" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_XTOR_FUNC )
+ maXtorFunc.Check( TRUE );
+ maXtorFunc.SetPosSizePixel( LogicToPixel( Point( 75, 15 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maXtorExit.Show();
+ maXtorExit.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "E~xit" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_XTOR_EXIT )
+ maXtorExit.Check( TRUE );
+ maXtorExit.SetPosSizePixel( LogicToPixel( Point( 140, 15 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maXtorReport.Show();
+ maXtorReport.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Report" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_XTOR_REPORT )
+ maXtorReport.Check( TRUE );
+ maXtorReport.SetPosSizePixel( LogicToPixel( Point( 205, 15 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maXtorTrace.Show();
+ maXtorTrace.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Trace" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_XTOR_TRACE )
+ maXtorTrace.Check( TRUE );
+ maXtorTrace.SetPosSizePixel( LogicToPixel( Point( 270, 15 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maBox1.Show();
+ maBox1.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Object Tests" ) ) );
+ maBox1.SetPosSizePixel( LogicToPixel( Point( 5, 5 ), aAppMap ),
+ LogicToPixel( Size( 330, 30 ), aAppMap ) );
+ }
+
+ {
+ maMemInit.Show();
+ maMemInit.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Initialize" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_INIT )
+ maMemInit.Check( TRUE );
+ maMemInit.SetPosSizePixel( LogicToPixel( Point( 10, 50 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemOverwrite.Show();
+ maMemOverwrite.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Overwrite" )) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_OVERWRITE )
+ maMemOverwrite.Check( TRUE );
+ maMemOverwrite.SetPosSizePixel( LogicToPixel( Point( 75, 50 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemOverwriteFree.Show();
+ maMemOverwriteFree.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Free" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_OVERWRITEFREE )
+ maMemOverwriteFree.Check( TRUE );
+ maMemOverwriteFree.SetPosSizePixel( LogicToPixel( Point( 140, 50 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemPtr.Show();
+ maMemPtr.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Pointer" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_POINTER )
+ maMemPtr.Check( TRUE );
+ maMemPtr.SetPosSizePixel( LogicToPixel( Point( 205, 50 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemReport.Show();
+ maMemReport.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Report" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_REPORT )
+ maMemReport.Check( TRUE );
+ maMemReport.SetPosSizePixel( LogicToPixel( Point( 270, 50 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemTrace.Show();
+ maMemTrace.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Trace" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_TRACE )
+ maMemTrace.Check( TRUE );
+ maMemTrace.SetPosSizePixel( LogicToPixel( Point( 10, 65 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemLeakReport.Show();
+ maMemLeakReport.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Leak-Report" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_LEAKREPORT )
+ maMemLeakReport.Check( TRUE );
+ maMemLeakReport.SetPosSizePixel( LogicToPixel( Point( 75, 65 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemNewDel.Show();
+ maMemNewDel.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~New/Delete" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_NEWDEL )
+ maMemNewDel.Check( TRUE );
+ maMemNewDel.SetPosSizePixel( LogicToPixel( Point( 140, 65 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maMemXtor.Show();
+ maMemXtor.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Ob~ject Test" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_MEM_XTOR )
+ maMemXtor.Check( TRUE );
+ maMemXtor.SetPosSizePixel( LogicToPixel( Point( 205, 65 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maBox2.Show();
+ maBox2.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Memory Tests" ) ) );
+ maBox2.SetPosSizePixel( LogicToPixel( Point( 5, 40 ), aAppMap ),
+ LogicToPixel( Size( 330, 40 ), aAppMap ) );
+ }
+
+ {
+ maProf.Show();
+ maProf.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Profiling" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_PROFILING )
+ maProf.Check( TRUE );
+ maProf.SetPosSizePixel( LogicToPixel( Point( 10, 95 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maRes.Show();
+ maRes.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Resourcen" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_RESOURCE )
+ maRes.Check( TRUE );
+ maRes.SetPosSizePixel( LogicToPixel( Point( 75, 95 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maDialog.Show();
+ maDialog.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Dialog" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_DIALOG )
+ maDialog.Check( TRUE );
+ maDialog.SetPosSizePixel( LogicToPixel( Point( 140, 95 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maBoldAppFont.Show();
+ maBoldAppFont.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Bold AppFont" ) ) );
+ if ( pData->nTestFlags & DBG_TEST_BOLDAPPFONT )
+ maBoldAppFont.Check( TRUE );
+ maBoldAppFont.SetPosSizePixel( LogicToPixel( Point( 205, 95 ), aAppMap ),
+ aButtonSize );
+ maBoldAppFont.SaveValue();
+ }
+
+ {
+ maBox3.Show();
+ maBox3.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Test Options" ) ) );
+ maBox3.SetPosSizePixel( LogicToPixel( Point( 5, 85 ), aAppMap ),
+ LogicToPixel( Size( 330, 30 ), aAppMap ) );
+ }
+
+ {
+ maDebugName.Show();
+ maDebugName.SetText( XubString( pData->aDebugName, RTL_TEXTENCODING_UTF8 ) );
+ maDebugName.SetMaxTextLen( sizeof( pData->aDebugName ) );
+ maDebugName.SetPosSizePixel( LogicToPixel( Point( 10, 130 ), aAppMap ),
+ LogicToPixel( Size( 185, 14 ), aAppMap ) );
+ }
+
+ {
+ maOverwrite.Show();
+ maOverwrite.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Overwrite ~File" ) ) );
+ if ( pData->bOverwrite )
+ maOverwrite.Check( TRUE );
+ maOverwrite.SetPosSizePixel( LogicToPixel( Point( 205, 130 ), aAppMap ),
+ aButtonSize );
+ }
+
+ {
+ maHookOSLBox.Show();
+ maHookOSLBox.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Reroute osl debug ~messages" ) ) );
+ if ( pData->bHookOSLAssert )
+ maHookOSLBox.Check( TRUE );
+ maHookOSLBox.SetPosSizePixel( LogicToPixel( Point( 10, 240 ), aAppMap ),
+ LogicToPixel( Size( 100, 12 ), aAppMap ) );
+ }
+
+ {
+ maInclClassText.Show();
+ maInclClassText.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Include-ObjectTest-Filter" ) ) );
+ maInclClassText.SetPosSizePixel( LogicToPixel( Point( 10, 150 ), aAppMap ),
+ LogicToPixel( Size( 95, 9 ), aAppMap ) );
+ }
+
+ {
+ maInclClassFilter.Show();
+ maInclClassFilter.SetText( XubString( pData->aInclClassFilter, RTL_TEXTENCODING_UTF8 ) );
+ maInclClassFilter.SetMaxTextLen( sizeof( pData->aInclClassFilter ) );
+ maInclClassFilter.SetPosSizePixel( LogicToPixel( Point( 10, 160 ), aAppMap ),
+ LogicToPixel( Size( 95, 14 ), aAppMap ) );
+ }
+
+ {
+ maExclClassText.Show();
+ maExclClassText.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Exclude-ObjectTest-Filter" ) ) );
+ maExclClassText.SetPosSizePixel( LogicToPixel( Point( 115, 150 ), aAppMap ),
+ LogicToPixel( Size( 95, 9 ), aAppMap ) );
+ }
+
+ {
+ maExclClassFilter.Show();
+ maExclClassFilter.SetText( XubString( pData->aExclClassFilter, RTL_TEXTENCODING_UTF8 ) );
+ maExclClassFilter.SetMaxTextLen( sizeof( pData->aExclClassFilter ) );
+ maExclClassFilter.SetPosSizePixel( LogicToPixel( Point( 115, 160 ), aAppMap ),
+ LogicToPixel( Size( 95, 14 ), aAppMap ) );
+ }
+
+ {
+ maInclText.Show();
+ maInclText.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Include-Filter" ) ) );
+ maInclText.SetPosSizePixel( LogicToPixel( Point( 10, 180 ), aAppMap ),
+ LogicToPixel( Size( 95, 9 ), aAppMap ) );
+ }
+
+ {
+ maInclFilter.Show();
+ maInclFilter.SetText( XubString( pData->aInclFilter, RTL_TEXTENCODING_UTF8 ) );
+ maInclFilter.SetMaxTextLen( sizeof( pData->aInclFilter ) );
+ maInclFilter.SetPosSizePixel( LogicToPixel( Point( 10, 190 ), aAppMap ),
+ LogicToPixel( Size( 95, 14 ), aAppMap ) );
+ }
+
+ {
+ maExclText.Show();
+ maExclText.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Exclude-Filter" ) ) );
+ maExclText.SetPosSizePixel( LogicToPixel( Point( 115, 180 ), aAppMap ),
+ LogicToPixel( Size( 95, 9 ), aAppMap ) );
+ }
+
+ {
+ maExclFilter.Show();
+ maExclFilter.SetText( XubString( pData->aExclFilter, RTL_TEXTENCODING_UTF8 ) );
+ maExclFilter.SetMaxTextLen( sizeof( pData->aExclFilter ) );
+ maExclFilter.SetPosSizePixel( LogicToPixel( Point( 115, 190 ), aAppMap ),
+ LogicToPixel( Size( 95, 14 ), aAppMap ) );
+ }
+
+ {
+ maTraceText.Show();
+ maTraceText.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Trace" ) ) );
+ maTraceText.SetPosSizePixel( LogicToPixel( Point( 10, 210 ), aAppMap ),
+ LogicToPixel( Size( 95, 9 ), aAppMap ) );
+ }
+
+ {
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "File" ) ) );
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Window" ) ) );
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Shell" ) ) );
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "MessageBox" ) ) );
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "TestTool" ) ) );
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Debugger" ) ) );
+ maTraceBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "CoreDump" ) ) );
+ ImplAppendUserDefinedChannels( maTraceBox );
+ ImplSelectChannel( maTraceBox, pData->nTraceOut, 0 );
+ maTraceBox.Show();
+ maTraceBox.SetPosSizePixel( LogicToPixel( Point( 10, 220 ), aAppMap ),
+ LogicToPixel( Size( 95, 80 ), aAppMap ) );
+ }
+
+ {
+ maWarningText.Show();
+ maWarningText.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Warning" ) ) );
+ maWarningText.SetPosSizePixel( LogicToPixel( Point( 115, 210 ), aAppMap ),
+ LogicToPixel( Size( 95, 9 ), aAppMap ) );
+ }
+
+ {
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "File" ) ) );
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Window" ) ) );
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Shell" ) ) );
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "MessageBox" ) ) );
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "TestTool" ) ) );
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Debugger" ) ) );
+ maWarningBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "CoreDump" ) ) );
+ ImplAppendUserDefinedChannels( maWarningBox );
+ ImplSelectChannel( maWarningBox, pData->nWarningOut, 0 );
+ maWarningBox.Show();
+ maWarningBox.SetPosSizePixel( LogicToPixel( Point( 115, 220 ), aAppMap ),
+ LogicToPixel( Size( 95, 80 ), aAppMap ) );
+ }
+
+ {
+ maErrorText.Show();
+ maErrorText.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Error" ) ) );
+ maErrorText.SetPosSizePixel( LogicToPixel( Point( 220, 210 ), aAppMap ),
+ LogicToPixel( Size( 95, 9 ), aAppMap ) );
+ }
+
+ {
+ if ( DbgIsAllErrorOut() )
+ {
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "File" ) ) );
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Window" ) ) );
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Shell" ) ) );
+ mnErrorOff = 0;
+ }
+ else
+ mnErrorOff = 4;
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "MessageBox" ) ) );
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "TestTool" ) ) );
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "Debugger" ) ) );
+ maErrorBox.InsertEntry( XubString( RTL_CONSTASCII_USTRINGPARAM( "CoreDump" ) ) );
+ ImplAppendUserDefinedChannels( maErrorBox );
+ ImplSelectChannel( maErrorBox, pData->nErrorOut, mnErrorOff );
+ maErrorBox.Show();
+ maErrorBox.SetPosSizePixel( LogicToPixel( Point( 220, 220 ), aAppMap ),
+ LogicToPixel( Size( 95, 80 ), aAppMap ) );
+ }
+
+ {
+ maBox4.Show();
+ maBox4.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Output" ) ) );
+ maBox4.SetPosSizePixel( LogicToPixel( Point( 5, 120 ), aAppMap ),
+ LogicToPixel( Size( 330, 135 ), aAppMap ) );
+ }
+
+ {
+ maOKButton.Show();
+ maOKButton.SetClickHdl( LINK( this, DbgDialog, ClickHdl ) );
+ maOKButton.SetPosSizePixel( LogicToPixel( Point( 10, 260 ), aAppMap ),
+ LogicToPixel( Size( 50, 15 ), aAppMap ) );
+ }
+ {
+ maCancelButton.Show();
+ maCancelButton.SetPosSizePixel( LogicToPixel( Point( 70, 260 ), aAppMap ),
+ LogicToPixel( Size( 50, 15 ), aAppMap ) );
+ }
+ {
+ maInfoButton.Show();
+ maInfoButton.SetClickHdl( LINK( this, DbgDialog, ClickHdl ) );
+ maInfoButton.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "~Info..." ) ) );
+ maInfoButton.SetPosSizePixel( LogicToPixel( Point( 130, 260 ), aAppMap ),
+ LogicToPixel( Size( 50, 15 ), aAppMap ) );
+ }
+ {
+ maHelpButton.Show();
+ maHelpButton.SetPosSizePixel( LogicToPixel( Point( 190, 260 ), aAppMap ),
+ LogicToPixel( Size( 50, 15 ), aAppMap ) );
+ }
+
+ {
+ SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "VCL Debug Options" ) ) );
+ SetOutputSizePixel( LogicToPixel( Size( 340, 280 ), aAppMap ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( DbgDialog, ClickHdl, Button*, pButton )
+{
+ if ( pButton == &maOKButton )
+ {
+ DbgData aData;
+
+ memcpy( &aData, DbgGetData(), sizeof( DbgData ) );
+ aData.nTestFlags = 0;
+
+ aData.nTraceOut = ImplGetChannelId( maTraceBox, 0 );
+ aData.nWarningOut = ImplGetChannelId( maWarningBox, 0 );
+ aData.nErrorOut = ImplGetChannelId( maErrorBox, mnErrorOff );
+
+ strncpy( aData.aDebugName, ByteString( maDebugName.GetText(), RTL_TEXTENCODING_UTF8 ).GetBuffer(), sizeof( aData.aDebugName ) );
+ strncpy( aData.aInclClassFilter, ByteString( maInclClassFilter.GetText(), RTL_TEXTENCODING_UTF8 ).GetBuffer(), sizeof( aData.aInclClassFilter ) );
+ strncpy( aData.aExclClassFilter, ByteString( maExclClassFilter.GetText(), RTL_TEXTENCODING_UTF8 ).GetBuffer(), sizeof( aData.aExclClassFilter ) );
+ strncpy( aData.aInclFilter, ByteString( maInclFilter.GetText(), RTL_TEXTENCODING_UTF8 ).GetBuffer(), sizeof( aData.aInclFilter ) );
+ strncpy( aData.aExclFilter, ByteString( maExclFilter.GetText(), RTL_TEXTENCODING_UTF8 ).GetBuffer(), sizeof( aData.aExclFilter ) );
+ aData.aDebugName[sizeof( aData.aDebugName )-1] = '\0';
+ aData.aInclClassFilter[sizeof( aData.aInclClassFilter )-1] = '\0';
+ aData.aExclClassFilter[sizeof( aData.aExclClassFilter )-1] = '\0';
+ aData.aInclFilter[sizeof( aData.aInclFilter )-1] = '\0';
+ aData.aExclFilter[sizeof( aData.aExclFilter )-1] = '\0';
+
+ aData.bOverwrite = maOverwrite.IsChecked() ? TRUE : FALSE;
+ aData.bHookOSLAssert = maHookOSLBox.IsChecked() ? TRUE : FALSE;
+
+ if ( maXtorThis.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_XTOR_THIS;
+
+ if ( maXtorFunc.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_XTOR_FUNC;
+
+ if ( maXtorExit.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_XTOR_EXIT;
+
+ if ( maXtorReport.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_XTOR_REPORT;
+
+ if ( maXtorTrace.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_XTOR_TRACE;
+
+ if ( maMemInit.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_INIT;
+
+ if ( maMemOverwrite.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_OVERWRITE;
+
+ if ( maMemOverwriteFree.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_OVERWRITEFREE;
+
+ if ( maMemPtr.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_POINTER;
+
+ if ( maMemReport.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_REPORT;
+
+ if ( maMemTrace.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_TRACE;
+
+ if ( maMemLeakReport.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_LEAKREPORT;
+
+ if ( maMemNewDel.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_NEWDEL;
+
+ if ( maMemXtor.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_MEM_XTOR;
+
+ if ( maProf.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_PROFILING;
+
+ if ( maRes.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_RESOURCE;
+
+ if ( maDialog.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_DIALOG;
+
+ if ( maBoldAppFont.IsChecked() )
+ aData.nTestFlags |= DBG_TEST_BOLDAPPFONT;
+
+ // Daten speichern
+ DbgSaveData( aData );
+
+ // Umschalten der Laufzeitwerte
+ DBG_INSTOUTTRACE( aData.nTraceOut );
+ DBG_INSTOUTWARNING( aData.nWarningOut );
+ DBG_INSTOUTERROR( aData.nErrorOut );
+ DbgUpdateOslHook( &aData );
+
+ DbgData* pData = DbgGetData();
+ #define IMMEDIATE_FLAGS (DBG_TEST_MEM_INIT | DBG_TEST_RESOURCE | DBG_TEST_DIALOG | DBG_TEST_BOLDAPPFONT)
+ pData->nTestFlags &= ~IMMEDIATE_FLAGS;
+ pData->nTestFlags |= aData.nTestFlags & IMMEDIATE_FLAGS;
+ strncpy( pData->aInclClassFilter, aData.aInclClassFilter, sizeof( pData->aInclClassFilter ) );
+ strncpy( pData->aExclClassFilter, aData.aExclClassFilter, sizeof( pData->aExclClassFilter ) );
+ strncpy( pData->aInclFilter, aData.aInclFilter, sizeof( pData->aInclFilter ) );
+ strncpy( pData->aExclFilter, aData.aExclFilter, sizeof( pData->aExclFilter ) );
+ if ( maBoldAppFont.GetSavedValue() != maBoldAppFont.IsChecked() )
+ {
+ AllSettings aSettings = Application::GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ Font aFont = aStyleSettings.GetAppFont();
+ if ( maBoldAppFont.IsChecked() )
+ aFont.SetWeight( WEIGHT_BOLD );
+ else
+ aFont.SetWeight( WEIGHT_NORMAL );
+ aStyleSettings.SetAppFont( aFont );
+ aSettings.SetStyleSettings( aStyleSettings );
+ Application::SetSettings( aSettings );
+ }
+ if( (aData.nTestFlags & ~IMMEDIATE_FLAGS) != (pData->nTestFlags & ~IMMEDIATE_FLAGS) )
+ {
+ InfoBox aBox( this, String( RTL_CONSTASCII_USTRINGPARAM(
+ "Some of the changed settings will only be active after "
+ "restarting the process"
+ ) ) );
+ aBox.Execute();
+ }
+ EndDialog( TRUE );
+ }
+ else if ( pButton == &maInfoButton )
+ {
+ DbgInfoDialog aInfoDialog( this );
+ aDbgInfoBuf[0] = '\0';
+ DbgMemInfo( aDbgInfoBuf );
+ DbgXtorInfo( aDbgInfoBuf );
+ XubString aInfoText( aDbgInfoBuf, RTL_TEXTENCODING_UTF8 );
+ aInfoDialog.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Debug InfoReport" ) ) );
+ aInfoDialog.SetInfoText( aInfoText );
+ aInfoDialog.Execute();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void DbgDialog::RequestHelp( const HelpEvent& rHEvt )
+{
+ if ( rHEvt.GetMode() & HELPMODE_CONTEXT )
+ {
+ DbgInfoDialog aInfoDialog( this, TRUE );
+ XubString aHelpText;
+ const sal_Char** pHelpStrs = pDbgHelpText;
+ while ( *pHelpStrs )
+ {
+ aHelpText.AppendAscii( *pHelpStrs );
+ pHelpStrs++;
+ }
+ aInfoDialog.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Debug Hilfe" ) ) );
+ aInfoDialog.SetInfoText( aHelpText );
+ aInfoDialog.Execute();
+ }
+}
+
+// =======================================================================
+
+DbgInfoDialog::DbgInfoDialog( Window* pParent, BOOL bHelpText ) :
+ ModalDialog( pParent, WB_STDMODAL ),
+ maListBox( this, WB_BORDER | WB_AUTOHSCROLL ),
+ maOKButton( this, WB_DEFBUTTON )
+{
+ mbHelpText = bHelpText;
+
+ if ( !bHelpText )
+ {
+ Font aFont = GetDefaultFont( DEFAULTFONT_FIXED, LANGUAGE_ENGLISH_US, 0 );
+ aFont.SetHeight( 8 );
+ aFont.SetPitch( PITCH_FIXED );
+ maListBox.SetControlFont( aFont );
+ }
+ maListBox.SetPosSizePixel( Point( 5, 5 ), Size( 630, 380 ) );
+ maListBox.Show();
+
+ maOKButton.SetPosSizePixel( Point( 290, 390 ), Size( 60, 25 ) );
+ maOKButton.Show();
+
+ SetOutputSizePixel( Size( 640, 420 ) );
+}
+
+// -----------------------------------------------------------------------
+
+void DbgInfoDialog::SetInfoText( const XubString& rStr )
+{
+ maListBox.SetUpdateMode( FALSE );
+ maListBox.Clear();
+ XubString aStr = rStr;
+ aStr.ConvertLineEnd( LINEEND_LF );
+ USHORT nStrIndex = 0;
+ USHORT nFoundIndex;
+ do
+ {
+ nFoundIndex = aStr.Search( _LF, nStrIndex );
+ XubString aTextParagraph = aStr.Copy( nStrIndex, nFoundIndex-nStrIndex );
+ if ( mbHelpText )
+ {
+ long nMaxWidth = maListBox.GetOutputSizePixel().Width()-30;
+ USHORT nLastIndex = 0;
+ USHORT nIndex = aTextParagraph.Search( ' ' );
+ while ( nIndex != STRING_NOTFOUND )
+ {
+ if ( maListBox.GetTextWidth( aTextParagraph, 0, nIndex ) > nMaxWidth )
+ {
+ if ( !nLastIndex )
+ nLastIndex = nIndex+1;
+ XubString aTempStr = aTextParagraph.Copy( 0, nLastIndex );
+ aTextParagraph.Erase( 0, nLastIndex );
+ maListBox.InsertEntry( aTempStr );
+ nLastIndex = 0;
+ }
+ else
+ nLastIndex = nIndex+1;
+ nIndex = aTextParagraph.Search( ' ', nLastIndex );
+ }
+
+ if ( maListBox.GetTextWidth( aTextParagraph, 0, nIndex ) > nMaxWidth )
+ {
+ if ( !nLastIndex )
+ nLastIndex = nIndex+1;
+ XubString aTempStr = aTextParagraph.Copy( 0, nLastIndex );
+ aTextParagraph.Erase( 0, nLastIndex );
+ maListBox.InsertEntry( aTempStr );
+ }
+ }
+ maListBox.InsertEntry( aTextParagraph );
+ nStrIndex = nFoundIndex+1;
+ }
+ while ( nFoundIndex != STRING_NOTFOUND );
+ maListBox.SetUpdateMode( TRUE );
+}
+
+// =======================================================================
+
+void DbgDialogTest( Window* pWindow )
+{
+ BOOL aAccelBuf[65536];
+ USHORT nChildCount = pWindow->GetChildCount();
+ Window* pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
+ Window* pChild;
+ Point aTabPos;
+
+ if ( !pGetChild )
+ return;
+
+ Rectangle* pRectAry = (Rectangle*)new long[(sizeof(Rectangle)*nChildCount)/sizeof(long)];
+ memset( aAccelBuf, 0, sizeof( aAccelBuf ) );
+ memset( pRectAry, 0, sizeof(Rectangle)*nChildCount );
+
+ if ( pWindow->IsDialog() )
+ {
+ BOOL bOKCancelButton = FALSE;
+ BOOL bDefPushButton = FALSE;
+ BOOL bButton = FALSE;
+ pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pGetChild )
+ {
+ pChild = pGetChild->ImplGetWindow();
+
+ if ( pChild->ImplIsPushButton() )
+ {
+ bButton = TRUE;
+ if ( (pChild->GetType() == WINDOW_OKBUTTON) || (pChild->GetType() == WINDOW_CANCELBUTTON) )
+ bOKCancelButton = TRUE;
+ if ( pChild->GetStyle() & WB_DEFBUTTON )
+ bDefPushButton = TRUE;
+ }
+
+ pGetChild = pGetChild->GetWindow( WINDOW_NEXT );
+ }
+
+ if ( bButton )
+ {
+ if ( !bOKCancelButton )
+ DbgError( "Dialogs should have a OK- or CancelButton" );
+ if ( !bDefPushButton )
+ DbgError( "Dialogs should have a Button with WB_DEFBUTTON" );
+ }
+ }
+
+ USHORT i = 0;
+ pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pGetChild )
+ {
+ pChild = pGetChild->ImplGetWindow();
+
+ if ( (pChild->GetType() != WINDOW_TABCONTROL) &&
+ (pChild->GetType() != WINDOW_TABPAGE) &&
+ (pChild->GetType() != WINDOW_GROUPBOX) )
+ {
+ XubString aText = pChild->GetText();
+ XubString aErrorText = aText;
+ USHORT nAccelPos = STRING_NOTFOUND;
+ xub_Unicode cAccel = 0;
+ if ( aErrorText.Len() > 128 )
+ {
+ aErrorText.Erase( 128 );
+ aErrorText.AppendAscii( "..." );
+ }
+ if ( aText.Len() && (aText.Len() < 1024) )
+ {
+ nAccelPos = aText.Search( '~' );
+ if ( nAccelPos != STRING_NOTFOUND )
+ {
+ const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetLocale();
+ uno::Reference < i18n::XCharacterClassification > xCharClass = vcl::unohelper::CreateCharacterClassification();
+ XubString aUpperText = xCharClass->toUpper( aText, 0, aText.Len(), rLocale );
+ cAccel = aUpperText.GetChar( nAccelPos+1 );
+ if ( pChild->IsVisible() )
+ {
+ if ( aAccelBuf[cAccel] )
+ DbgOutTypef( DBG_OUT_ERROR, "Double mnemonic char: %c", cAccel );
+ else
+ aAccelBuf[cAccel] = TRUE;
+ }
+ }
+ }
+
+ if ( (pChild->GetType() == WINDOW_RADIOBUTTON) ||
+ (pChild->GetType() == WINDOW_IMAGERADIOBUTTON) ||
+ (pChild->GetType() == WINDOW_CHECKBOX) ||
+ (pChild->GetType() == WINDOW_TRISTATEBOX) ||
+ (pChild->GetType() == WINDOW_PUSHBUTTON) )
+ {
+ if ( aText.Len() && !aText.EqualsAscii( "..." ) )
+ {
+ const char* pClass;
+ if ( pChild->GetType() == WINDOW_RADIOBUTTON )
+ pClass = "RadioButton";
+ else if ( pChild->GetType() == WINDOW_IMAGERADIOBUTTON )
+ pClass = "ImageRadioButton";
+ else if ( pChild->GetType() == WINDOW_CHECKBOX )
+ pClass = "CheckBox";
+ else if ( pChild->GetType() == WINDOW_TRISTATEBOX )
+ pClass = "TriStateBox";
+ else if ( pChild->GetType() == WINDOW_PUSHBUTTON )
+ pClass = "PushButton";
+ else
+ pClass = "Dontknow";
+ if( !cAccel )
+ DbgOutTypef( DBG_OUT_ERROR,
+ "%s should have a mnemonic char (~): %s",
+ pClass,
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+
+ // check text width
+ int aWidth=0;
+ switch( pChild->GetType() )
+ {
+ case WINDOW_RADIOBUTTON:
+ case WINDOW_IMAGERADIOBUTTON:
+ aWidth = ((RadioButton*)pChild)->CalcMinimumSize(0).Width();
+ break;
+ case WINDOW_CHECKBOX:
+ case WINDOW_TRISTATEBOX:
+ aWidth = ((CheckBox*)pChild)->CalcMinimumSize(0).Width();
+ break;
+ case WINDOW_PUSHBUTTON:
+ aWidth = ((PushButton*)pChild)->CalcMinimumSize(0).Width();
+ break;
+ default: break;
+ }
+ if( pChild->IsVisible() && pChild->GetSizePixel().Width() < aWidth )
+ DbgOutTypef( DBG_OUT_ERROR,
+ "%s exceeds window width: %s",
+ pClass,
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ }
+
+ if ( pChild->GetType() == WINDOW_FIXEDLINE )
+ {
+ if ( pChild->GetSizePixel().Width() < pChild->GetTextWidth( aText ) )
+ DbgOutTypef( DBG_OUT_ERROR,
+ "FixedLine exceeds window width: %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+
+ if ( pChild->GetType() == WINDOW_FIXEDTEXT )
+ {
+ if ( (pChild->GetSizePixel().Height() >= pChild->GetTextHeight()*2) &&
+ !(pChild->GetStyle() & WB_WORDBREAK) )
+ {
+ DbgOutTypef( DBG_OUT_ERROR,
+ "FixedText greater than one line, but WordBreak is not set: %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+
+ if ( pChild->IsVisible() )
+ {
+ int aWidth=0;
+ if( nAccelPos != STRING_NOTFOUND )
+ {
+ aWidth = pChild->GetTextWidth( aText, 0, nAccelPos ) +
+ pChild->GetTextWidth( aText, nAccelPos+1, aText.Len() - nAccelPos - 1);
+ }
+ else
+ aWidth = pChild->GetTextWidth( aText );
+
+ if ( pChild->GetSizePixel().Width() < aWidth && !(pChild->GetStyle() & WB_WORDBREAK) )
+ {
+ DbgOutTypef( DBG_OUT_ERROR,
+ "FixedText exceeds window width: %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ }
+
+ if ( (i+1 < nChildCount) && aText.Len() )
+ {
+ Window* pTempChild = pGetChild->GetWindow( WINDOW_NEXT )->ImplGetWindow();
+ if ( (pTempChild->GetType() == WINDOW_EDIT) ||
+ (pTempChild->GetType() == WINDOW_MULTILINEEDIT) ||
+ (pTempChild->GetType() == WINDOW_SPINFIELD) ||
+ (pTempChild->GetType() == WINDOW_PATTERNFIELD) ||
+ (pTempChild->GetType() == WINDOW_NUMERICFIELD) ||
+ (pTempChild->GetType() == WINDOW_METRICFIELD) ||
+ (pTempChild->GetType() == WINDOW_CURRENCYFIELD) ||
+ (pTempChild->GetType() == WINDOW_DATEFIELD) ||
+ (pTempChild->GetType() == WINDOW_TIMEFIELD) ||
+ (pTempChild->GetType() == WINDOW_LISTBOX) ||
+ (pTempChild->GetType() == WINDOW_MULTILISTBOX) ||
+ (pTempChild->GetType() == WINDOW_COMBOBOX) ||
+ (pTempChild->GetType() == WINDOW_PATTERNBOX) ||
+ (pTempChild->GetType() == WINDOW_NUMERICBOX) ||
+ (pTempChild->GetType() == WINDOW_METRICBOX) ||
+ (pTempChild->GetType() == WINDOW_CURRENCYBOX) ||
+ (pTempChild->GetType() == WINDOW_DATEBOX) ||
+ (pTempChild->GetType() == WINDOW_TIMEBOX) )
+ {
+ if ( !cAccel )
+ {
+ DbgOutTypef( DBG_OUT_ERROR,
+ "Labels befor Fields (Edit,ListBox,...) should have a mnemonic char (~): %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ if ( !pTempChild->IsEnabled() && pChild->IsEnabled() )
+ {
+ DbgOutTypef( DBG_OUT_ERROR,
+ "Labels befor Fields (Edit,ListBox,...) should be disabled, when the field is disabled: %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ }
+ }
+ }
+
+ if ( pChild->GetType() == WINDOW_MULTILINEEDIT )
+ {
+ if ( ( 0 == ( pChild->GetStyle() & WB_IGNORETAB ) )
+ && ( 0 == ( pChild->GetStyle() & WB_READONLY ) )
+ )
+ {
+ DbgError( "editable MultiLineEdits in Dialogs should have the Style WB_IGNORETAB" );
+ }
+ }
+
+ if ( (pChild->GetType() == WINDOW_RADIOBUTTON) ||
+ (pChild->GetType() == WINDOW_IMAGERADIOBUTTON) ||
+ (pChild->GetType() == WINDOW_CHECKBOX) ||
+ (pChild->GetType() == WINDOW_TRISTATEBOX) ||
+ (pChild->GetType() == WINDOW_FIXEDTEXT) )
+ {
+ pChild->SetBackground( Wallpaper( Color( COL_LIGHTGREEN ) ) );
+ }
+
+ if ( pChild->IsVisible() )
+ {
+ BOOL bMaxWarning = FALSE;
+ if ( pChild->GetType() == WINDOW_NUMERICFIELD )
+ {
+ NumericField* pField = (NumericField*)pChild;
+ if ( pField->GetMax() == LONG_MAX )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_METRICFIELD )
+ {
+ MetricField* pField = (MetricField*)pChild;
+ if ( pField->GetMax() == LONG_MAX )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_CURRENCYFIELD )
+ {
+ CurrencyField* pField = (CurrencyField*)pChild;
+ if ( pField->GetMax() == LONG_MAX )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_TIMEFIELD )
+ {
+ TimeField* pField = (TimeField*)pChild;
+ if ( pField->GetMax() == Time( 23, 59, 59, 99 ) )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_DATEFIELD )
+ {
+ DateField* pField = (DateField*)pChild;
+ if ( pField->GetMax() == Date( 31, 12, 9999 ) )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_NUMERICBOX )
+ {
+ NumericBox* pBox = (NumericBox*)pChild;
+ if ( pBox->GetMax() == LONG_MAX )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_METRICBOX )
+ {
+ MetricBox* pBox = (MetricBox*)pChild;
+ if ( pBox->GetMax() == LONG_MAX )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_CURRENCYBOX )
+ {
+ CurrencyBox* pBox = (CurrencyBox*)pChild;
+ if ( pBox->GetMax() == LONG_MAX )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_TIMEBOX )
+ {
+ TimeBox* pBox = (TimeBox*)pChild;
+ if ( pBox->GetMax() == Time( 23, 59, 59, 99 ) )
+ bMaxWarning = TRUE;
+ }
+ else if ( pChild->GetType() == WINDOW_DATEBOX )
+ {
+ DateBox* pBox = (DateBox*)pChild;
+ if ( pBox->GetMax() == Date( 31, 12, 9999 ) )
+ bMaxWarning = TRUE;
+ }
+ if ( bMaxWarning )
+ {
+ DbgOutTypef( DBG_OUT_ERROR,
+ "No Max-Value is set: %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+
+ if ( (pChild->GetType() == WINDOW_RADIOBUTTON) ||
+ (pChild->GetType() == WINDOW_IMAGERADIOBUTTON) ||
+ (pChild->GetType() == WINDOW_CHECKBOX) ||
+ (pChild->GetType() == WINDOW_TRISTATEBOX) ||
+ (pChild->GetType() == WINDOW_PUSHBUTTON) ||
+ (pChild->GetType() == WINDOW_OKBUTTON) ||
+ (pChild->GetType() == WINDOW_CANCELBUTTON) ||
+ (pChild->GetType() == WINDOW_HELPBUTTON) ||
+ (pChild->GetType() == WINDOW_IMAGEBUTTON) ||
+ (pChild->GetType() == WINDOW_FIXEDTEXT) ||
+ (pChild->GetType() == WINDOW_EDIT) ||
+ (pChild->GetType() == WINDOW_MULTILINEEDIT) ||
+ (pChild->GetType() == WINDOW_SPINFIELD) ||
+ (pChild->GetType() == WINDOW_PATTERNFIELD) ||
+ (pChild->GetType() == WINDOW_NUMERICFIELD) ||
+ (pChild->GetType() == WINDOW_METRICFIELD) ||
+ (pChild->GetType() == WINDOW_CURRENCYFIELD) ||
+ (pChild->GetType() == WINDOW_DATEFIELD) ||
+ (pChild->GetType() == WINDOW_TIMEFIELD) ||
+ (pChild->GetType() == WINDOW_LISTBOX) ||
+ (pChild->GetType() == WINDOW_MULTILISTBOX) ||
+ (pChild->GetType() == WINDOW_COMBOBOX) ||
+ (pChild->GetType() == WINDOW_PATTERNBOX) ||
+ (pChild->GetType() == WINDOW_NUMERICBOX) ||
+ (pChild->GetType() == WINDOW_METRICBOX) ||
+ (pChild->GetType() == WINDOW_CURRENCYBOX) ||
+ (pChild->GetType() == WINDOW_DATEBOX) ||
+ (pChild->GetType() == WINDOW_TIMEBOX) )
+ {
+ Point aNewPos = pChild->GetPosPixel();
+ Rectangle aChildRect( aNewPos, pChild->GetSizePixel() );
+
+ if ( cAccel || (pChild->GetStyle() & WB_TABSTOP) ||
+ (pChild->GetType() == WINDOW_RADIOBUTTON) ||
+ (pChild->GetType() == WINDOW_IMAGERADIOBUTTON) )
+ {
+ if ( (aNewPos.X() <= aTabPos.X()) && (aNewPos.Y() <= aTabPos.Y()) )
+ {
+ DbgOutTypef( DBG_OUT_ERROR,
+ "Possible wrong childorder for dialogcontrol: %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ aTabPos = aNewPos;
+ }
+
+ for ( USHORT j = 0; j < i; j++ )
+ {
+ if ( ((pRectAry[j].Right() != 0) || (pRectAry[j].Bottom() != 0)) &&
+ aChildRect.IsOver( pRectAry[j] ) )
+ {
+ DbgOutTypef( DBG_OUT_ERROR,
+ "Window overlaps with sibling window: %s",
+ ByteString( aErrorText, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ }
+ pRectAry[i] = aChildRect;
+ }
+ }
+ }
+
+ pGetChild = pGetChild->GetWindow( WINDOW_NEXT );
+ i++;
+ }
+
+ delete [] pRectAry;
+}
+
+// =======================================================================
+#ifndef WNT
+#define USE_VCL_MSGBOX
+#define COPY_BUTTON_ID 25
+
+class DbgMessageBox : public ErrorBox
+{
+ String m_aMessage;
+ public:
+ DbgMessageBox( const String& rMessage ) :
+ ErrorBox( NULL, WB_YES_NO_CANCEL | WB_DEF_NO, rMessage ),
+ m_aMessage( rMessage )
+ {
+ SetText( String( RTL_CONSTASCII_USTRINGPARAM("Debug Output") ) );
+ AddButton( String( RTL_CONSTASCII_USTRINGPARAM( "Copy" ) ), COPY_BUTTON_ID, 0 );
+ }
+
+ virtual void Click()
+ {
+ if( GetCurButtonId() == COPY_BUTTON_ID )
+ vcl::unohelper::TextDataObject::CopyStringTo( m_aMessage, GetClipboard() );
+ else
+ ErrorBox::Click();
+ }
+};
+
+#endif
+
+class SolarMessageBoxExecutor : public ::vcl::SolarThreadExecutor
+{
+private:
+ String m_sDebugMessage;
+
+public:
+ SolarMessageBoxExecutor( const String& _rDebugMessage )
+ :m_sDebugMessage( _rDebugMessage )
+ {
+ }
+
+protected:
+ virtual long doIt();
+};
+
+long SolarMessageBoxExecutor::doIt()
+{
+ long nResult = RET_NO;
+
+ // Tracking beenden und Mouse freigeben, damit die Boxen nicht haengen
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpTrackWin )
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL );
+ if ( pSVData->maWinData.mpCaptureWin )
+ pSVData->maWinData.mpCaptureWin->ReleaseMouse();
+
+#if ! defined USE_VCL_MSGBOX
+#ifdef WNT
+ BOOL bOldCallTimer = pSVData->mbNoCallTimer;
+ pSVData->mbNoCallTimer = TRUE;
+ MessageBeep( MB_ICONHAND );
+ nResult = MessageBoxW( 0, (LPWSTR)m_sDebugMessage.GetBuffer(), L"Debug Output",
+ MB_TASKMODAL | MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONSTOP );
+ pSVData->mbNoCallTimer = bOldCallTimer;
+ switch ( nResult )
+ {
+ case IDYES:
+ nResult = RET_YES;
+ break;
+ case IDNO:
+ nResult = RET_NO;
+ break;
+ case IDCANCEL:
+ nResult = RET_CANCEL;
+ break;
+ }
+#endif // WNT
+#else
+ USHORT nOldMode = Application::GetSystemWindowMode();
+ Application::SetSystemWindowMode( nOldMode & ~SYSTEMWINDOW_MODE_NOAUTOMODE );
+ DbgMessageBox aBox( m_sDebugMessage );
+ Application::SetSystemWindowMode( nOldMode );
+ nResult = aBox.Execute();
+#endif
+
+ return nResult;
+}
+
+void DbgPrintMsgBox( const char* pLine )
+{
+ // are modal message boxes prohibited at the moment?
+ if ( Application::IsDialogCancelEnabled() )
+ {
+#if defined( WNT )
+ // TODO: Shouldn't this be a IsDebuggerPresent()?
+ if ( GetSystemMetrics( SM_DEBUG ) )
+ {
+ MessageBeep( MB_ICONHAND );
+ strcpy( aDbgOutBuf, pLine );
+ strcat( aDbgOutBuf, "\r\n" );
+ OutputDebugString( aDbgOutBuf );
+ return;
+ }
+#endif
+
+ Sound::Beep( SOUND_ERROR );
+#ifdef UNX
+ fprintf( stderr, "%s\n", pLine );
+ return;
+#else
+ DbgPrintFile( pLine );
+ return;
+#endif
+ }
+
+ strcpy( aDbgOutBuf, pLine );
+ strcat( aDbgOutBuf, "\nAbort ? (Yes=abort / No=ignore / Cancel=core dump)" );
+
+ SolarMessageBoxExecutor aMessageBox( String( aDbgOutBuf, RTL_TEXTENCODING_UTF8 ) );
+ TimeValue aTimeout; aTimeout.Seconds = 2; aTimeout.Nanosec = 0;
+ long nResult = aMessageBox.execute( aTimeout );
+
+ if ( aMessageBox.didTimeout() )
+ DbgPrintShell( pLine );
+ else if ( nResult == RET_YES )
+ GetpApp()->Abort( XubString( RTL_CONSTASCII_USTRINGPARAM( "Debug-Utilities-Error" ) ) );
+ else if ( nResult == RET_CANCEL )
+ DbgCoreDump();
+}
+
+// -----------------------------------------------------------------------
+
+class SolarWindowPrinter : public ::vcl::SolarThreadExecutor
+{
+private:
+ String m_sDebugMessage;
+
+public:
+ SolarWindowPrinter( const String& _rDebugMessage )
+ :m_sDebugMessage( _rDebugMessage )
+ {
+ }
+
+protected:
+ virtual long doIt();
+};
+
+long SolarWindowPrinter::doIt()
+{
+ DbgWindow* pDbgWindow = ImplGetSVData()->maWinData.mpDbgWin;
+ if ( !pDbgWindow )
+ {
+ pDbgWindow = new DbgWindow;
+ ImplGetSVData()->maWinData.mpDbgWin = pDbgWindow;
+ }
+ pDbgWindow->InsertLine( m_sDebugMessage );
+
+ return 0L;
+}
+
+// -----------------------------------------------------------------------
+
+void DbgPrintWindow( const char* pLine )
+{
+ static BOOL bIn = FALSE;
+
+ // keine rekursiven Traces
+ if ( bIn )
+ return;
+ bIn = TRUE;
+
+ SolarWindowPrinter aPrinter( String( pLine, RTL_TEXTENCODING_UTF8 ) );
+ TimeValue aTimeout; aTimeout.Seconds = 2; aTimeout.Nanosec = 0;
+ aPrinter.execute( aTimeout );
+
+ if ( aPrinter.didTimeout() )
+ DbgPrintShell( pLine );
+
+ bIn = FALSE;
+}
+
+// =======================================================================
+
+#ifdef WNT
+void ImplDbgTestSolarMutex();
+#endif
+
+// =======================================================================
+
+void DbgGUIInit()
+{
+ DbgSetPrintMsgBox( DbgPrintMsgBox );
+ DbgSetPrintWindow( DbgPrintWindow );
+#ifdef WNT
+ DbgSetTestSolarMutex( ImplDbgTestSolarMutex );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+void DbgGUIDeInit()
+{
+ DbgSetPrintMsgBox( NULL );
+ DbgSetPrintWindow( NULL );
+#ifdef WNT
+ DbgSetTestSolarMutex( NULL );
+#endif
+
+ DbgWindow* pDbgWindow = ImplGetSVData()->maWinData.mpDbgWin;
+ if ( pDbgWindow )
+ delete pDbgWindow;
+}
+
+// -----------------------------------------------------------------------
+
+void DbgGUIStart()
+{
+ DbgData* pData = DbgGetData();
+
+ if ( pData )
+ {
+ DbgDialog* pDialog = new DbgDialog;
+ // Fuer den Debug-Dialog schalten wir Dialogtests aus
+ ULONG nOldFlags = pData->nTestFlags;
+ pData->nTestFlags &= ~DBG_TEST_DIALOG;
+ if ( !pDialog->Execute() )
+ pData->nTestFlags |= (nOldFlags & DBG_TEST_DIALOG);
+ delete pDialog;
+ }
+ else
+ {
+ ErrorBox( 0, WB_OK,
+ XubString( RTL_CONSTASCII_USTRINGPARAM( "TOOLS Library has no Debug-Routines" ) ) ).Execute();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT DbgRegisterNamedUserChannel( const XubString& _rChannelUIName, DbgPrintLine pProc )
+{
+ DbgChannelId nChannelId = DbgRegisterUserChannel( pProc );
+ UserDefinedChannels& rChannels = ImplDbgGetUserDefinedChannels();
+ rChannels[ _rChannelUIName ] = nChannelId;
+ return nChannelId;
+}
+
+#endif // DBG_UTIL
diff --git a/vcl/source/app/dndhelp.cxx b/vcl/source/app/dndhelp.cxx
new file mode 100644
index 000000000000..d1eb2014b4df
--- /dev/null
+++ b/vcl/source/app/dndhelp.cxx
@@ -0,0 +1,182 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+
+
+#include <vcl/dndhelp.hxx>
+
+using namespace ::com::sun::star;
+
+vcl::unohelper::DragAndDropClient::~DragAndDropClient() {}
+
+void vcl::unohelper::DragAndDropClient::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& /*dge*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& /*dsde*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragEnter( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& /*dsde*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragExit( const ::com::sun::star::datatransfer::dnd::DragSourceEvent& /*dse*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragOver( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& /*dsde*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dropActionChanged( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& /*dsde*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& /*dtde*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& /*dtdee*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& /*dte*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& /*dtde*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dropActionChanged( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& /*dtde*/ ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+// =======================================================================
+
+vcl::unohelper::DragAndDropWrapper::DragAndDropWrapper( DragAndDropClient* pClient )
+{
+ mpClient = pClient;
+}
+
+vcl::unohelper::DragAndDropWrapper::~DragAndDropWrapper()
+{
+}
+
+// uno::XInterface
+uno::Any vcl::unohelper::DragAndDropWrapper::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException)
+{
+ uno::Any aRet = ::cppu::queryInterface( rType,
+ SAL_STATIC_CAST( ::com::sun::star::lang::XEventListener*, (::com::sun::star::datatransfer::dnd::XDragGestureListener*)this ),
+ SAL_STATIC_CAST( ::com::sun::star::datatransfer::dnd::XDragGestureListener*, this ),
+ SAL_STATIC_CAST( ::com::sun::star::datatransfer::dnd::XDragSourceListener*, this ),
+ SAL_STATIC_CAST( ::com::sun::star::datatransfer::dnd::XDropTargetListener*, this ) );
+ return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
+}
+
+// ::com::sun::star::lang::XEventListener
+void vcl::unohelper::DragAndDropWrapper::disposing( const ::com::sun::star::lang::EventObject& rEvent ) throw (::com::sun::star::uno::RuntimeException)
+{
+ // Empty Source means it's the client, because the client is not a XInterface
+ if ( !rEvent.Source.is() )
+ mpClient = NULL;
+}
+
+
+// ::com::sun::star::datatransfer::dnd::XDragGestureListener
+void vcl::unohelper::DragAndDropWrapper::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragGestureRecognized( rDGE );
+}
+
+// ::com::sun::star::datatransfer::dnd::XDragSourceListener
+void vcl::unohelper::DragAndDropWrapper::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragDropEnd( rDSDE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragEnter( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragEnter( dsde );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragExit( const ::com::sun::star::datatransfer::dnd::DragSourceEvent& dse ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragExit( dse );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragOver( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragOver( dsde );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dropActionChanged( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dropActionChanged( dsde );
+}
+
+// ::com::sun::star::datatransfer::dnd::XDropTargetListener
+void vcl::unohelper::DragAndDropWrapper::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->drop( rDTDE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& rDTDEE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragEnter( rDTDEE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragExit( dte );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dragOver( rDTDE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dropActionChanged( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpClient )
+ mpClient->dropActionChanged( rDTDE );
+}
+
diff --git a/vcl/source/app/help.cxx b/vcl/source/app/help.cxx
new file mode 100644
index 000000000000..1f9efa7b6e65
--- /dev/null
+++ b/vcl/source/app/help.cxx
@@ -0,0 +1,787 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/svdata.hxx"
+#include "vcl/window.hxx"
+#include "vcl/event.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/wrkwin.hxx"
+#include "vcl/help.hxx"
+#include "vcl/helpwin.hxx"
+#include "tools/debug.hxx"
+#include "tools/time.hxx"
+
+// =======================================================================
+
+#define HELPWINSTYLE_QUICK 0
+#define HELPWINSTYLE_BALLOON 1
+
+#define HELPTEXTMARGIN_QUICK 3
+#define HELPTEXTMARGIN_BALLOON 6
+
+#define HELPDELAY_NORMAL 1
+#define HELPDELAY_SHORT 2
+#define HELPDELAY_NONE 3
+
+// =======================================================================
+
+Help::Help()
+{
+}
+
+Help::~Help()
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::Start( ULONG, const Window* )
+{
+ return FALSE;
+}
+
+void Help::OpenHelpAgent( ULONG )
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::Start( const XubString&, const Window* )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Help::GetHelpText( ULONG, const Window* )
+{
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+XubString Help::GetHelpText( const String&, const Window* )
+{
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void Help::EnableContextHelp()
+{
+ ImplGetSVData()->maHelpData.mbContextHelp = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::DisableContextHelp()
+{
+ ImplGetSVData()->maHelpData.mbContextHelp = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::IsContextHelpEnabled()
+{
+ return ImplGetSVData()->maHelpData.mbContextHelp;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::StartContextHelp()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maHelpData.mbContextHelp )
+ {
+ Window* pWindow = pSVData->maWinData.mpFocusWin;
+ if ( pWindow )
+ {
+ Point aMousePos = pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() );
+ HelpEvent aHelpEvent( aMousePos, HELPMODE_CONTEXT );
+ pWindow->RequestHelp( aHelpEvent );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::EnableExtHelp()
+{
+ ImplGetSVData()->maHelpData.mbExtHelp = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::DisableExtHelp()
+{
+ ImplGetSVData()->maHelpData.mbExtHelp = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::IsExtHelpEnabled()
+{
+ return ImplGetSVData()->maHelpData.mbExtHelp;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::StartExtHelp()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maHelpData.mbExtHelp && !pSVData->maHelpData.mbExtHelpMode )
+ {
+ pSVData->maHelpData.mbExtHelpMode = TRUE;
+ pSVData->maHelpData.mbOldBalloonMode = pSVData->maHelpData.mbBalloonHelp;
+ pSVData->maHelpData.mbBalloonHelp = TRUE;
+ if ( pSVData->maWinData.mpAppWin )
+ pSVData->maWinData.mpAppWin->ImplGenerateMouseMove();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::EndExtHelp()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maHelpData.mbExtHelp && pSVData->maHelpData.mbExtHelpMode )
+ {
+ pSVData->maHelpData.mbExtHelpMode = FALSE;
+ pSVData->maHelpData.mbBalloonHelp = pSVData->maHelpData.mbOldBalloonMode;
+ if ( pSVData->maWinData.mpAppWin )
+ pSVData->maWinData.mpAppWin->ImplGenerateMouseMove();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::IsExtHelpActive()
+{
+ return ImplGetSVData()->maHelpData.mbExtHelpMode;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::EnableBalloonHelp()
+{
+ ImplGetSVData()->maHelpData.mbBalloonHelp = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::DisableBalloonHelp()
+{
+ ImplGetSVData()->maHelpData.mbBalloonHelp = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::IsBalloonHelpEnabled()
+{
+ return ImplGetSVData()->maHelpData.mbBalloonHelp;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::ShowBalloon( Window* pParent,
+ const Point& rScreenPos,
+ const XubString& rHelpText )
+{
+ ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, 0,
+ rHelpText, ImplGetSVEmptyStr(), rScreenPos );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::ShowBalloon( Window* pParent,
+ const Point& rScreenPos, const Rectangle& rRect,
+ const XubString& rHelpText )
+{
+ ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, 0,
+ rHelpText, ImplGetSVEmptyStr(), rScreenPos, &rRect );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::EnableQuickHelp()
+{
+ ImplGetSVData()->maHelpData.mbQuickHelp = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::DisableQuickHelp()
+{
+ ImplGetSVData()->maHelpData.mbQuickHelp = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::IsQuickHelpEnabled()
+{
+ return ImplGetSVData()->maHelpData.mbQuickHelp;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Help::ShowQuickHelp( Window* pParent,
+ const Rectangle& rScreenRect,
+ const XubString& rHelpText,
+ const XubString& rLongHelpText,
+ USHORT nStyle )
+{
+ ImplShowHelpWindow( pParent, HELPWINSTYLE_QUICK, nStyle,
+ rHelpText, rLongHelpText,
+ pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), &rScreenRect );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Help::ShowTip( Window* pParent, const Rectangle& rRect,
+ const XubString& rText, USHORT nStyle )
+{
+ USHORT nHelpWinStyle = HELPWINSTYLE_QUICK;
+ HelpTextWindow* pHelpWin = new HelpTextWindow( pParent, rText, nHelpWinStyle, nStyle );
+
+ Size aSz = pHelpWin->CalcOutSize();
+ pHelpWin->SetOutputSizePixel( aSz );
+ ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle,
+ pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), &rRect );
+ pHelpWin->ShowHelp( HELPDELAY_NONE );
+ return (ULONG)pHelpWin;
+}
+
+// -----------------------------------------------------------------------
+
+void Help::HideTip( ULONG nId )
+{
+ HelpTextWindow* pHelpWin = (HelpTextWindow*)nId;
+ Window* pFrameWindow = pHelpWin->ImplGetFrameWindow();
+ pHelpWin->Hide();
+ // Update ausloesen, damit ein Paint sofort ausgeloest wird, da
+ // wir den Hintergrund nicht sichern
+ pFrameWindow->ImplUpdateAll();
+ delete pHelpWin;
+ ImplGetSVData()->maHelpData.mnLastHelpHideTime = Time::GetSystemTicks();
+}
+
+// =======================================================================
+
+HelpTextWindow::HelpTextWindow( Window* pParent, const XubString& rText, USHORT nHelpWinStyle, USHORT nStyle ) :
+ //FloatingWindow( pParent->ImplGetFrameWindow(), WB_SYSTEMWINDOW ),
+ FloatingWindow( pParent, WB_SYSTEMWINDOW|WB_TOOLTIPWIN ), // #105827# if we change the parent, mirroring will not work correctly when positioning this window
+ maHelpText( rText )
+{
+ SetType( WINDOW_HELPTEXTWINDOW );
+ ImplSetMouseTransparent( TRUE );
+ mnHelpWinStyle = nHelpWinStyle;
+ mnStyle = nStyle;
+// on windows this will raise the application window, because help windows are system windows now
+// EnableAlwaysOnTop();
+ EnableSaveBackground();
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ SetPointFont( rStyleSettings.GetHelpFont() );
+ SetTextColor( rStyleSettings.GetHelpTextColor() );
+ SetTextAlign( ALIGN_TOP );
+ if ( IsNativeControlSupported( CTRL_TOOLTIP, PART_ENTIRE_CONTROL ) )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ SetBackground( Wallpaper( rStyleSettings.GetHelpColor() ) );
+ if( rStyleSettings.GetHelpColor().IsDark() )
+ SetLineColor( COL_WHITE );
+ else
+ SetLineColor( COL_BLACK );
+ SetFillColor();
+
+ if( mnStyle & QUICKHELP_BIDI_RTL )
+ {
+ ULONG nLayoutMode = GetLayoutMode();
+ nLayoutMode |= TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
+ SetLayoutMode( nLayoutMode );
+ }
+ SetHelpText( rText );
+ Window::SetHelpText( rText );
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maHelpData.mbSetKeyboardHelp )
+ pSVData->maHelpData.mbKeyboardHelp = TRUE;
+
+ const HelpSettings& rHelpSettings = pParent->GetSettings().GetHelpSettings();
+ maShowTimer.SetTimeoutHdl( LINK( this, HelpTextWindow, TimerHdl ) );
+ maHideTimer.SetTimeoutHdl( LINK( this, HelpTextWindow, TimerHdl ) );
+ maHideTimer.SetTimeout( rHelpSettings.GetTipTimeout() );
+}
+
+// -----------------------------------------------------------------------
+
+HelpTextWindow::~HelpTextWindow()
+{
+ maShowTimer.Stop();
+ maHideTimer.Stop();
+
+ if( this == ImplGetSVData()->maHelpData.mpHelpWin )
+ ImplGetSVData()->maHelpData.mpHelpWin = NULL;
+
+ if ( maStatusText.Len() )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpApp->HideHelpStatusText();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void HelpTextWindow::SetHelpText( const String& rHelpText )
+{
+ maHelpText = rHelpText;
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
+ {
+ Size aSize;
+ aSize.Height() = GetTextHeight();
+ if ( mnStyle & QUICKHELP_CTRLTEXT )
+ aSize.Width() = GetCtrlTextWidth( maHelpText );
+ else
+ aSize.Width() = GetTextWidth( maHelpText );
+ maTextRect = Rectangle( Point( HELPTEXTMARGIN_QUICK, HELPTEXTMARGIN_QUICK ), aSize );
+ }
+ else // HELPWINSTYLE_BALLOON
+ {
+ Point aTmpPoint;
+ USHORT nCharsInLine = 35 + ((maHelpText.Len()/100)*5);
+ XubString aXXX;
+ aXXX.Fill( nCharsInLine, 'x' ); // Durchschnittliche Breite, damit nicht jedes Fenster anders.
+ long nWidth = GetTextWidth( aXXX );
+ Size aTmpSize( nWidth, 0x7FFFFFFF );
+ Rectangle aTry1( aTmpPoint, aTmpSize );
+ USHORT nDrawFlags = TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK |
+ TEXT_DRAW_LEFT | TEXT_DRAW_TOP;
+ if ( mnStyle & QUICKHELP_CTRLTEXT )
+ nDrawFlags |= TEXT_DRAW_MNEMONIC;
+ Rectangle aTextRect = GetTextRect( aTry1, maHelpText, nDrawFlags );
+
+ // Spaeter mal eine geeignete Breite ermitteln...
+ maTextRect = aTextRect;
+
+ // Sicherheitsabstand...
+ maTextRect.SetPos( Point( HELPTEXTMARGIN_BALLOON, HELPTEXTMARGIN_BALLOON ) );
+ }
+
+ Size aSize( CalcOutSize() );
+ SetOutputSizePixel( aSize );
+}
+
+// -----------------------------------------------------------------------
+
+void HelpTextWindow::ImplShow()
+{
+ ImplDelData aDogTag( this );
+ if ( maStatusText.Len() )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpApp->ShowHelpStatusText( maStatusText );
+ }
+ Show( TRUE, SHOW_NOACTIVATE );
+ if( !aDogTag.IsDelete() )
+ Update();
+}
+
+// -----------------------------------------------------------------------
+
+void HelpTextWindow::Paint( const Rectangle& )
+{
+ // paint native background
+ bool bNativeOK = false;
+ if ( IsNativeControlSupported( CTRL_TOOLTIP, PART_ENTIRE_CONTROL ) )
+ {
+ // #i46472# workaround gcc3.3 temporary problem
+ Rectangle aCtrlRegion( Point( 0, 0 ), GetOutputSizePixel() );
+ ImplControlValue aControlValue;
+ bNativeOK = DrawNativeControl( CTRL_TOOLTIP, PART_ENTIRE_CONTROL, aCtrlRegion,
+ 0, aControlValue, rtl::OUString() );
+ }
+
+ // paint text
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
+ {
+ if ( mnStyle & QUICKHELP_CTRLTEXT )
+ DrawCtrlText( maTextRect.TopLeft(), maHelpText );
+ else
+ DrawText( maTextRect.TopLeft(), maHelpText );
+ }
+ else // HELPWINSTYLE_BALLOON
+ {
+ USHORT nDrawFlags = TEXT_DRAW_MULTILINE|TEXT_DRAW_WORDBREAK|
+ TEXT_DRAW_LEFT|TEXT_DRAW_TOP;
+ if ( mnStyle & QUICKHELP_CTRLTEXT )
+ nDrawFlags |= TEXT_DRAW_MNEMONIC;
+ DrawText( maTextRect, maHelpText, nDrawFlags );
+ }
+
+ // border
+ if( ! bNativeOK )
+ {
+ Size aSz = GetOutputSizePixel();
+ DrawRect( Rectangle( Point(), aSz ) );
+ if ( mnHelpWinStyle == HELPWINSTYLE_BALLOON )
+ {
+ aSz.Width() -= 2;
+ aSz.Height() -= 2;
+ Color aColor( GetLineColor() );
+ SetLineColor( ( COL_GRAY ) );
+ DrawRect( Rectangle( Point( 1, 1 ), aSz ) );
+ SetLineColor( aColor );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void HelpTextWindow::ShowHelp( USHORT nDelayMode )
+{
+ ULONG nTimeout = 0;
+ if ( nDelayMode != HELPDELAY_NONE )
+ {
+ // Im ExtendedHelp-Fall die Hilfe schneller anzeigen
+ if ( ImplGetSVData()->maHelpData.mbExtHelpMode )
+ nTimeout = 15;
+ else
+ {
+ const HelpSettings& rHelpSettings = GetSettings().GetHelpSettings();
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
+ nTimeout = rHelpSettings.GetTipDelay();
+ else
+ nTimeout = rHelpSettings.GetBalloonDelay();
+ }
+
+ if ( nDelayMode == HELPDELAY_SHORT )
+ nTimeout /= 3;
+ }
+
+ maShowTimer.SetTimeout( nTimeout );
+ maShowTimer.Start();
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( HelpTextWindow, TimerHdl, Timer*, pTimer)
+{
+ if ( pTimer == &maShowTimer )
+ {
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
+ {
+ // start auto-hide-timer for non-ShowTip windows
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( this == pSVData->maHelpData.mpHelpWin )
+ maHideTimer.Start();
+ }
+ ImplShow();
+ }
+ else
+ {
+ DBG_ASSERT( pTimer == &maHideTimer, "HelpTextWindow::TimerHdl with bad Timer" );
+ ImplDestroyHelpWindow( true );
+ }
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+Size HelpTextWindow::CalcOutSize() const
+{
+ Size aSz = maTextRect.GetSize();
+ aSz.Width() += 2*maTextRect.Left();
+ aSz.Height() += 2*maTextRect.Top();
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+void HelpTextWindow::RequestHelp( const HelpEvent& /*rHEvt*/ )
+{
+ // Nur damit nicht von Window::RequestHelp() ein
+ // ShowQuickHelp/ShowBalloonHelp am HelpTextWindow aufgerufen wird.
+}
+
+// -----------------------------------------------------------------------
+
+String HelpTextWindow::GetText() const
+{
+ return maHelpText;
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > HelpTextWindow::CreateAccessible()
+{
+ return FloatingWindow::CreateAccessible();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL HelpTextWindow::RegisterAccessibleParent()
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void HelpTextWindow::RevokeAccessibleParent()
+{
+}
+
+// =======================================================================
+
+void ImplShowHelpWindow( Window* pParent, USHORT nHelpWinStyle, USHORT nStyle,
+ const XubString& rHelpText, const XubString& rStatusText,
+ const Point& rScreenPos, const Rectangle* pHelpArea )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if( !rHelpText.Len() && !pSVData->maHelpData.mbRequestingHelp )
+ return;
+
+ HelpTextWindow* pHelpWin = pSVData->maHelpData.mpHelpWin;
+ USHORT nDelayMode = HELPDELAY_NORMAL;
+ if ( pHelpWin )
+ {
+ DBG_ASSERT( pHelpWin != pParent, "HelpInHelp ?!" );
+
+ if ( (( pHelpWin->GetHelpText() != rHelpText ) ||
+ ( pHelpWin->GetWinStyle() != nHelpWinStyle ) ||
+ ( pHelpArea && ( pHelpWin->GetHelpArea() != *pHelpArea ) ) )
+ && pSVData->maHelpData.mbRequestingHelp )
+ {
+ // remove help window if no HelpText or other HelpText or
+ // other help mode. but keep it if we are scrolling, ie not requesting help
+ bool bWasVisible = pHelpWin->IsVisible();
+ if ( bWasVisible )
+ nDelayMode = HELPDELAY_NONE; // display it quickly if we were already in quick help mode
+ pHelpWin = NULL;
+ ImplDestroyHelpWindow( bWasVisible );
+ }
+ else
+ {
+ bool bTextChanged = rHelpText != pHelpWin->GetHelpText();
+ if( bTextChanged )
+ {
+ Window * pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
+ Rectangle aInvRect( pHelpWin->GetWindowExtentsRelative( pWindow ) );
+ if( pHelpWin->IsVisible() )
+ pWindow->Invalidate( aInvRect );
+
+ pHelpWin->SetHelpText( rHelpText );
+ // approach mouse position
+ ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, pHelpArea );
+ if( pHelpWin->IsVisible() )
+ pHelpWin->Invalidate();
+ }
+ }
+ }
+
+ if ( !pHelpWin && rHelpText.Len() )
+ {
+ ULONG nCurTime = Time::GetSystemTicks();
+ if( (nCurTime - pSVData->maHelpData.mnLastHelpHideTime) < pParent->GetSettings().GetHelpSettings().GetTipDelay() )
+ nDelayMode = HELPDELAY_NONE;
+
+ DBG_ASSERT( !pHelpWin, "Noch ein HelpWin ?!" );
+ pHelpWin = new HelpTextWindow( pParent, rHelpText, nHelpWinStyle, nStyle );
+ pSVData->maHelpData.mpHelpWin = pHelpWin;
+ pHelpWin->SetStatusText( rStatusText );
+ if ( pHelpArea )
+ pHelpWin->SetHelpArea( *pHelpArea );
+
+ // positioning
+ Size aSz = pHelpWin->CalcOutSize();
+ pHelpWin->SetOutputSizePixel( aSz );
+ ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, pHelpArea );
+ // if not called from Window::RequestHelp, then without delay...
+ if ( !pSVData->maHelpData.mbRequestingHelp )
+ nDelayMode = HELPDELAY_NONE;
+ pHelpWin->ShowHelp( nDelayMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDestroyHelpWindow( bool bUpdateHideTime )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ HelpTextWindow* pHelpWin = pSVData->maHelpData.mpHelpWin;
+ if ( pHelpWin )
+ {
+ Window * pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
+ // find out screen area covered by system help window
+ Rectangle aInvRect( pHelpWin->GetWindowExtentsRelative( pWindow ) );
+ if( pHelpWin->IsVisible() )
+ pWindow->Invalidate( aInvRect );
+ pSVData->maHelpData.mpHelpWin = NULL;
+ pSVData->maHelpData.mbKeyboardHelp = FALSE;
+ pHelpWin->Hide();
+ delete pHelpWin;
+ if( bUpdateHideTime )
+ pSVData->maHelpData.mnLastHelpHideTime = Time::GetSystemTicks();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSetHelpWindowPos( Window* pHelpWin, USHORT nHelpWinStyle, USHORT nStyle,
+ const Point& rPos, const Rectangle* pHelpArea )
+{
+ Point aPos = rPos;
+ Size aSz = pHelpWin->GetSizePixel();
+ Rectangle aScreenRect = pHelpWin->ImplGetFrameWindow()->GetDesktopRectPixel();
+ aPos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( aPos );
+ // get mouse screen coords
+ Point mPos( pHelpWin->GetParent()->ImplGetFrameWindow()->GetPointerPosPixel() );
+ mPos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( mPos );
+
+ if ( nHelpWinStyle == HELPWINSTYLE_QUICK )
+ {
+ if ( !(nStyle & QUICKHELP_NOAUTOPOS) )
+ {
+ long nScreenHeight = aScreenRect.GetHeight();
+ aPos.X() -= 4;
+ if ( aPos.Y() > aScreenRect.Top()+nScreenHeight-(nScreenHeight/4) )
+ aPos.Y() -= aSz.Height()+4;
+ else
+ aPos.Y() += 21;
+ }
+ }
+ else
+ {
+ // If it's the mouse position, move the window slightly
+ // so the mouse pointer does not cover it
+ if ( aPos == mPos )
+ {
+ aPos.X() += 12;
+ aPos.Y() += 16;
+ }
+ }
+
+ if ( nStyle & QUICKHELP_NOAUTOPOS )
+ {
+ if ( pHelpArea )
+ {
+ // convert help area to screen coords
+ Rectangle devHelpArea(
+ pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( pHelpArea->TopLeft() ),
+ pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( pHelpArea->BottomRight() ) );
+
+ // Welche Position vom Rechteck?
+ aPos = devHelpArea.Center();
+
+ if ( nStyle & QUICKHELP_LEFT )
+ aPos.X() = devHelpArea.Left();
+ else if ( nStyle & QUICKHELP_RIGHT )
+ aPos.X() = devHelpArea.Right();
+
+ if ( nStyle & QUICKHELP_TOP )
+ aPos.Y() = devHelpArea.Top();
+ else if ( nStyle & QUICKHELP_BOTTOM )
+ aPos.Y() = devHelpArea.Bottom();
+ }
+
+ // Welche Richtung?
+ if ( nStyle & QUICKHELP_LEFT )
+ ;
+ else if ( nStyle & QUICKHELP_RIGHT )
+ aPos.X() -= aSz.Width();
+ else
+ aPos.X() -= aSz.Width()/2;
+
+ if ( nStyle & QUICKHELP_TOP )
+ ;
+ else if ( nStyle & QUICKHELP_BOTTOM )
+ aPos.Y() -= aSz.Height();
+ else
+ aPos.Y() -= aSz.Height()/2;
+ }
+
+ if ( aPos.X() < aScreenRect.Left() )
+ aPos.X() = aScreenRect.Left();
+ else if ( ( aPos.X() + aSz.Width() ) > aScreenRect.Right() )
+ aPos.X() = aScreenRect.Right() - aSz.Width();
+ if ( aPos.Y() < aScreenRect.Top() )
+ aPos.Y() = aScreenRect.Top();
+ else if ( ( aPos.Y() + aSz.Height() ) > aScreenRect.Bottom() )
+ aPos.Y() = aScreenRect.Bottom() - aSz.Height();
+
+ if( ! (nStyle & QUICKHELP_NOEVADEPOINTER) )
+ {
+ /* the remark below should be obsolete by now as the helpwindow should
+ not be focusable, leaving it as a hint. However it is sensible in most
+ conditions to evade the mouse pointer so the content window is fully visible.
+
+ // the popup must not appear under the mouse
+ // otherwise it would directly be closed due to a focus change...
+ */
+ Rectangle aHelpRect( aPos, aSz );
+ if( aHelpRect.IsInside( mPos ) )
+ {
+ Point delta(2,2);
+ Point pSize( aSz.Width(), aSz.Height() );
+ Point pTest( mPos - pSize - delta );
+ if( pTest.X() > aScreenRect.Left() && pTest.Y() > aScreenRect.Top() )
+ aPos = pTest;
+ else
+ aPos = mPos + delta;
+ }
+ }
+
+ Window* pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
+ aPos = pWindow->AbsoluteScreenToOutputPixel( aPos );
+ pHelpWin->SetPosPixel( aPos );
+}
diff --git a/vcl/source/app/i18nhelp.cxx b/vcl/source/app/i18nhelp.cxx
new file mode 100644
index 000000000000..17bc760ff5fc
--- /dev/null
+++ b/vcl/source/app/i18nhelp.cxx
@@ -0,0 +1,187 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/i18nhelp.hxx"
+
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/i18n/TransliterationModules.hpp"
+#include "unotools/localedatawrapper.hxx"
+#include "unotools/transliterationwrapper.hxx"
+#include "i18npool/mslangid.hxx"
+
+#include "rtl/ustrbuf.hxx"
+
+using namespace ::com::sun::star;
+
+vcl::I18nHelper::I18nHelper( ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxMSF, const ::com::sun::star::lang::Locale& rLocale )
+{
+ mxMSF = rxMSF;
+ maLocale = rLocale;
+ mpLocaleDataWrapper = NULL;
+ mpTransliterationWrapper= NULL;
+ mbTransliterateIgnoreCase = sal_False;
+}
+
+vcl::I18nHelper::~I18nHelper()
+{
+ ImplDestroyWrappers();
+}
+
+void vcl::I18nHelper::ImplDestroyWrappers()
+{
+ delete mpLocaleDataWrapper;
+ mpLocaleDataWrapper = NULL;
+
+ delete mpTransliterationWrapper;
+ mpTransliterationWrapper= NULL;
+}
+
+utl::TransliterationWrapper& vcl::I18nHelper::ImplGetTransliterationWrapper() const
+{
+ if ( !mpTransliterationWrapper )
+ {
+ sal_Int32 nModules = i18n::TransliterationModules_IGNORE_WIDTH;
+ if ( mbTransliterateIgnoreCase )
+ nModules |= i18n::TransliterationModules_IGNORE_CASE;
+
+ ((vcl::I18nHelper*)this)->mpTransliterationWrapper = new utl::TransliterationWrapper( mxMSF, (i18n::TransliterationModules)nModules );
+ ((vcl::I18nHelper*)this)->mpTransliterationWrapper->loadModuleIfNeeded( MsLangId::convertLocaleToLanguage( maLocale ) );
+ }
+ return *mpTransliterationWrapper;
+}
+
+LocaleDataWrapper& vcl::I18nHelper::ImplGetLocaleDataWrapper() const
+{
+ if ( !mpLocaleDataWrapper )
+ {
+ ((vcl::I18nHelper*)this)->mpLocaleDataWrapper = new LocaleDataWrapper( mxMSF, maLocale );
+ }
+ return *mpLocaleDataWrapper;
+}
+
+const ::com::sun::star::lang::Locale& vcl::I18nHelper::getLocale() const
+{
+ return maLocale;
+}
+
+inline bool is_formatting_mark( sal_Unicode c )
+{
+ if( (c >= 0x200B) && (c <= 0x200F) ) // BiDi and zero-width-markers
+ return true;
+ if( (c >= 0x2028) && (c <= 0x202E) ) // BiDi and paragraph-markers
+ return true;
+ return false;
+}
+
+/* #i100057# filter formatting marks out of strings before passing them to
+ the transliteration. The real solution would have been an additional TransliterationModule
+ to ignore these marks during transliteration; however changin the code in i18npool that actually
+ implements this could produce unwanted side effects.
+
+ Of course this copying around is not really good, but looking at i18npool, one more time
+ will not hurt.
+*/
+String vcl::I18nHelper::filterFormattingChars( const String& rStr )
+{
+ sal_Int32 nUnicodes = rStr.Len();
+ rtl::OUStringBuffer aBuf( nUnicodes );
+ const sal_Unicode* pStr = rStr.GetBuffer();
+ while( nUnicodes-- )
+ {
+ if( ! is_formatting_mark( *pStr ) )
+ aBuf.append( *pStr );
+ pStr++;
+ }
+ return aBuf.makeStringAndClear();
+}
+
+sal_Int32 vcl::I18nHelper::CompareString( const String& rStr1, const String& rStr2 ) const
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( ((vcl::I18nHelper*)this)->maMutex );
+
+ if ( mbTransliterateIgnoreCase )
+ {
+ // Change mbTransliterateIgnoreCase and destroy the warpper, next call to
+ // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase
+ ((vcl::I18nHelper*)this)->mbTransliterateIgnoreCase = FALSE;
+ delete ((vcl::I18nHelper*)this)->mpTransliterationWrapper;
+ ((vcl::I18nHelper*)this)->mpTransliterationWrapper = NULL;
+ }
+
+
+ String aStr1( filterFormattingChars(rStr1) );
+ String aStr2( filterFormattingChars(rStr2) );
+ return ImplGetTransliterationWrapper().compareString( aStr1, aStr2 );
+}
+
+sal_Bool vcl::I18nHelper::MatchString( const String& rStr1, const String& rStr2 ) const
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( ((vcl::I18nHelper*)this)->maMutex );
+
+ if ( !mbTransliterateIgnoreCase )
+ {
+ // Change mbTransliterateIgnoreCase and destroy the warpper, next call to
+ // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase
+ ((vcl::I18nHelper*)this)->mbTransliterateIgnoreCase = TRUE;
+ delete ((vcl::I18nHelper*)this)->mpTransliterationWrapper;
+ ((vcl::I18nHelper*)this)->mpTransliterationWrapper = NULL;
+ }
+
+ String aStr1( filterFormattingChars(rStr1) );
+ String aStr2( filterFormattingChars(rStr2) );
+ return ImplGetTransliterationWrapper().isMatch( aStr1, aStr2 );
+}
+
+sal_Bool vcl::I18nHelper::MatchMnemonic( const String& rString, sal_Unicode cMnemonicChar ) const
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( ((vcl::I18nHelper*)this)->maMutex );
+
+ BOOL bEqual = FALSE;
+ USHORT n = rString.Search( '~' );
+ if ( n != STRING_NOTFOUND )
+ {
+ String aMatchStr( rString, n+1, STRING_LEN ); // not only one char, because of transliteration...
+ bEqual = MatchString( cMnemonicChar, aMatchStr );
+ }
+ return bEqual;
+}
+
+
+String vcl::I18nHelper::GetDate( const Date& rDate ) const
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( ((vcl::I18nHelper*)this)->maMutex );
+
+ return ImplGetLocaleDataWrapper().getDate( rDate );
+}
+
+String vcl::I18nHelper::GetNum( long nNumber, USHORT nDecimals, BOOL bUseThousandSep, BOOL bTrailingZeros ) const
+{
+ return ImplGetLocaleDataWrapper().getNum( nNumber, nDecimals, bUseThousandSep, bTrailingZeros );
+}
diff --git a/vcl/source/app/idlemgr.cxx b/vcl/source/app/idlemgr.cxx
new file mode 100644
index 000000000000..0318bc5d6f2d
--- /dev/null
+++ b/vcl/source/app/idlemgr.cxx
@@ -0,0 +1,150 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/list.hxx>
+#include <vcl/idlemgr.hxx>
+#include <vcl/svapp.hxx>
+
+// =======================================================================
+
+struct ImplIdleData
+{
+ Link maIdleHdl;
+ USHORT mnPriority;
+ BOOL mbTimeout;
+};
+
+DECLARE_LIST( ImplIdleList, ImplIdleData* )
+
+#define IMPL_IDLETIMEOUT 350
+
+// =======================================================================
+
+ImplIdleMgr::ImplIdleMgr()
+{
+ mpIdleList = new ImplIdleList( 8, 8, 8 );
+
+ maTimer.SetTimeout( IMPL_IDLETIMEOUT );
+ maTimer.SetTimeoutHdl( LINK( this, ImplIdleMgr, TimeoutHdl ) );
+}
+
+// -----------------------------------------------------------------------
+
+ImplIdleMgr::~ImplIdleMgr()
+{
+ // Liste loeschen
+ ImplIdleData* pIdleData = mpIdleList->First();
+ while ( pIdleData )
+ {
+ delete pIdleData;
+ pIdleData = mpIdleList->Next();
+ }
+
+ delete mpIdleList;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplIdleMgr::InsertIdleHdl( const Link& rLink, USHORT nPriority )
+{
+ ULONG nPos = LIST_APPEND;
+ ImplIdleData* pIdleData = mpIdleList->First();
+ while ( pIdleData )
+ {
+ // Wenn Link schon existiert, dann gebe FALSE zurueck
+ if ( pIdleData->maIdleHdl == rLink )
+ return FALSE;
+
+ // Nach Prioritaet sortieren
+ if ( nPriority <= pIdleData->mnPriority )
+ nPos = mpIdleList->GetCurPos();
+
+ // Schleife nicht beenden, da noch
+ // geprueft werden muss, ob sich der Link
+ // schon in der Liste befindet
+
+ pIdleData = mpIdleList->Next();
+ }
+
+ pIdleData = new ImplIdleData;
+ pIdleData->maIdleHdl = rLink;
+ pIdleData->mnPriority = nPriority;
+ pIdleData->mbTimeout = FALSE;
+ mpIdleList->Insert( pIdleData, nPos );
+
+ // Wenn Timer noch nicht gestartet ist, dann starten
+ if ( !maTimer.IsActive() )
+ maTimer.Start();
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplIdleMgr::RemoveIdleHdl( const Link& rLink )
+{
+ ImplIdleData* pIdleData = mpIdleList->First();
+ while ( pIdleData )
+ {
+ if ( pIdleData->maIdleHdl == rLink )
+ {
+ mpIdleList->Remove();
+ delete pIdleData;
+ break;
+ }
+
+ pIdleData = mpIdleList->Next();
+ }
+
+ // keine Handdler mehr da
+ if ( !mpIdleList->Count() )
+ maTimer.Stop();
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplIdleMgr, TimeoutHdl, Timer*, EMPTYARG )
+{
+ ImplIdleData* pIdleData = mpIdleList->First();
+ while ( pIdleData )
+ {
+ if ( !pIdleData->mbTimeout )
+ {
+ pIdleData->mbTimeout = TRUE;
+ pIdleData->maIdleHdl.Call( GetpApp() );
+ // Kann im Handler entfernt worden sein
+ if ( mpIdleList->GetPos( pIdleData ) != LIST_ENTRY_NOTFOUND )
+ pIdleData->mbTimeout = FALSE;
+ }
+
+ pIdleData = mpIdleList->Next();
+ }
+
+ return 0;
+}
diff --git a/vcl/source/app/makefile.mk b/vcl/source/app/makefile.mk
new file mode 100644
index 000000000000..5d14f0032b4a
--- /dev/null
+++ b/vcl/source/app/makefile.mk
@@ -0,0 +1,69 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=app
+ENABLE_EXCEPTIONS=TRUE
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+CDEFS+=-DDLLPOSTFIX=$(DLLPOSTFIX)
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/dbggui.obj \
+ $(SLO)$/help.obj \
+ $(SLO)$/idlemgr.obj \
+ $(SLO)$/settings.obj \
+ $(SLO)$/sound.obj \
+ $(SLO)$/stdtext.obj \
+ $(SLO)$/svapp.obj \
+ $(SLO)$/svdata.obj \
+ $(SLO)$/svmain.obj \
+ $(SLO)$/svmainhook.obj \
+ $(SLO)$/timer.obj \
+ $(SLO)$/dndhelp.obj \
+ $(SLO)$/unohelp.obj \
+ $(SLO)$/unohelp2.obj \
+ $(SLO)$/vclevent.obj \
+ $(SLO)$/i18nhelp.obj \
+ $(SLO)$/salvtables.obj \
+ $(SLO)$/session.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
new file mode 100644
index 000000000000..9a2404d36740
--- /dev/null
+++ b/vcl/source/app/salvtables.cxx
@@ -0,0 +1,144 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/salframe.hxx>
+#include <vcl/salinst.hxx>
+#include <vcl/salvd.hxx>
+#include <vcl/salprn.hxx>
+#include <vcl/saltimer.hxx>
+#include <vcl/salimestatus.hxx>
+#include <vcl/salsys.hxx>
+#include <vcl/salbmp.hxx>
+#include <vcl/salobj.hxx>
+#include <vcl/salmenu.hxx>
+#include <vcl/salctrlhandle.hxx>
+
+// this file contains the virtual destructors of the sal interface
+// compilers ususally put their vtables where the destructor is
+
+SalFrame::~SalFrame()
+{
+}
+
+// -----------------------------------------------------------------------
+
+// default to full-frame flushes
+// on ports where partial-flushes are much cheaper this method should be overridden
+void SalFrame::Flush( const Rectangle& )
+{
+ Flush();
+}
+
+// -----------------------------------------------------------------------
+
+void SalFrame::SetRepresentedURL( const rtl::OUString& )
+{
+ // currently this is Mac only functionality
+}
+
+// -----------------------------------------------------------------------
+
+SalInstance::~SalInstance()
+{
+}
+
+void SalInstance::FillFontPathList( std::list< rtl::OString >& )
+{
+ // do nothing
+}
+
+SalTimer::~SalTimer()
+{
+}
+
+SalBitmap::~SalBitmap()
+{
+}
+
+SalI18NImeStatus::~SalI18NImeStatus()
+{
+}
+
+SalSystem::~SalSystem()
+{
+}
+
+SalPrinter::~SalPrinter()
+{
+}
+
+BOOL SalPrinter::StartJob( const String*, const String&, const String&,
+ ImplJobSetup*, vcl::PrinterController& )
+{
+ return FALSE;
+}
+
+SalInfoPrinter::~SalInfoPrinter()
+{
+}
+
+SalVirtualDevice::~SalVirtualDevice()
+{
+}
+
+SalObject::~SalObject()
+{
+}
+
+SalMenu::~SalMenu()
+{
+}
+
+bool SalMenu::ShowNativePopupMenu(FloatingWindow *, const Rectangle&, ULONG )
+{
+ return false;
+}
+
+bool SalMenu::AddMenuBarButton( const SalMenuButtonItem& )
+{
+ return false;
+}
+
+void SalMenu::RemoveMenuBarButton( USHORT )
+{
+}
+
+Rectangle SalMenu::GetMenuBarButtonRectPixel( USHORT, SalFrame* )
+{
+ return Rectangle();
+}
+
+SalMenuItem::~SalMenuItem()
+{
+}
+SalControlHandle::~SalControlHandle()
+{
+}
+
diff --git a/vcl/source/app/session.cxx b/vcl/source/app/session.cxx
new file mode 100644
index 000000000000..c65eb13224e1
--- /dev/null
+++ b/vcl/source/app/session.cxx
@@ -0,0 +1,369 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/svapp.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/salinst.hxx>
+#include <vcl/salsession.hxx>
+#include <cppuhelper/compbase1.hxx>
+#include <tools/debug.hxx>
+#include <com/sun/star/frame/XSessionManagerClient.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/frame/XSessionManagerListener2.hpp>
+
+#include <list>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::frame;
+using namespace rtl;
+
+SalSession::~SalSession()
+{
+}
+
+class VCLSession : public cppu::WeakComponentImplHelper1 < XSessionManagerClient >
+{
+ struct Listener
+ {
+ Reference< XSessionManagerListener > m_xListener;
+ bool m_bInteractionRequested;
+ bool m_bInteractionDone;
+ bool m_bSaveDone;
+
+ Listener( const Reference< XSessionManagerListener >& xListener )
+ : m_xListener( xListener ),
+ m_bInteractionRequested( false ),
+ m_bInteractionDone( false ),
+ m_bSaveDone( false )
+ {}
+ };
+
+ std::list< Listener > m_aListeners;
+ SalSession* m_pSession;
+ osl::Mutex m_aMutex;
+ bool m_bInteractionRequested;
+ bool m_bInteractionGranted;
+ bool m_bInteractionDone;
+ bool m_bSaveDone;
+
+ static void SalSessionEventProc( SalSessionEvent* pEvent );
+ static VCLSession* pOneInstance;
+
+ void callSaveRequested( bool bShutdown, bool bCancelable );
+ void callShutdownCancelled();
+ void callInteractionGranted( bool bGranted );
+ void callQuit();
+public:
+ VCLSession();
+ virtual ~VCLSession();
+
+ virtual void SAL_CALL addSessionManagerListener( const Reference< XSessionManagerListener >& xListener ) throw( RuntimeException );
+ virtual void SAL_CALL removeSessionManagerListener( const Reference< XSessionManagerListener>& xListener ) throw( RuntimeException );
+ virtual void SAL_CALL queryInteraction( const Reference< XSessionManagerListener >& xListener ) throw( RuntimeException );
+ virtual void SAL_CALL interactionDone( const Reference< XSessionManagerListener >& xListener ) throw( RuntimeException );
+ virtual void SAL_CALL saveDone( const Reference< XSessionManagerListener >& xListener ) throw( RuntimeException );
+ virtual sal_Bool SAL_CALL cancelShutdown() throw( RuntimeException );
+};
+
+VCLSession* VCLSession::pOneInstance = NULL;
+
+VCLSession::VCLSession()
+ : cppu::WeakComponentImplHelper1< XSessionManagerClient >( m_aMutex ),
+ m_bInteractionRequested( false ),
+ m_bInteractionGranted( false ),
+ m_bInteractionDone( false ),
+ m_bSaveDone( false )
+{
+ DBG_ASSERT( pOneInstance == 0, "One instance of VCLSession only !" );
+ pOneInstance = this;
+ m_pSession = ImplGetSVData()->mpDefInst->CreateSalSession();
+ if( m_pSession )
+ m_pSession->SetCallback( SalSessionEventProc );
+}
+
+VCLSession::~VCLSession()
+{
+ DBG_ASSERT( pOneInstance == this, "Another instance of VCLSession in destructor !" );
+ pOneInstance = NULL;
+ delete m_pSession;
+}
+
+void VCLSession::callSaveRequested( bool bShutdown, bool bCancelable )
+{
+ std::list< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // reset listener states
+ for( std::list< Listener >::iterator it = m_aListeners.begin();
+ it != m_aListeners.end(); ++it )
+ {
+ it->m_bSaveDone = it->m_bInteractionRequested = it->m_bInteractionDone = false;
+ }
+
+ // copy listener list since calling a listener may remove it.
+ aListeners = m_aListeners;
+ // set back interaction state
+ m_bSaveDone = false;
+ m_bInteractionDone = false;
+ // without session we assume UI is always possible,
+ // so it was reqeusted and granted
+ m_bInteractionRequested = m_bInteractionGranted = m_pSession ? false : true;
+
+ // answer the session manager even if no listeners available anymore
+ DBG_ASSERT( ! aListeners.empty(), "saveRequested but no listeners !" );
+ if( aListeners.empty() )
+ {
+ if( m_pSession )
+ m_pSession->saveDone();
+ return;
+ }
+ }
+
+ ULONG nAcquireCount = Application::ReleaseSolarMutex();
+ for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it )
+ it->m_xListener->doSave( bShutdown, bCancelable );
+ Application::AcquireSolarMutex( nAcquireCount );
+}
+
+void VCLSession::callInteractionGranted( bool bInteractionGranted )
+{
+ std::list< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // copy listener list since calling a listener may remove it.
+ for( std::list< Listener >::const_iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it )
+ if( it->m_bInteractionRequested )
+ aListeners.push_back( *it );
+
+ m_bInteractionGranted = bInteractionGranted;
+
+ // answer the session manager even if no listeners available anymore
+ DBG_ASSERT( ! aListeners.empty(), "interactionGranted but no listeners !" );
+ if( aListeners.empty() )
+ {
+ if( m_pSession )
+ m_pSession->interactionDone();
+ return;
+ }
+ }
+
+ ULONG nAcquireCount = Application::ReleaseSolarMutex();
+ for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it )
+ it->m_xListener->approveInteraction( bInteractionGranted );
+
+ Application::AcquireSolarMutex( nAcquireCount );
+}
+
+void VCLSession::callShutdownCancelled()
+{
+ std::list< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // copy listener list since calling a listener may remove it.
+ aListeners = m_aListeners;
+ // set back interaction state
+ m_bInteractionRequested = m_bInteractionDone = m_bInteractionGranted = false;
+ }
+
+ ULONG nAcquireCount = Application::ReleaseSolarMutex();
+ for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it )
+ it->m_xListener->shutdownCanceled();
+ Application::AcquireSolarMutex( nAcquireCount );
+}
+
+void VCLSession::callQuit()
+{
+ std::list< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // copy listener list since calling a listener may remove it.
+ aListeners = m_aListeners;
+ // set back interaction state
+ m_bInteractionRequested = m_bInteractionDone = m_bInteractionGranted = false;
+ }
+
+ ULONG nAcquireCount = Application::ReleaseSolarMutex();
+ for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it )
+ {
+ Reference< XSessionManagerListener2 > xListener2( it->m_xListener, UNO_QUERY );
+ if( xListener2.is() )
+ xListener2->doQuit();
+ }
+ Application::AcquireSolarMutex( nAcquireCount );
+}
+
+void VCLSession::SalSessionEventProc( SalSessionEvent* pEvent )
+{
+ switch( pEvent->m_eType )
+ {
+ case Interaction:
+ {
+ SalSessionInteractionEvent* pIEv = static_cast<SalSessionInteractionEvent*>(pEvent);
+ pOneInstance->callInteractionGranted( pIEv->m_bInteractionGranted );
+ }
+ break;
+ case SaveRequest:
+ {
+ SalSessionSaveRequestEvent* pSEv = static_cast<SalSessionSaveRequestEvent*>(pEvent);
+ pOneInstance->callSaveRequested( pSEv->m_bShutdown, pSEv->m_bCancelable );
+ }
+ break;
+ case ShutdownCancel:
+ pOneInstance->callShutdownCancelled();
+ break;
+ case Quit:
+ pOneInstance->callQuit();
+ break;
+ }
+}
+
+void SAL_CALL VCLSession::addSessionManagerListener( const Reference<XSessionManagerListener>& xListener ) throw( RuntimeException )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ m_aListeners.push_back( Listener( xListener ) );
+}
+
+void SAL_CALL VCLSession::removeSessionManagerListener( const Reference<XSessionManagerListener>& xListener ) throw( RuntimeException )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ std::list< Listener >::iterator it = m_aListeners.begin();
+ while( it != m_aListeners.end() )
+ {
+ if( it->m_xListener == xListener )
+ {
+ m_aListeners.erase( it );
+ it = m_aListeners.begin();
+ }
+ else
+ ++it;
+ }
+}
+
+void SAL_CALL VCLSession::queryInteraction( const Reference<XSessionManagerListener>& xListener ) throw( RuntimeException )
+{
+ if( m_bInteractionGranted )
+ {
+ if( m_bInteractionDone )
+ xListener->approveInteraction( false );
+ else
+ xListener->approveInteraction( true );
+ return;
+ }
+
+ osl::MutexGuard aGuard( m_aMutex );
+ if( ! m_bInteractionRequested )
+ {
+ m_pSession->queryInteraction();
+ m_bInteractionRequested = true;
+ }
+ for( std::list< Listener >::iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it )
+ {
+ if( it->m_xListener == xListener )
+ {
+ it->m_bInteractionRequested = true;
+ it->m_bInteractionDone = false;
+ }
+ }
+}
+
+void SAL_CALL VCLSession::interactionDone( const Reference< XSessionManagerListener >& xListener ) throw( RuntimeException )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ int nRequested = 0, nDone = 0;
+ for( std::list< Listener >::iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it )
+ {
+ if( it->m_bInteractionRequested )
+ {
+ nRequested++;
+ if( xListener == it->m_xListener )
+ it->m_bInteractionDone = true;
+ }
+ if( it->m_bInteractionDone )
+ nDone++;
+ }
+ if( nDone == nRequested && nDone > 0 )
+ {
+ m_bInteractionDone = true;
+ if( m_pSession )
+ m_pSession->interactionDone();
+ }
+}
+
+void SAL_CALL VCLSession::saveDone( const Reference< XSessionManagerListener >& xListener ) throw( RuntimeException )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ bool bSaveDone = true;
+ for( std::list< Listener >::iterator it = m_aListeners.begin();
+ it != m_aListeners.end(); ++it )
+ {
+ if( it->m_xListener == xListener )
+ it->m_bSaveDone = true;
+ if( ! it->m_bSaveDone )
+ bSaveDone = false;
+ }
+ if( bSaveDone )
+ {
+ m_bSaveDone = true;
+ if( m_pSession )
+ m_pSession->saveDone();
+ }
+}
+
+sal_Bool SAL_CALL VCLSession::cancelShutdown() throw( RuntimeException )
+{
+ return m_pSession ? (sal_Bool)m_pSession->cancelShutdown() : sal_False;
+}
+
+// service implementation
+
+OUString SAL_CALL vcl_session_getImplementationName()
+{
+ static OUString aImplementationName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.VCLSessionManagerClient" ) );
+ return aImplementationName;
+}
+
+Sequence< rtl::OUString > SAL_CALL vcl_session_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString::createFromAscii("com.sun.star.frame.SessionManagerClient");
+ return aRet;
+}
+
+Reference< XInterface > SAL_CALL vcl_session_createInstance( const Reference< XMultiServiceFactory > & /*xMultiServiceFactory*/ )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->xSMClient.is() )
+ pSVData->xSMClient = new VCLSession();
+
+ return Reference< XInterface >(pSVData->xSMClient, UNO_QUERY );
+}
diff --git a/vcl/source/app/settings.cxx b/vcl/source/app/settings.cxx
new file mode 100755
index 000000000000..7f97ba2d8720
--- /dev/null
+++ b/vcl/source/app/settings.cxx
@@ -0,0 +1,2081 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include "tools/debug.hxx"
+#include "i18npool/mslangid.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/event.hxx"
+#include "vcl/settings.hxx"
+#include "vcl/i18nhelp.hxx"
+#include "unotools/fontcfg.hxx"
+#include "vcl/configsettings.hxx"
+#include "vcl/gradient.hxx"
+#include "vcl/unohelp.hxx"
+#include "vcl/bitmapex.hxx"
+#include "vcl/impimagetree.hxx"
+#include "unotools/localedatawrapper.hxx"
+#include "unotools/collatorwrapper.hxx"
+#include "unotools/configmgr.hxx"
+#include "unotools/confignode.hxx"
+#include <unotools/syslocaleoptions.hxx>
+
+#ifdef WNT
+#include "tools/prewin.h"
+#include <windows.h>
+#include "tools/postwin.h"
+#endif
+
+using namespace rtl;
+
+// =======================================================================
+
+DBG_NAME( AllSettings )
+
+// =======================================================================
+
+#define STDSYS_STYLE (STYLE_OPTION_SCROLLARROW | \
+ STYLE_OPTION_SPINARROW | \
+ STYLE_OPTION_SPINUPDOWN | \
+ STYLE_OPTION_NOMNEMONICS)
+
+// =======================================================================
+ImplMachineData::ImplMachineData()
+{
+ mnRefCount = 1;
+ mnOptions = 0;
+ mnScreenOptions = 0;
+ mnPrintOptions = 0;
+ mnScreenRasterFontDeviation = 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplMachineData::ImplMachineData( const ImplMachineData& rData )
+{
+ mnRefCount = 1;
+ mnOptions = rData.mnOptions;
+ mnScreenOptions = rData.mnScreenOptions;
+ mnPrintOptions = rData.mnPrintOptions;
+ mnScreenRasterFontDeviation = rData.mnScreenRasterFontDeviation;
+}
+
+// -----------------------------------------------------------------------
+
+MachineSettings::MachineSettings()
+{
+ mpData = new ImplMachineData();
+}
+
+// -----------------------------------------------------------------------
+
+MachineSettings::MachineSettings( const MachineSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "MachineSettings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+MachineSettings::~MachineSettings()
+{
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+const MachineSettings& MachineSettings::operator =( const MachineSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "MachineSettings: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void MachineSettings::CopyData()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplMachineData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MachineSettings::operator ==( const MachineSettings& rSet ) const
+{
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->mnOptions == rSet.mpData->mnOptions) &&
+ (mpData->mnScreenOptions == rSet.mpData->mnScreenOptions) &&
+ (mpData->mnPrintOptions == rSet.mpData->mnPrintOptions) &&
+ (mpData->mnScreenRasterFontDeviation == rSet.mpData->mnScreenRasterFontDeviation) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// =======================================================================
+
+ImplMouseData::ImplMouseData()
+{
+ mnRefCount = 1;
+ mnOptions = 0;
+ mnDoubleClkTime = 500;
+ mnDoubleClkWidth = 2;
+ mnDoubleClkHeight = 2;
+ mnStartDragWidth = 2;
+ mnStartDragHeight = 2;
+ mnStartDragCode = MOUSE_LEFT;
+ mnDragMoveCode = 0;
+ mnDragCopyCode = KEY_MOD1;
+ mnDragLinkCode = KEY_SHIFT | KEY_MOD1;
+ mnContextMenuCode = MOUSE_RIGHT;
+ mnContextMenuClicks = 1;
+ mbContextMenuDown = TRUE;
+ mnMiddleButtonAction = MOUSE_MIDDLE_AUTOSCROLL;
+ mnScrollRepeat = 100;
+ mnButtonStartRepeat = 370;
+ mnButtonRepeat = 90;
+ mnActionDelay = 250;
+ mnMenuDelay = 150;
+ mnFollow = MOUSE_FOLLOW_MENU | MOUSE_FOLLOW_DDLIST;
+ mnWheelBehavior = MOUSE_WHEEL_ALWAYS;
+}
+
+// -----------------------------------------------------------------------
+
+ImplMouseData::ImplMouseData( const ImplMouseData& rData )
+{
+ mnRefCount = 1;
+ mnOptions = rData.mnOptions;
+ mnDoubleClkTime = rData.mnDoubleClkTime;
+ mnDoubleClkWidth = rData.mnDoubleClkWidth;
+ mnDoubleClkHeight = rData.mnDoubleClkHeight;
+ mnStartDragWidth = rData.mnStartDragWidth;
+ mnStartDragHeight = rData.mnStartDragHeight;
+ mnStartDragCode = rData.mnStartDragCode;
+ mnDragMoveCode = rData.mnDragMoveCode;
+ mnDragCopyCode = rData.mnDragCopyCode;
+ mnDragLinkCode = rData.mnDragLinkCode;
+ mnContextMenuCode = rData.mnContextMenuCode;
+ mnContextMenuClicks = rData.mnContextMenuClicks;
+ mbContextMenuDown = rData.mbContextMenuDown;
+ mnMiddleButtonAction = rData.mnMiddleButtonAction;
+ mnScrollRepeat = rData.mnScrollRepeat;
+ mnButtonStartRepeat = rData.mnButtonStartRepeat;
+ mnButtonRepeat = rData.mnButtonRepeat;
+ mnActionDelay = rData.mnActionDelay;
+ mnMenuDelay = rData.mnMenuDelay;
+ mnFollow = rData.mnFollow;
+ mnWheelBehavior = rData.mnWheelBehavior;
+}
+
+// -----------------------------------------------------------------------
+
+MouseSettings::MouseSettings()
+{
+ mpData = new ImplMouseData();
+}
+
+// -----------------------------------------------------------------------
+
+MouseSettings::MouseSettings( const MouseSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "MouseSettings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+MouseSettings::~MouseSettings()
+{
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+const MouseSettings& MouseSettings::operator =( const MouseSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "MouseSettings: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void MouseSettings::CopyData()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplMouseData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MouseSettings::operator ==( const MouseSettings& rSet ) const
+{
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->mnOptions == rSet.mpData->mnOptions) &&
+ (mpData->mnDoubleClkTime == rSet.mpData->mnDoubleClkTime) &&
+ (mpData->mnDoubleClkWidth == rSet.mpData->mnDoubleClkWidth) &&
+ (mpData->mnDoubleClkHeight == rSet.mpData->mnDoubleClkHeight) &&
+ (mpData->mnStartDragWidth == rSet.mpData->mnStartDragWidth) &&
+ (mpData->mnStartDragHeight == rSet.mpData->mnStartDragHeight) &&
+ (mpData->mnStartDragCode == rSet.mpData->mnStartDragCode) &&
+ (mpData->mnDragMoveCode == rSet.mpData->mnDragMoveCode) &&
+ (mpData->mnDragCopyCode == rSet.mpData->mnDragCopyCode) &&
+ (mpData->mnDragLinkCode == rSet.mpData->mnDragLinkCode) &&
+ (mpData->mnContextMenuCode == rSet.mpData->mnContextMenuCode) &&
+ (mpData->mnContextMenuClicks == rSet.mpData->mnContextMenuClicks) &&
+ (mpData->mbContextMenuDown == rSet.mpData->mbContextMenuDown) &&
+ (mpData->mnMiddleButtonAction == rSet.mpData->mnMiddleButtonAction) &&
+ (mpData->mnScrollRepeat == rSet.mpData->mnScrollRepeat) &&
+ (mpData->mnButtonStartRepeat == rSet.mpData->mnButtonStartRepeat) &&
+ (mpData->mnButtonRepeat == rSet.mpData->mnButtonRepeat) &&
+ (mpData->mnActionDelay == rSet.mpData->mnActionDelay) &&
+ (mpData->mnMenuDelay == rSet.mpData->mnMenuDelay) &&
+ (mpData->mnFollow == rSet.mpData->mnFollow) &&
+ (mpData->mnWheelBehavior == rSet.mpData->mnWheelBehavior ) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// =======================================================================
+
+ImplKeyboardData::ImplKeyboardData()
+{
+ mnRefCount = 1;
+ mnOptions = 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplKeyboardData::ImplKeyboardData( const ImplKeyboardData& rData )
+{
+ mnRefCount = 1;
+ mnOptions = rData.mnOptions;
+}
+
+// -----------------------------------------------------------------------
+
+KeyboardSettings::KeyboardSettings()
+{
+ mpData = new ImplKeyboardData();
+}
+
+// -----------------------------------------------------------------------
+
+KeyboardSettings::KeyboardSettings( const KeyboardSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "KeyboardSettings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+KeyboardSettings::~KeyboardSettings()
+{
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+const KeyboardSettings& KeyboardSettings::operator =( const KeyboardSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "KeyboardSettings: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void KeyboardSettings::CopyData()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplKeyboardData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL KeyboardSettings::operator ==( const KeyboardSettings& rSet ) const
+{
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->mnOptions == rSet.mpData->mnOptions) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// =======================================================================
+
+ImplStyleData::ImplStyleData()
+{
+ mnRefCount = 1;
+ mnScrollBarSize = 16;
+ mnMinThumbSize = 16;
+ mnSplitSize = 3;
+ mnSpinSize = 16;
+ mnIconHorzSpace = 50;
+ mnIconVertSpace = 40;
+ mnAntialiasedMin = 0;
+ mnCursorSize = 2;
+ mnCursorBlinkTime = STYLE_CURSOR_NOBLINKTIME;
+ mnScreenZoom = 100;
+ mnScreenFontZoom = 100;
+ mnRadioButtonStyle = 0;
+ mnCheckBoxStyle = 0;
+ mnPushButtonStyle = 0;
+ mnTabControlStyle = 0;
+ mnLogoDisplayTime = LOGO_DISPLAYTIME_STARTTIME;
+ mnDragFullOptions = 0;
+ mnAnimationOptions = 0;
+ mnSelectionOptions = 0;
+ mnDisplayOptions = 0;
+ mnOptions = 0;
+ mnAutoMnemonic = 1;
+ mnToolbarIconSize = STYLE_TOOLBAR_ICONSIZE_UNKNOWN;
+ mnSymbolsStyle = STYLE_SYMBOLS_AUTO;
+ mnPreferredSymbolsStyle = STYLE_SYMBOLS_AUTO;
+ mpFontOptions = NULL;
+
+ SetStandardStyles();
+}
+
+// -----------------------------------------------------------------------
+
+ImplStyleData::ImplStyleData( const ImplStyleData& rData ) :
+ maActiveBorderColor( rData.maActiveBorderColor ),
+ maActiveColor( rData.maActiveColor ),
+ maActiveColor2( rData.maActiveColor2 ),
+ maActiveTextColor( rData.maActiveTextColor ),
+ maButtonTextColor( rData.maButtonTextColor ),
+ maButtonRolloverTextColor( rData.maButtonRolloverTextColor ),
+ maCheckedColor( rData.maCheckedColor ),
+ maDarkShadowColor( rData.maDarkShadowColor ),
+ maDeactiveBorderColor( rData.maDeactiveBorderColor ),
+ maDeactiveColor( rData.maDeactiveColor ),
+ maDeactiveColor2( rData.maDeactiveColor2 ),
+ maDeactiveTextColor( rData.maDeactiveTextColor ),
+ maDialogColor( rData.maDialogColor ),
+ maDialogTextColor( rData.maDialogTextColor ),
+ maDisableColor( rData.maDisableColor ),
+ maFaceColor( rData.maFaceColor ),
+ maFieldColor( rData.maFieldColor ),
+ maFieldTextColor( rData.maFieldTextColor ),
+ maFieldRolloverTextColor( rData.maFieldRolloverTextColor ),
+ maFontColor( rData.maFontColor ),
+ maGroupTextColor( rData.maGroupTextColor ),
+ maHelpColor( rData.maHelpColor ),
+ maHelpTextColor( rData.maHelpTextColor ),
+ maHighlightColor( rData.maHighlightColor ),
+ maHighlightLinkColor( rData.maHighlightLinkColor ),
+ maHighlightTextColor( rData.maHighlightTextColor ),
+ maInfoTextColor( rData.maInfoTextColor ),
+ maLabelTextColor( rData.maLabelTextColor ),
+ maLightBorderColor( rData.maLightBorderColor ),
+ maLightColor( rData.maLightColor ),
+ maLinkColor( rData.maLinkColor ),
+ maMenuBarColor( rData.maMenuBarColor ),
+ maMenuBorderColor( rData.maMenuBorderColor ),
+ maMenuColor( rData.maMenuColor ),
+ maMenuHighlightColor( rData.maMenuHighlightColor ),
+ maMenuHighlightTextColor( rData.maMenuHighlightTextColor ),
+ maMenuTextColor( rData.maMenuTextColor ),
+ maMenuBarTextColor( rData.maMenuBarTextColor ),
+ maMonoColor( rData.maMonoColor ),
+ maRadioCheckTextColor( rData.maRadioCheckTextColor ),
+ maShadowColor( rData.maShadowColor ),
+ maVisitedLinkColor( rData.maVisitedLinkColor ),
+ maWindowColor( rData.maWindowColor ),
+ maWindowTextColor( rData.maWindowTextColor ),
+ maWorkspaceColor( rData.maWorkspaceColor ),
+ maActiveTabColor( rData.maActiveTabColor ),
+ maInactiveTabColor( rData.maInactiveTabColor ),
+ maAppFont( rData.maAppFont ),
+ maHelpFont( rData.maAppFont ),
+ maTitleFont( rData.maTitleFont ),
+ maFloatTitleFont( rData.maFloatTitleFont ),
+ maMenuFont( rData.maMenuFont ),
+ maToolFont( rData.maToolFont ),
+ maLabelFont( rData.maLabelFont ),
+ maInfoFont( rData.maInfoFont ),
+ maRadioCheckFont( rData.maRadioCheckFont ),
+ maPushButtonFont( rData.maPushButtonFont ),
+ maFieldFont( rData.maFieldFont ),
+ maIconFont( rData.maIconFont ),
+ maGroupFont( rData.maGroupFont ),
+ maWorkspaceGradient( rData.maWorkspaceGradient )
+{
+ mnRefCount = 1;
+ mnBorderSize = rData.mnBorderSize;
+ mnTitleHeight = rData.mnTitleHeight;
+ mnFloatTitleHeight = rData.mnFloatTitleHeight;
+ mnTearOffTitleHeight = rData.mnTearOffTitleHeight;
+ mnMenuBarHeight = rData.mnMenuBarHeight;
+ mnScrollBarSize = rData.mnScrollBarSize;
+ mnMinThumbSize = rData.mnMinThumbSize;
+ mnSplitSize = rData.mnSplitSize;
+ mnSpinSize = rData.mnSpinSize;
+ mnIconHorzSpace = rData.mnIconHorzSpace;
+ mnIconVertSpace = rData.mnIconVertSpace;
+ mnAntialiasedMin = rData.mnAntialiasedMin;
+ mnCursorSize = rData.mnCursorSize;
+ mnCursorBlinkTime = rData.mnCursorBlinkTime;
+ mnScreenZoom = rData.mnScreenZoom;
+ mnScreenFontZoom = rData.mnScreenFontZoom;
+ mnRadioButtonStyle = rData.mnRadioButtonStyle;
+ mnCheckBoxStyle = rData.mnCheckBoxStyle;
+ mnPushButtonStyle = rData.mnPushButtonStyle;
+ mnTabControlStyle = rData.mnTabControlStyle;
+ mnLogoDisplayTime = rData.mnLogoDisplayTime;
+ mnDragFullOptions = rData.mnDragFullOptions;
+ mnAnimationOptions = rData.mnAnimationOptions;
+ mnSelectionOptions = rData.mnSelectionOptions;
+ mnDisplayOptions = rData.mnDisplayOptions;
+ mnOptions = rData.mnOptions;
+ mnHighContrast = rData.mnHighContrast;
+ mnUseSystemUIFonts = rData.mnUseSystemUIFonts;
+ mnUseFlatBorders = rData.mnUseFlatBorders;
+ mnUseFlatMenues = rData.mnUseFlatMenues;
+ mnAutoMnemonic = rData.mnAutoMnemonic;
+ mnUseImagesInMenus = rData.mnUseImagesInMenus;
+ mnSkipDisabledInMenus = rData.mnSkipDisabledInMenus;
+ mnToolbarIconSize = rData.mnToolbarIconSize;
+ mnSymbolsStyle = rData.mnSymbolsStyle;
+ mnPreferredSymbolsStyle = rData.mnPreferredSymbolsStyle;
+ mpFontOptions = rData.mpFontOptions;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplStyleData::SetStandardStyles()
+{
+ Font aStdFont( FAMILY_SWISS, Size( 0, 8 ) );
+ aStdFont.SetCharSet( gsl_getSystemTextEncoding() );
+ aStdFont.SetWeight( WEIGHT_NORMAL );
+ aStdFont.SetName( utl::DefaultFontConfiguration::get()->getUserInterfaceFont(com::sun::star::lang::Locale( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), rtl::OUString(), rtl::OUString() ) ) );
+ maAppFont = aStdFont;
+ maHelpFont = aStdFont;
+ maMenuFont = aStdFont;
+ maToolFont = aStdFont;
+ maGroupFont = aStdFont;
+ maLabelFont = aStdFont;
+ maInfoFont = aStdFont;
+ maRadioCheckFont = aStdFont;
+ maPushButtonFont = aStdFont;
+ maFieldFont = aStdFont;
+ maIconFont = aStdFont;
+ maFloatTitleFont = aStdFont;
+ aStdFont.SetWeight( WEIGHT_BOLD );
+ maTitleFont = aStdFont;
+
+ maFaceColor = Color( COL_LIGHTGRAY );
+ maCheckedColor = Color( 0xCC, 0xCC, 0xCC );
+ maLightColor = Color( COL_WHITE );
+ maLightBorderColor = Color( COL_LIGHTGRAY );
+ maShadowColor = Color( COL_GRAY );
+ maDarkShadowColor = Color( COL_BLACK );
+ maButtonTextColor = Color( COL_BLACK );
+ maButtonRolloverTextColor = Color( COL_BLACK );
+ maRadioCheckTextColor = Color( COL_BLACK );
+ maGroupTextColor = Color( COL_BLACK );
+ maLabelTextColor = Color( COL_BLACK );
+ maInfoTextColor = Color( COL_BLACK );
+ maWindowColor = Color( COL_WHITE );
+ maWindowTextColor = Color( COL_BLACK );
+ maDialogColor = Color( COL_LIGHTGRAY );
+ maDialogTextColor = Color( COL_BLACK );
+ maWorkspaceColor = Color( COL_GRAY );
+ maMonoColor = Color( COL_BLACK );
+ maFieldColor = Color( COL_WHITE );
+ maFieldTextColor = Color( COL_BLACK );
+ maFieldRolloverTextColor = Color( COL_BLACK );
+ maActiveColor = Color( COL_BLUE );
+ maActiveColor2 = Color( COL_BLACK );
+ maActiveTextColor = Color( COL_WHITE );
+ maActiveBorderColor = Color( COL_LIGHTGRAY );
+ maDeactiveColor = Color( COL_GRAY );
+ maDeactiveColor2 = Color( COL_BLACK );
+ maDeactiveTextColor = Color( COL_LIGHTGRAY );
+ maDeactiveBorderColor = Color( COL_LIGHTGRAY );
+ maMenuColor = Color( COL_LIGHTGRAY );
+ maMenuBarColor = Color( COL_LIGHTGRAY );
+ maMenuBorderColor = Color( COL_LIGHTGRAY );
+ maMenuTextColor = Color( COL_BLACK );
+ maMenuBarTextColor = Color( COL_BLACK );
+ maMenuHighlightColor = Color( COL_BLUE );
+ maMenuHighlightTextColor = Color( COL_WHITE );
+ maHighlightColor = Color( COL_BLUE );
+ maHighlightTextColor = Color( COL_WHITE );
+ maActiveTabColor = Color( COL_WHITE );
+ maInactiveTabColor = Color( COL_LIGHTGRAY );
+ maDisableColor = Color( COL_GRAY );
+ maHelpColor = Color( 0xFF, 0xFF, 0xE0 );
+ maHelpTextColor = Color( COL_BLACK );
+ maLinkColor = Color( COL_BLUE );
+ maVisitedLinkColor = Color( 0x00, 0x00, 0xCC );
+ maHighlightLinkColor = Color( COL_LIGHTBLUE );
+ maFontColor = Color( COL_BLACK );
+
+ mnRadioButtonStyle &= ~STYLE_RADIOBUTTON_STYLE;
+ mnCheckBoxStyle &= ~STYLE_CHECKBOX_STYLE;
+ mnPushButtonStyle &= ~STYLE_PUSHBUTTON_STYLE;
+ mnTabControlStyle = 0;
+
+ mnOptions &= ~(STYLE_OPTION_SYSTEMSTYLE | STDSYS_STYLE);
+ mnBorderSize = 1;
+ mnTitleHeight = 18;
+ mnFloatTitleHeight = 13;
+ mnTearOffTitleHeight = 8;
+ mnMenuBarHeight = 14;
+ mnHighContrast = 0;
+ mnUseSystemUIFonts = 1;
+ mnUseFlatBorders = 0;
+ mnUseFlatMenues = 0;
+ mnUseImagesInMenus = (USHORT)TRUE;
+ mnSkipDisabledInMenus = (USHORT)FALSE;
+
+ Gradient aGrad( GRADIENT_LINEAR, DEFAULT_WORKSPACE_GRADIENT_START_COLOR, DEFAULT_WORKSPACE_GRADIENT_END_COLOR );
+ maWorkspaceGradient = Wallpaper( aGrad );
+}
+
+// -----------------------------------------------------------------------
+
+StyleSettings::StyleSettings()
+{
+ mpData = new ImplStyleData();
+}
+
+// -----------------------------------------------------------------------
+
+StyleSettings::StyleSettings( const StyleSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "StyleSettings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+StyleSettings::~StyleSettings()
+{
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+void StyleSettings::Set3DColors( const Color& rColor )
+{
+ CopyData();
+ mpData->maFaceColor = rColor;
+ mpData->maLightBorderColor = rColor;
+ mpData->maMenuBorderColor = rColor;
+ mpData->maDarkShadowColor = Color( COL_BLACK );
+ if ( rColor != Color( COL_LIGHTGRAY ) )
+ {
+ mpData->maLightColor = rColor;
+ mpData->maShadowColor = rColor;
+ mpData->maLightColor.IncreaseLuminance( 64 );
+ mpData->maShadowColor.DecreaseLuminance( 64 );
+ ULONG nRed = mpData->maLightColor.GetRed();
+ ULONG nGreen = mpData->maLightColor.GetGreen();
+ ULONG nBlue = mpData->maLightColor.GetBlue();
+ nRed += (ULONG)(mpData->maShadowColor.GetRed());
+ nGreen += (ULONG)(mpData->maShadowColor.GetGreen());
+ nBlue += (ULONG)(mpData->maShadowColor.GetBlue());
+ mpData->maCheckedColor = Color( (BYTE)(nRed/2), (BYTE)(nGreen/2), (BYTE)(nBlue/2) );
+ }
+ else
+ {
+ mpData->maCheckedColor = Color( 0x99, 0x99, 0x99 );
+ mpData->maLightColor = Color( COL_WHITE );
+ mpData->maShadowColor = Color( COL_GRAY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+::rtl::OUString StyleSettings::ImplSymbolsStyleToName( ULONG nStyle ) const
+{
+ switch ( nStyle )
+ {
+ case STYLE_SYMBOLS_DEFAULT: return ::rtl::OUString::createFromAscii( "default" );
+ case STYLE_SYMBOLS_HICONTRAST: return ::rtl::OUString::createFromAscii( "hicontrast" );
+ case STYLE_SYMBOLS_INDUSTRIAL: return ::rtl::OUString::createFromAscii( "tango" ); // industrial is dead
+ case STYLE_SYMBOLS_CRYSTAL: return ::rtl::OUString::createFromAscii( "crystal" );
+ case STYLE_SYMBOLS_TANGO: return ::rtl::OUString::createFromAscii( "tango" );
+ case STYLE_SYMBOLS_OXYGEN: return ::rtl::OUString::createFromAscii( "oxygen" );
+ case STYLE_SYMBOLS_CLASSIC: return ::rtl::OUString::createFromAscii( "classic" );
+ }
+
+ return ::rtl::OUString::createFromAscii( "auto" );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG StyleSettings::ImplNameToSymbolsStyle( const ::rtl::OUString &rName ) const
+{
+ if ( rName == ::rtl::OUString::createFromAscii( "default" ) )
+ return STYLE_SYMBOLS_DEFAULT;
+ else if ( rName == ::rtl::OUString::createFromAscii( "hicontrast" ) )
+ return STYLE_SYMBOLS_HICONTRAST;
+ else if ( rName == ::rtl::OUString::createFromAscii( "industrial" ) )
+ return STYLE_SYMBOLS_TANGO; // industrial is dead
+ else if ( rName == ::rtl::OUString::createFromAscii( "crystal" ) )
+ return STYLE_SYMBOLS_CRYSTAL;
+ else if ( rName == ::rtl::OUString::createFromAscii( "tango" ) )
+ return STYLE_SYMBOLS_TANGO;
+ else if ( rName == ::rtl::OUString::createFromAscii( "oxygen" ) )
+ return STYLE_SYMBOLS_OXYGEN;
+ else if ( rName == ::rtl::OUString::createFromAscii( "classic" ) )
+ return STYLE_SYMBOLS_CLASSIC;
+
+ return STYLE_SYMBOLS_AUTO;
+}
+
+// -----------------------------------------------------------------------
+
+/**
+ The preferred style name can be read from the desktop setting. We
+ need to find the closest theme name registered in OOo. Therefore
+ we check if any registered style name is a case-insensitive
+ substring of the preferred style name.
+*/
+void StyleSettings::SetPreferredSymbolsStyleName( const ::rtl::OUString &rName )
+{
+ if ( rName.getLength() > 0 )
+ {
+ ::rtl::OUString rNameLowCase( rName.toAsciiLowerCase() );
+
+ for( sal_uInt32 n = 0; n <= STYLE_SYMBOLS_THEMES_MAX; n++ )
+ if ( rNameLowCase.indexOf( ImplSymbolsStyleToName( n ) ) != -1 )
+ SetPreferredSymbolsStyle( n );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG StyleSettings::GetCurrentSymbolsStyle() const
+{
+ // style selected in Tools -> Options... -> OpenOffice.org -> View
+ ULONG nStyle = GetSymbolsStyle();
+
+ if ( nStyle == STYLE_SYMBOLS_AUTO || ( !CheckSymbolStyle (nStyle) ) )
+ {
+ // the preferred style can be read from the desktop setting by the desktop native widgets modules
+ ULONG nPreferredStyle = GetPreferredSymbolsStyle();
+
+ if ( nPreferredStyle == STYLE_SYMBOLS_AUTO || ( !CheckSymbolStyle (nPreferredStyle) ) )
+ {
+
+ // use a hardcoded desktop-specific fallback if no preferred style has been detected
+ static bool sbFallbackDesktopChecked = false;
+ static ULONG snFallbackDesktopStyle = STYLE_SYMBOLS_DEFAULT;
+
+ if ( !sbFallbackDesktopChecked )
+ {
+ snFallbackDesktopStyle = GetAutoSymbolsStyle();
+ sbFallbackDesktopChecked = true;
+ }
+
+ nPreferredStyle = snFallbackDesktopStyle;
+ }
+
+ if (GetHighContrastMode() && CheckSymbolStyle (STYLE_SYMBOLS_HICONTRAST) )
+ nStyle = STYLE_SYMBOLS_HICONTRAST;
+ else
+ nStyle = nPreferredStyle;
+ }
+
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG StyleSettings::GetAutoSymbolsStyle() const
+{
+ const ::rtl::OUString& rDesktopEnvironment = Application::GetDesktopEnvironment();
+ ULONG nRet = STYLE_SYMBOLS_DEFAULT;
+ bool bCont = true;
+
+ try
+ {
+ const ::com::sun::star::uno::Any aAny( ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::OPENSOURCECONTEXT ) );
+ sal_Int32 nValue( 0 );
+
+ aAny >>= nValue;
+
+ if( 0 == nValue )
+ bCont = false;
+ }
+ catch ( ::com::sun::star::uno::Exception& )
+ {
+ }
+
+ if( bCont )
+ {
+ if( rDesktopEnvironment.equalsIgnoreAsciiCaseAscii( "gnome" ) ||
+ rDesktopEnvironment.equalsIgnoreAsciiCaseAscii( "windows" ) )
+ nRet = STYLE_SYMBOLS_TANGO;
+ else if( rDesktopEnvironment.equalsIgnoreAsciiCaseAscii( "kde" ) )
+ nRet = STYLE_SYMBOLS_CRYSTAL;
+ else if( rDesktopEnvironment.equalsIgnoreAsciiCaseAscii( "kde4" ) )
+ nRet = STYLE_SYMBOLS_OXYGEN;
+ }
+
+ // falback to any existing style
+ if ( ! CheckSymbolStyle (nRet) )
+ {
+ for ( ULONG n = 0 ; n <= STYLE_SYMBOLS_THEMES_MAX ; n++ )
+ {
+ ULONG nStyleToCheck = n;
+
+ // auto is not a real theme => can't be fallback
+ if ( nStyleToCheck == STYLE_SYMBOLS_AUTO )
+ continue;
+
+ // will check hicontrast in the end
+ if ( nStyleToCheck == STYLE_SYMBOLS_HICONTRAST )
+ continue;
+ if ( nStyleToCheck == STYLE_SYMBOLS_THEMES_MAX )
+ nStyleToCheck = STYLE_SYMBOLS_HICONTRAST;
+
+ if ( CheckSymbolStyle ( nStyleToCheck ) )
+ {
+ nRet = nStyleToCheck;
+ n = STYLE_SYMBOLS_THEMES_MAX;
+ }
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+bool StyleSettings::CheckSymbolStyle( ULONG nStyle ) const
+{
+ static ImplImageTreeSingletonRef aImageTree;
+ return aImageTree->checkStyle( ImplSymbolsStyleToName( nStyle ) );
+}
+
+// -----------------------------------------------------------------------
+
+void StyleSettings::SetStandardStyles()
+{
+ CopyData();
+ mpData->SetStandardStyles();
+}
+
+// -----------------------------------------------------------------------
+
+void StyleSettings::SetStandardWinStyles()
+{
+ return; // no more style changes since NWF
+}
+
+// -----------------------------------------------------------------------
+
+void StyleSettings::SetStandardOS2Styles()
+{
+ return; // no more style changes since NWF
+}
+
+// -----------------------------------------------------------------------
+
+void StyleSettings::SetStandardMacStyles()
+{
+ return; // no more style changes since NWF
+}
+
+// -----------------------------------------------------------------------
+
+void StyleSettings::SetStandardUnixStyles()
+{
+ return; // no more style changes since NWF
+}
+
+// -----------------------------------------------------------------------
+
+Color StyleSettings::GetFaceGradientColor() const
+{
+ // compute a brighter face color that can be used in gradients
+ // for a convex look (eg toolbars)
+
+ USHORT h, s, b;
+ GetFaceColor().RGBtoHSB( h, s, b );
+ if( s > 1) s=1;
+ if( b < 98) b=98;
+ return Color( Color::HSBtoRGB( h, s, b ) );
+}
+
+// -----------------------------------------------------------------------
+
+Color StyleSettings::GetSeparatorColor() const
+{
+ // compute a brighter shadow color for separators (used in toolbars or between menubar and toolbars on Windows XP)
+ USHORT h, s, b;
+ GetShadowColor().RGBtoHSB( h, s, b );
+ b += b/4;
+ s -= s/4;
+ return Color( Color::HSBtoRGB( h, s, b ) );
+}
+
+// -----------------------------------------------------------------------
+
+const StyleSettings& StyleSettings::operator =( const StyleSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "StyleSettings: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void StyleSettings::CopyData()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplStyleData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline BOOL ImplIsBackOrWhite( const Color& rColor )
+{
+ UINT8 nLuminance = rColor.GetLuminance();
+ return ( nLuminance < 8 ) || ( nLuminance > 250 );
+}
+
+BOOL StyleSettings::IsHighContrastBlackAndWhite() const
+{
+ BOOL bBWOnly = TRUE;
+
+ // Only use B&W if fully B&W, like on GNOME.
+ // Some colors like CheckedColor and HighlightColor are not B&W in Windows Standard HC Black,
+ // and we don't want to be B&W then, so check these color first, very probably not B&W.
+
+ // Unfortunately, GNOME uses a very very dark color (0x000033) instead of BLACK (0x000000)
+
+ if ( !ImplIsBackOrWhite( GetFaceColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetHighlightTextColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetWindowColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetWindowTextColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetButtonTextColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetButtonTextColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetGroupTextColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetLabelTextColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetDialogColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetFieldColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetMenuColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetMenuBarColor() ) )
+ bBWOnly = FALSE;
+ else if ( !ImplIsBackOrWhite( GetMenuHighlightColor() ) )
+ bBWOnly = FALSE;
+
+ return bBWOnly;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL StyleSettings::operator ==( const StyleSettings& rSet ) const
+{
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->mnOptions == rSet.mpData->mnOptions) &&
+ (mpData->mnAutoMnemonic == rSet.mpData->mnAutoMnemonic) &&
+ (mpData->mnLogoDisplayTime == rSet.mpData->mnLogoDisplayTime) &&
+ (mpData->mnDragFullOptions == rSet.mpData->mnDragFullOptions) &&
+ (mpData->mnAnimationOptions == rSet.mpData->mnAnimationOptions) &&
+ (mpData->mnSelectionOptions == rSet.mpData->mnSelectionOptions) &&
+ (mpData->mnDisplayOptions == rSet.mpData->mnDisplayOptions) &&
+ (mpData->mnCursorSize == rSet.mpData->mnCursorSize) &&
+ (mpData->mnCursorBlinkTime == rSet.mpData->mnCursorBlinkTime) &&
+ (mpData->mnBorderSize == rSet.mpData->mnBorderSize) &&
+ (mpData->mnTitleHeight == rSet.mpData->mnTitleHeight) &&
+ (mpData->mnFloatTitleHeight == rSet.mpData->mnFloatTitleHeight) &&
+ (mpData->mnTearOffTitleHeight == rSet.mpData->mnTearOffTitleHeight) &&
+ (mpData->mnMenuBarHeight == rSet.mpData->mnMenuBarHeight) &&
+ (mpData->mnScrollBarSize == rSet.mpData->mnScrollBarSize) &&
+ (mpData->mnMinThumbSize == rSet.mpData->mnMinThumbSize) &&
+ (mpData->mnSplitSize == rSet.mpData->mnSplitSize) &&
+ (mpData->mnSpinSize == rSet.mpData->mnSpinSize) &&
+ (mpData->mnIconHorzSpace == rSet.mpData->mnIconHorzSpace) &&
+ (mpData->mnIconVertSpace == rSet.mpData->mnIconVertSpace) &&
+ (mpData->mnAntialiasedMin == rSet.mpData->mnAntialiasedMin) &&
+ (mpData->mnScreenZoom == rSet.mpData->mnScreenZoom) &&
+ (mpData->mnScreenFontZoom == rSet.mpData->mnScreenFontZoom) &&
+ (mpData->mnRadioButtonStyle == rSet.mpData->mnRadioButtonStyle) &&
+ (mpData->mnCheckBoxStyle == rSet.mpData->mnCheckBoxStyle) &&
+ (mpData->mnPushButtonStyle == rSet.mpData->mnPushButtonStyle) &&
+ (mpData->mnTabControlStyle == rSet.mpData->mnTabControlStyle) &&
+ (mpData->mnHighContrast == rSet.mpData->mnHighContrast) &&
+ (mpData->mnUseSystemUIFonts == rSet.mpData->mnUseSystemUIFonts) &&
+ (mpData->mnUseFlatBorders == rSet.mpData->mnUseFlatBorders) &&
+ (mpData->mnUseFlatMenues == rSet.mpData->mnUseFlatMenues) &&
+ (mpData->maFaceColor == rSet.mpData->maFaceColor) &&
+ (mpData->maCheckedColor == rSet.mpData->maCheckedColor) &&
+ (mpData->maLightColor == rSet.mpData->maLightColor) &&
+ (mpData->maLightBorderColor == rSet.mpData->maLightBorderColor) &&
+ (mpData->maShadowColor == rSet.mpData->maShadowColor) &&
+ (mpData->maDarkShadowColor == rSet.mpData->maDarkShadowColor) &&
+ (mpData->maButtonTextColor == rSet.mpData->maButtonTextColor) &&
+ (mpData->maRadioCheckTextColor == rSet.mpData->maRadioCheckTextColor) &&
+ (mpData->maGroupTextColor == rSet.mpData->maGroupTextColor) &&
+ (mpData->maLabelTextColor == rSet.mpData->maLabelTextColor) &&
+ (mpData->maInfoTextColor == rSet.mpData->maInfoTextColor) &&
+ (mpData->maWindowColor == rSet.mpData->maWindowColor) &&
+ (mpData->maWindowTextColor == rSet.mpData->maWindowTextColor) &&
+ (mpData->maDialogColor == rSet.mpData->maDialogColor) &&
+ (mpData->maDialogTextColor == rSet.mpData->maDialogTextColor) &&
+ (mpData->maWorkspaceColor == rSet.mpData->maWorkspaceColor) &&
+ (mpData->maMonoColor == rSet.mpData->maMonoColor) &&
+ (mpData->maFieldColor == rSet.mpData->maFieldColor) &&
+ (mpData->maFieldTextColor == rSet.mpData->maFieldTextColor) &&
+ (mpData->maActiveColor == rSet.mpData->maActiveColor) &&
+ (mpData->maActiveColor2 == rSet.mpData->maActiveColor2) &&
+ (mpData->maActiveTextColor == rSet.mpData->maActiveTextColor) &&
+ (mpData->maActiveBorderColor == rSet.mpData->maActiveBorderColor) &&
+ (mpData->maDeactiveColor == rSet.mpData->maDeactiveColor) &&
+ (mpData->maDeactiveColor2 == rSet.mpData->maDeactiveColor2) &&
+ (mpData->maDeactiveTextColor == rSet.mpData->maDeactiveTextColor) &&
+ (mpData->maDeactiveBorderColor == rSet.mpData->maDeactiveBorderColor) &&
+ (mpData->maMenuColor == rSet.mpData->maMenuColor) &&
+ (mpData->maMenuBarColor == rSet.mpData->maMenuBarColor) &&
+ (mpData->maMenuBorderColor == rSet.mpData->maMenuBorderColor) &&
+ (mpData->maMenuTextColor == rSet.mpData->maMenuTextColor) &&
+ (mpData->maMenuBarTextColor == rSet.mpData->maMenuBarTextColor) &&
+ (mpData->maMenuHighlightColor == rSet.mpData->maMenuHighlightColor) &&
+ (mpData->maMenuHighlightTextColor == rSet.mpData->maMenuHighlightTextColor) &&
+ (mpData->maHighlightColor == rSet.mpData->maHighlightColor) &&
+ (mpData->maHighlightTextColor == rSet.mpData->maHighlightTextColor) &&
+ (mpData->maActiveTabColor == rSet.mpData->maActiveTabColor) &&
+ (mpData->maInactiveTabColor == rSet.mpData->maInactiveTabColor) &&
+ (mpData->maDisableColor == rSet.mpData->maDisableColor) &&
+ (mpData->maHelpColor == rSet.mpData->maHelpColor) &&
+ (mpData->maHelpTextColor == rSet.mpData->maHelpTextColor) &&
+ (mpData->maLinkColor == rSet.mpData->maLinkColor) &&
+ (mpData->maVisitedLinkColor == rSet.mpData->maVisitedLinkColor) &&
+ (mpData->maHighlightLinkColor == rSet.mpData->maHighlightLinkColor) &&
+ (mpData->maAppFont == rSet.mpData->maAppFont) &&
+ (mpData->maHelpFont == rSet.mpData->maHelpFont) &&
+ (mpData->maTitleFont == rSet.mpData->maTitleFont) &&
+ (mpData->maFloatTitleFont == rSet.mpData->maFloatTitleFont) &&
+ (mpData->maMenuFont == rSet.mpData->maMenuFont) &&
+ (mpData->maToolFont == rSet.mpData->maToolFont) &&
+ (mpData->maGroupFont == rSet.mpData->maGroupFont) &&
+ (mpData->maLabelFont == rSet.mpData->maLabelFont) &&
+ (mpData->maInfoFont == rSet.mpData->maInfoFont) &&
+ (mpData->maRadioCheckFont == rSet.mpData->maRadioCheckFont) &&
+ (mpData->maPushButtonFont == rSet.mpData->maPushButtonFont) &&
+ (mpData->maFieldFont == rSet.mpData->maFieldFont) &&
+ (mpData->maIconFont == rSet.mpData->maIconFont) &&
+ (mpData->mnUseImagesInMenus == rSet.mpData->mnUseImagesInMenus) &&
+ (mpData->mnSkipDisabledInMenus == rSet.mpData->mnSkipDisabledInMenus) &&
+ (mpData->maFontColor == rSet.mpData->maFontColor ))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// =======================================================================
+
+ImplMiscData::ImplMiscData()
+{
+ mnRefCount = 1;
+ mnEnableATT = sal::static_int_cast<USHORT>(~0U);
+ mnDisablePrinting = sal::static_int_cast<USHORT>(~0U);
+ static const char* pEnv = getenv("SAL_DECIMALSEP_ENABLED" ); // set default without UI
+ mbEnableLocalizedDecimalSep = (pEnv != NULL) ? TRUE : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplMiscData::ImplMiscData( const ImplMiscData& rData )
+{
+ mnRefCount = 1;
+ mnEnableATT = rData.mnEnableATT;
+ mnDisablePrinting = rData.mnDisablePrinting;
+ mbEnableLocalizedDecimalSep = rData.mbEnableLocalizedDecimalSep;
+}
+
+// -----------------------------------------------------------------------
+
+MiscSettings::MiscSettings()
+{
+ mpData = new ImplMiscData();
+}
+
+// -----------------------------------------------------------------------
+
+MiscSettings::MiscSettings( const MiscSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "MiscSettings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+MiscSettings::~MiscSettings()
+{
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+const MiscSettings& MiscSettings::operator =( const MiscSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "MiscSettings: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void MiscSettings::CopyData()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplMiscData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MiscSettings::operator ==( const MiscSettings& rSet ) const
+{
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->mnEnableATT == rSet.mpData->mnEnableATT ) &&
+ (mpData->mnDisablePrinting == rSet.mpData->mnDisablePrinting ) &&
+ (mpData->mbEnableLocalizedDecimalSep == rSet.mpData->mbEnableLocalizedDecimalSep ) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MiscSettings::GetDisablePrinting() const
+{
+ if( mpData->mnDisablePrinting == (USHORT)~0 )
+ {
+ rtl::OUString aEnable =
+ vcl::SettingsConfigItem::get()->
+ getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DesktopManagement" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisablePrinting" ) ) );
+ mpData->mnDisablePrinting = aEnable.equalsIgnoreAsciiCaseAscii( "true" ) ? 1 : 0;
+ }
+
+ return (BOOL)mpData->mnDisablePrinting;
+}
+// -----------------------------------------------------------------------
+
+BOOL MiscSettings::GetEnableATToolSupport() const
+{
+
+#ifdef WNT
+ if( mpData->mnEnableATT == (USHORT)~0 )
+ {
+ // Check in the Windows registry if an AT tool wants Accessibility support to
+ // be activated ..
+ HKEY hkey;
+
+ if( ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER,
+ "Software\\OpenOffice.org\\Accessibility\\AtToolSupport",
+ &hkey) )
+ {
+ DWORD dwType;
+ WIN_BYTE Data[6]; // possible values: "true", "false", "1", "0", DWORD
+ DWORD cbData = sizeof(Data);
+
+ if( ERROR_SUCCESS == RegQueryValueEx(hkey, "SupportAssistiveTechnology",
+ NULL, &dwType, Data, &cbData) )
+ {
+ switch (dwType)
+ {
+ case REG_SZ:
+ mpData->mnEnableATT = ((0 == stricmp((const char *) Data, "1")) || (0 == stricmp((const char *) Data, "true")));
+ break;
+ case REG_DWORD:
+ mpData->mnEnableATT = (USHORT) (((DWORD *) Data)[0]);
+ break;
+ default:
+ // Unsupported registry type
+ break;
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+ }
+#endif
+
+ if( mpData->mnEnableATT == (USHORT)~0 )
+ {
+ static const char* pEnv = getenv("SAL_ACCESSIBILITY_ENABLED" );
+ if( !pEnv || !*pEnv )
+ {
+ rtl::OUString aEnable =
+ vcl::SettingsConfigItem::get()->
+ getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Accessibility" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EnableATToolSupport" ) ) );
+ mpData->mnEnableATT = aEnable.equalsIgnoreAsciiCaseAscii( "true" ) ? 1 : 0;
+ }
+ else
+ {
+ mpData->mnEnableATT = 1;
+ }
+ }
+
+ return (BOOL)mpData->mnEnableATT;
+}
+
+// -----------------------------------------------------------------------
+
+void MiscSettings::SetDisablePrinting( BOOL bEnable )
+{
+ if ( bEnable != mpData->mnDisablePrinting )
+ {
+ vcl::SettingsConfigItem::get()->
+ setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DesktopManagement" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisablePrinting" ) ),
+ rtl::OUString::createFromAscii( bEnable ? "true" : "false" ) );
+ mpData->mnDisablePrinting = bEnable ? 1 : 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void MiscSettings::SetEnableATToolSupport( BOOL bEnable )
+{
+ if ( bEnable != mpData->mnEnableATT )
+ {
+ BOOL bDummy;
+ if( bEnable && !ImplInitAccessBridge(false, bDummy) )
+ return;
+
+#ifdef WNT
+ HKEY hkey;
+
+ // If the accessibility key in the Windows registry exists, change it synchronously
+ if( ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER,
+ "Software\\OpenOffice.org\\Accessibility\\AtToolSupport",
+ &hkey) )
+ {
+ DWORD dwType;
+ WIN_BYTE Data[6]; // possible values: "true", "false", 1, 0
+ DWORD cbData = sizeof(Data);
+
+ if( ERROR_SUCCESS == RegQueryValueEx(hkey, "SupportAssistiveTechnology",
+ NULL, &dwType, Data, &cbData) )
+ {
+ switch (dwType)
+ {
+ case REG_SZ:
+ RegSetValueEx(hkey, "SupportAssistiveTechnology",
+ NULL, dwType,
+ bEnable ? (WIN_BYTE *) "true" : (WIN_BYTE *) "false",
+ bEnable ? sizeof("true") : sizeof("false"));
+ break;
+ case REG_DWORD:
+ ((DWORD *) Data)[0] = bEnable ? 1 : 0;
+ RegSetValueEx(hkey, "SupportAssistiveTechnology",
+ NULL, dwType, Data, sizeof(DWORD));
+ break;
+ default:
+ // Unsupported registry type
+ break;
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+
+#endif
+ vcl::SettingsConfigItem::get()->
+ setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Accessibility" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EnableATToolSupport" ) ),
+ rtl::OUString::createFromAscii( bEnable ? "true" : "false" ) );
+ mpData->mnEnableATT = bEnable ? 1 : 0;
+ }
+}
+
+void MiscSettings::SetEnableLocalizedDecimalSep( BOOL bEnable )
+{
+ CopyData();
+ mpData->mbEnableLocalizedDecimalSep = bEnable;
+}
+
+BOOL MiscSettings::GetEnableLocalizedDecimalSep() const
+{
+ return mpData->mbEnableLocalizedDecimalSep;
+}
+
+// =======================================================================
+
+ImplNotificationData::ImplNotificationData()
+{
+ mnRefCount = 1;
+ mnOptions = 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplNotificationData::ImplNotificationData( const ImplNotificationData& rData )
+{
+ mnRefCount = 1;
+ mnOptions = rData.mnOptions;
+}
+
+// -----------------------------------------------------------------------
+
+NotificationSettings::NotificationSettings()
+{
+ mpData = new ImplNotificationData();
+}
+
+// -----------------------------------------------------------------------
+
+NotificationSettings::NotificationSettings( const NotificationSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "NotificationSettings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+NotificationSettings::~NotificationSettings()
+{
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+const NotificationSettings& NotificationSettings::operator =( const NotificationSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "NotificationSettings: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void NotificationSettings::CopyData()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplNotificationData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL NotificationSettings::operator ==( const NotificationSettings& rSet ) const
+{
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->mnOptions == rSet.mpData->mnOptions) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// =======================================================================
+
+ImplHelpData::ImplHelpData()
+{
+ mnRefCount = 1;
+ mnOptions = 0;
+ mnTipDelay = 500;
+ mnTipTimeout = 3000;
+ mnBalloonDelay = 1500;
+}
+
+// -----------------------------------------------------------------------
+
+ImplHelpData::ImplHelpData( const ImplHelpData& rData )
+{
+ mnRefCount = 1;
+ mnOptions = rData.mnOptions;
+ mnTipDelay = rData.mnTipDelay;
+ mnTipTimeout = rData.mnTipTimeout;
+ mnBalloonDelay = rData.mnBalloonDelay;
+}
+
+// -----------------------------------------------------------------------
+
+HelpSettings::HelpSettings()
+{
+ mpData = new ImplHelpData();
+}
+
+// -----------------------------------------------------------------------
+
+HelpSettings::HelpSettings( const HelpSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "HelpSettings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+HelpSettings::~HelpSettings()
+{
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+const HelpSettings& HelpSettings::operator =( const HelpSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "HelpSettings: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void HelpSettings::CopyData()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplHelpData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL HelpSettings::operator ==( const HelpSettings& rSet ) const
+{
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->mnOptions == rSet.mpData->mnOptions ) &&
+ (mpData->mnTipDelay == rSet.mpData->mnTipDelay ) &&
+ (mpData->mnTipTimeout == rSet.mpData->mnTipTimeout ) &&
+ (mpData->mnBalloonDelay == rSet.mpData->mnBalloonDelay ) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// =======================================================================
+
+ImplAllSettingsData::ImplAllSettingsData()
+{
+ mnRefCount = 1;
+ mnSystemUpdate = SETTINGS_ALLSETTINGS;
+ mnWindowUpdate = SETTINGS_ALLSETTINGS;
+ meLanguage = LANGUAGE_SYSTEM;
+ meUILanguage = LANGUAGE_SYSTEM;
+ mpLocaleDataWrapper = NULL;
+ mpUILocaleDataWrapper = NULL;
+ mpCollatorWrapper = NULL;
+ mpUICollatorWrapper = NULL;
+ mpI18nHelper = NULL;
+ mpUII18nHelper = NULL;
+ maMiscSettings.SetEnableLocalizedDecimalSep( maSysLocale.GetOptions().IsDecimalSeparatorAsLocale() );
+}
+
+// -----------------------------------------------------------------------
+
+ImplAllSettingsData::ImplAllSettingsData( const ImplAllSettingsData& rData ) :
+ maMouseSettings( rData.maMouseSettings ),
+ maKeyboardSettings( rData.maKeyboardSettings ),
+ maStyleSettings( rData.maStyleSettings ),
+ maMiscSettings( rData.maMiscSettings ),
+ maNotificationSettings( rData.maNotificationSettings ),
+ maHelpSettings( rData.maHelpSettings ),
+ maLocale( rData.maLocale )
+{
+ mnRefCount = 1;
+ mnSystemUpdate = rData.mnSystemUpdate;
+ mnWindowUpdate = rData.mnWindowUpdate;
+ meLanguage = rData.meLanguage;
+ // Pointer couldn't shared and objects haven't a copy ctor
+ // So we create the cache objects new, if the GetFunction is
+ // called
+ mpLocaleDataWrapper = NULL;
+ mpUILocaleDataWrapper = NULL;
+ mpCollatorWrapper = NULL;
+ mpUICollatorWrapper = NULL;
+ mpI18nHelper = NULL;
+ mpUII18nHelper = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplAllSettingsData::~ImplAllSettingsData()
+{
+ if ( mpLocaleDataWrapper )
+ delete mpLocaleDataWrapper;
+ if ( mpUILocaleDataWrapper )
+ delete mpUILocaleDataWrapper;
+ if ( mpCollatorWrapper )
+ delete mpCollatorWrapper;
+ if ( mpUICollatorWrapper )
+ delete mpUICollatorWrapper;
+ if ( mpI18nHelper )
+ delete mpI18nHelper;
+ if ( mpUII18nHelper )
+ delete mpUII18nHelper;
+}
+
+// -----------------------------------------------------------------------
+
+AllSettings::AllSettings()
+{
+ DBG_CTOR( AllSettings, NULL );
+
+ mpData = new ImplAllSettingsData();
+}
+
+// -----------------------------------------------------------------------
+
+AllSettings::AllSettings( const AllSettings& rSet )
+{
+ DBG_CTOR( AllSettings, NULL );
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "Settings: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpData = rSet.mpData;
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+AllSettings::~AllSettings()
+{
+ DBG_DTOR( AllSettings, NULL );
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+const AllSettings& AllSettings::operator =( const AllSettings& rSet )
+{
+ DBG_ASSERT( rSet.mpData->mnRefCount < 0xFFFFFFFE, "AllSettings: RefCount overflow" );
+ DBG_CHKTHIS( AllSettings, NULL );
+ DBG_CHKOBJ( &rSet, AllSettings, NULL );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rSet.mpData->mnRefCount++;
+
+ // Daten loeschen, wenn letzte Referenz
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+
+ mpData = rSet.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+void AllSettings::CopyData()
+{
+ DBG_CHKTHIS( AllSettings, NULL );
+
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplAllSettingsData( *mpData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AllSettings::Update( ULONG nFlags, const AllSettings& rSet )
+{
+ DBG_CHKTHIS( AllSettings, NULL );
+ DBG_CHKOBJ( &rSet, AllSettings, NULL );
+
+ ULONG nChangeFlags = 0;
+
+ if ( nFlags & SETTINGS_MACHINE )
+ {
+ if ( mpData->maMachineSettings != rSet.mpData->maMachineSettings )
+ {
+ CopyData();
+ mpData->maMachineSettings = rSet.mpData->maMachineSettings;
+ nChangeFlags |= SETTINGS_MACHINE;
+ }
+ }
+
+ if ( nFlags & SETTINGS_MOUSE )
+ {
+ if ( mpData->maMouseSettings != rSet.mpData->maMouseSettings )
+ {
+ CopyData();
+ mpData->maMouseSettings = rSet.mpData->maMouseSettings;
+ nChangeFlags |= SETTINGS_MOUSE;
+ }
+ }
+
+ if ( nFlags & SETTINGS_KEYBOARD )
+ {
+ if ( mpData->maKeyboardSettings != rSet.mpData->maKeyboardSettings )
+ {
+ CopyData();
+ mpData->maKeyboardSettings = rSet.mpData->maKeyboardSettings;
+ nChangeFlags |= SETTINGS_KEYBOARD;
+ }
+ }
+
+ if ( nFlags & SETTINGS_STYLE )
+ {
+ if ( mpData->maStyleSettings != rSet.mpData->maStyleSettings )
+ {
+ CopyData();
+ mpData->maStyleSettings = rSet.mpData->maStyleSettings;
+ nChangeFlags |= SETTINGS_STYLE;
+ }
+ }
+
+ if ( nFlags & SETTINGS_MISC )
+ {
+ if ( mpData->maMiscSettings != rSet.mpData->maMiscSettings )
+ {
+ CopyData();
+ mpData->maMiscSettings = rSet.mpData->maMiscSettings;
+ nChangeFlags |= SETTINGS_MISC;
+ }
+ }
+
+ if ( nFlags & SETTINGS_NOTIFICATION )
+ {
+ if ( mpData->maNotificationSettings != rSet.mpData->maNotificationSettings )
+ {
+ CopyData();
+ mpData->maNotificationSettings = rSet.mpData->maNotificationSettings;
+ nChangeFlags |= SETTINGS_NOTIFICATION;
+ }
+ }
+
+ if ( nFlags & SETTINGS_HELP )
+ {
+ if ( mpData->maHelpSettings != rSet.mpData->maHelpSettings )
+ {
+ CopyData();
+ mpData->maHelpSettings = rSet.mpData->maHelpSettings;
+ nChangeFlags |= SETTINGS_HELP;
+ }
+ }
+
+ if ( nFlags & SETTINGS_INTERNATIONAL )
+ {
+ // Nothing, class International is gone.
+ DBG_ERRORFILE("AllSettings::Update: who calls with SETTINGS_INTERNATIONAL and why? You're flogging a dead horse.");
+ }
+
+ if ( nFlags & SETTINGS_LOCALE )
+ {
+ if ( mpData->meLanguage || rSet.mpData->meLanguage )
+ {
+ SetLanguage( rSet.mpData->meLanguage );
+ nChangeFlags |= SETTINGS_LOCALE;
+ }
+ }
+
+ if ( nFlags & SETTINGS_UILOCALE )
+ {
+ // UILocale can't be changed
+ }
+
+ return nChangeFlags;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AllSettings::GetChangeFlags( const AllSettings& rSet ) const
+{
+ DBG_CHKTHIS( AllSettings, NULL );
+ DBG_CHKOBJ( &rSet, AllSettings, NULL );
+
+ ULONG nChangeFlags = 0;
+
+ if ( mpData->maMachineSettings != rSet.mpData->maMachineSettings )
+ nChangeFlags |= SETTINGS_MACHINE;
+
+ if ( mpData->maMouseSettings != rSet.mpData->maMouseSettings )
+ nChangeFlags |= SETTINGS_MOUSE;
+
+ if ( mpData->maKeyboardSettings != rSet.mpData->maKeyboardSettings )
+ nChangeFlags |= SETTINGS_KEYBOARD;
+
+ if ( mpData->maStyleSettings != rSet.mpData->maStyleSettings )
+ nChangeFlags |= SETTINGS_STYLE;
+
+ if ( mpData->maMiscSettings != rSet.mpData->maMiscSettings )
+ nChangeFlags |= SETTINGS_MISC;
+
+ if ( mpData->maNotificationSettings != rSet.mpData->maNotificationSettings )
+ nChangeFlags |= SETTINGS_NOTIFICATION;
+
+ if ( mpData->maHelpSettings != rSet.mpData->maHelpSettings )
+ nChangeFlags |= SETTINGS_HELP;
+
+ if ( mpData->meLanguage || rSet.mpData->meLanguage )
+ nChangeFlags |= SETTINGS_LOCALE;
+
+ return nChangeFlags;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AllSettings::operator ==( const AllSettings& rSet ) const
+{
+ DBG_CHKTHIS( AllSettings, NULL );
+ DBG_CHKOBJ( &rSet, AllSettings, NULL );
+
+ if ( mpData == rSet.mpData )
+ return TRUE;
+
+ if ( (mpData->maMachineSettings == rSet.mpData->maMachineSettings) &&
+ (mpData->maMouseSettings == rSet.mpData->maMouseSettings) &&
+ (mpData->maKeyboardSettings == rSet.mpData->maKeyboardSettings) &&
+ (mpData->maStyleSettings == rSet.mpData->maStyleSettings) &&
+ (mpData->maMiscSettings == rSet.mpData->maMiscSettings) &&
+ (mpData->maNotificationSettings == rSet.mpData->maNotificationSettings) &&
+ (mpData->maHelpSettings == rSet.mpData->maHelpSettings) &&
+ (mpData->mnSystemUpdate == rSet.mpData->mnSystemUpdate) &&
+ (mpData->maLocale == rSet.mpData->maLocale) &&
+ (mpData->mnWindowUpdate == rSet.mpData->mnWindowUpdate) )
+ {
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void AllSettings::SetLocale( const ::com::sun::star::lang::Locale& rLocale )
+{
+ CopyData();
+
+ mpData->maLocale = rLocale;
+
+ if ( !rLocale.Language.getLength() )
+ mpData->meLanguage = LANGUAGE_SYSTEM;
+ else
+ mpData->meLanguage = MsLangId::convertLocaleToLanguage( rLocale );
+ if ( mpData->mpLocaleDataWrapper )
+ {
+ delete mpData->mpLocaleDataWrapper;
+ mpData->mpLocaleDataWrapper = NULL;
+ }
+ if ( mpData->mpI18nHelper )
+ {
+ delete mpData->mpI18nHelper;
+ mpData->mpI18nHelper = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AllSettings::SetUILocale( const ::com::sun::star::lang::Locale& )
+{
+ // there is only one UILocale per process
+}
+
+// -----------------------------------------------------------------------
+
+void AllSettings::SetLanguage( LanguageType eLang )
+{
+ if ( eLang != mpData->meLanguage )
+ {
+ CopyData();
+
+ mpData->meLanguage = eLang;
+ MsLangId::convertLanguageToLocale( GetLanguage(), ((AllSettings*)this)->mpData->maLocale );
+ if ( mpData->mpLocaleDataWrapper )
+ {
+ delete mpData->mpLocaleDataWrapper;
+ mpData->mpLocaleDataWrapper = NULL;
+ }
+ if ( mpData->mpI18nHelper )
+ {
+ delete mpData->mpI18nHelper;
+ mpData->mpI18nHelper = NULL;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AllSettings::SetUILanguage( LanguageType )
+{
+ // there is only one UILanguage per process
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AllSettings::GetLayoutRTL() const
+{
+ static const char* pEnv = getenv("SAL_RTL_ENABLED" );
+ static int nUIMirroring = -1; // -1: undef, 0: auto, 1: on 2: off
+
+ // environment always overrides
+ if( pEnv )
+ return true;
+
+ BOOL bRTL = FALSE;
+
+ if( nUIMirroring == -1 )
+ {
+ nUIMirroring = 0; // ask configuration only once
+ utl::OConfigurationNode aNode = utl::OConfigurationTreeRoot::tryCreateWithServiceFactory(
+ vcl::unohelper::GetMultiServiceFactory(),
+ OUString::createFromAscii( "org.openoffice.Office.Common/I18N/CTL" ) ); // note: case sensisitive !
+ if ( aNode.isValid() )
+ {
+ BOOL bTmp = BOOL();
+ ::com::sun::star::uno::Any aValue = aNode.getNodeValue( OUString::createFromAscii( "UIMirroring" ) );
+ if( aValue >>= bTmp )
+ {
+ // found true or false; if it was nil, nothing is changed
+ nUIMirroring = bTmp ? 1 : 2;
+ }
+ }
+ }
+
+ if( nUIMirroring == 0 ) // no config found (eg, setup) or default (nil) was set: check language
+ {
+ LanguageType aLang = LANGUAGE_DONTKNOW;
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maAppData.mpSettings )
+ aLang = pSVData->maAppData.mpSettings->GetUILanguage();
+ bRTL = MsLangId::isRightToLeft( aLang );
+ }
+ else
+ bRTL = (nUIMirroring == 1);
+
+ return bRTL;
+}
+
+// -----------------------------------------------------------------------
+
+const ::com::sun::star::lang::Locale& AllSettings::GetLocale() const
+{
+ if ( !mpData->maLocale.Language.getLength() )
+ mpData->maLocale = mpData->maSysLocale.GetLocale();
+
+ return mpData->maLocale;
+}
+
+// -----------------------------------------------------------------------
+
+const ::com::sun::star::lang::Locale& AllSettings::GetUILocale() const
+{
+ // the UILocale is never changed
+ if ( !mpData->maUILocale.Language.getLength() )
+ mpData->maUILocale = mpData->maSysLocale.GetUILocale();
+
+ return mpData->maUILocale;
+}
+
+// -----------------------------------------------------------------------
+
+LanguageType AllSettings::GetLanguage() const
+{
+ // meLanguage == LANGUAGE_SYSTEM means: use settings from SvtSysLocale
+ if ( mpData->meLanguage == LANGUAGE_SYSTEM )
+ return mpData->maSysLocale.GetLanguage();
+
+ return mpData->meLanguage;
+}
+
+// -----------------------------------------------------------------------
+
+LanguageType AllSettings::GetUILanguage() const
+{
+ // the UILanguage is never changed
+ return mpData->maSysLocale.GetUILanguage();
+}
+
+// -----------------------------------------------------------------------
+
+const LocaleDataWrapper& AllSettings::GetLocaleDataWrapper() const
+{
+ if ( !mpData->mpLocaleDataWrapper )
+ ((AllSettings*)this)->mpData->mpLocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetLocale() );
+ return *mpData->mpLocaleDataWrapper;
+}
+
+// -----------------------------------------------------------------------
+
+const LocaleDataWrapper& AllSettings::GetUILocaleDataWrapper() const
+{
+ if ( !mpData->mpUILocaleDataWrapper )
+ ((AllSettings*)this)->mpData->mpUILocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetUILocale() );
+ return *mpData->mpUILocaleDataWrapper;
+}
+
+// -----------------------------------------------------------------------
+
+const vcl::I18nHelper& AllSettings::GetLocaleI18nHelper() const
+{
+ if ( !mpData->mpI18nHelper ) {
+ ::com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory> aFactory(vcl::unohelper::GetMultiServiceFactory());
+ ((AllSettings*)this)->mpData->mpI18nHelper = new vcl::I18nHelper( aFactory, GetLocale() );
+ }
+ return *mpData->mpI18nHelper;
+}
+
+// -----------------------------------------------------------------------
+
+const vcl::I18nHelper& AllSettings::GetUILocaleI18nHelper() const
+{
+ if ( !mpData->mpUII18nHelper ) {
+ ::com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory> aFactory(vcl::unohelper::GetMultiServiceFactory());
+ ((AllSettings*)this)->mpData->mpUII18nHelper = new vcl::I18nHelper( aFactory, GetUILocale() );
+ }
+ return *mpData->mpUII18nHelper;
+}
+
+
+// -----------------------------------------------------------------------
+/*
+const CollatorWrapper& AllSettings::GetCollatorWrapper() const
+{
+ if ( !mpData->mpCollatorWrapper )
+ {
+ ((AllSettings*)this)->mpData->mpCollatorWrapper = new CollatorWrapper( vcl::unohelper::GetMultiServiceFactory() );
+ ((AllSettings*)this)->mpData->mpCollatorWrapper->loadDefaultCollator( GetLocale(), 0 );
+ }
+ return *mpData->mpCollatorWrapper;
+}
+*/
+// -----------------------------------------------------------------------
+/*
+const CollatorWrapper& AllSettings::GetUICollatorWrapper() const
+{
+ if ( !mpData->mpUICollatorWrapper )
+ {
+ ((AllSettings*)this)->mpData->mpUICollatorWrapper = new CollatorWrapper( vcl::unohelper::GetMultiServiceFactory() );
+ ((AllSettings*)this)->mpData->mpUICollatorWrapper->loadDefaultCollator( GetUILocale(), 0 );
+ }
+ return *mpData->mpUICollatorWrapper;
+}
+*/
+
+void AllSettings::LocaleSettingsChanged( sal_uInt32 nHint )
+{
+ AllSettings aAllSettings( Application::GetSettings() );
+ if ( nHint & SYSLOCALEOPTIONS_HINT_DECSEP )
+ {
+ MiscSettings aMiscSettings = aAllSettings.GetMiscSettings();
+ BOOL bIsDecSepAsLocale = aAllSettings.mpData->maSysLocale.GetOptions().IsDecimalSeparatorAsLocale();
+ if ( aMiscSettings.GetEnableLocalizedDecimalSep() != bIsDecSepAsLocale )
+ {
+ aMiscSettings.SetEnableLocalizedDecimalSep( bIsDecSepAsLocale );
+ aAllSettings.SetMiscSettings( aMiscSettings );
+ }
+ }
+
+ if ( (nHint & SYSLOCALEOPTIONS_HINT_LOCALE) )
+ aAllSettings.SetLocale( aAllSettings.mpData->maSysLocale.GetOptions().GetLocale() );
+
+ Application::SetSettings( aAllSettings );
+}
diff --git a/vcl/source/app/sound.cxx b/vcl/source/app/sound.cxx
new file mode 100644
index 000000000000..bac9d50dc5da
--- /dev/null
+++ b/vcl/source/app/sound.cxx
@@ -0,0 +1,55 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/urlobj.hxx>
+#include <unotools/localfilehelper.hxx>
+#ifndef _UNOTOOLS_UCBSTREAMHELPER_HXX
+#include <unotools/ucbstreamhelper.hxx>
+#endif
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salframe.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/window.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/sound.hxx>
+#include <vcl/salinst.hxx>
+
+void Sound::Beep( SoundType eType, Window* pWindow )
+{
+ if( !pWindow )
+ {
+ Window* pDefWindow = ImplGetDefaultWindow();
+ pDefWindow->ImplGetFrame()->Beep( eType );
+ }
+ else
+ pWindow->ImplGetFrame()->Beep( eType );
+}
diff --git a/vcl/source/app/stdtext.cxx b/vcl/source/app/stdtext.cxx
new file mode 100644
index 000000000000..176ec5a1b4c6
--- /dev/null
+++ b/vcl/source/app/stdtext.cxx
@@ -0,0 +1,68 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/stdtext.hxx>
+
+
+
+// =======================================================================
+
+XubString GetStandardText( USHORT nStdText )
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ XubString aText;
+ if( pResMgr )
+ aText = XubString( ResId( nStdText-STANDARD_TEXT_FIRST+SV_STDTEXT_FIRST, *pResMgr ) );
+ return aText;
+}
+
+// =======================================================================
+
+void ShowServiceNotAvailableError( Window* pParent,
+ const XubString& rServiceName, BOOL bError )
+{
+ XubString aText( GetStandardText( STANDARD_TEXT_SERVICE_NOT_AVAILABLE ) );
+ aText.SearchAndReplaceAscii( "%s", rServiceName );
+ if ( bError )
+ {
+ ErrorBox aBox( pParent, WB_OK | WB_DEF_OK, aText );
+ aBox.Execute();
+ }
+ else
+ {
+ WarningBox aBox( pParent, WB_OK | WB_DEF_OK, aText );
+ aBox.Execute();
+ }
+}
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
new file mode 100644
index 000000000000..e503172eb2c6
--- /dev/null
+++ b/vcl/source/app/svapp.cxx
@@ -0,0 +1,2085 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "svsys.h"
+#include "vcl/salinst.hxx"
+#include "vcl/salframe.hxx"
+#include "vcl/salsys.hxx"
+#include "vos/process.hxx"
+#include "vos/mutex.hxx"
+#include "tools/tools.h"
+#include "tools/debug.hxx"
+#include "tools/time.hxx"
+#include "i18npool/mslangid.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/settings.hxx"
+#include "vcl/accmgr.hxx"
+#include "vcl/keycod.hxx"
+#include "vcl/event.hxx"
+#include "vcl/vclevent.hxx"
+#include "vcl/virdev.hxx"
+#include "vcl/windata.hxx"
+#include "vcl/window.h"
+#include "vcl/wrkwin.hxx"
+#include "vcl/idlemgr.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/cvtgrf.hxx"
+#include "vcl/unowrap.hxx"
+#include "vcl/xconnection.hxx"
+#include "vcl/svids.hrc"
+#include "vcl/timer.hxx"
+
+#include "vcl/unohelp.hxx"
+
+#include "com/sun/star/uno/Reference.h"
+#include "com/sun/star/awt/XToolkit.hpp"
+#include "com/sun/star/uno/XNamingService.hpp"
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "comphelper/processfactory.hxx"
+
+#include "osl/module.h"
+#include "osl/file.hxx"
+
+#include "osl/thread.h"
+#include "rtl/tencinfo.h"
+#include "rtl/instance.hxx"
+#include "vcl/salimestatus.hxx"
+
+#include <utility>
+#include <vcl/lazydelete.hxx>
+#include <unotools/syslocaleoptions.hxx>
+
+using namespace ::com::sun::star::uno;
+
+// keycodes handled internally by VCL
+class ImplReservedKey
+{
+public:
+ ImplReservedKey( KeyCode aKeyCode, USHORT nResId ) :
+ mKeyCode(aKeyCode), mnResId( nResId)
+ {}
+
+ KeyCode mKeyCode;
+ USHORT mnResId;
+};
+
+typedef std::pair<ImplReservedKey*, size_t> ReservedKeys;
+namespace
+{
+ struct ImplReservedKeysImpl
+ {
+ ReservedKeys* operator()()
+ {
+ static ImplReservedKey ImplReservedKeys[] =
+ {
+ ImplReservedKey(KeyCode(KEY_F1,0), SV_SHORTCUT_HELP),
+ ImplReservedKey(KeyCode(KEY_F1,KEY_SHIFT), SV_SHORTCUT_ACTIVEHELP),
+ ImplReservedKey(KeyCode(KEY_F1,KEY_MOD1), SV_SHORTCUT_CONTEXTHELP),
+ ImplReservedKey(KeyCode(KEY_F2,KEY_SHIFT), SV_SHORTCUT_CONTEXTHELP),
+ ImplReservedKey(KeyCode(KEY_F4,KEY_MOD1), SV_SHORTCUT_DOCKUNDOCK),
+ ImplReservedKey(KeyCode(KEY_F4,KEY_MOD2), SV_SHORTCUT_DOCKUNDOCK),
+ ImplReservedKey(KeyCode(KEY_F4,KEY_MOD1|KEY_MOD2), SV_SHORTCUT_DOCKUNDOCK),
+ ImplReservedKey(KeyCode(KEY_F6,0), SV_SHORTCUT_NEXTSUBWINDOW),
+ ImplReservedKey(KeyCode(KEY_F6,KEY_MOD1), SV_SHORTCUT_TODOCUMENT),
+ ImplReservedKey(KeyCode(KEY_F6,KEY_SHIFT), SV_SHORTCUT_PREVSUBWINDOW),
+ ImplReservedKey(KeyCode(KEY_F6,KEY_MOD1|KEY_SHIFT), SV_SHORTCUT_SPLITTER),
+ ImplReservedKey(KeyCode(KEY_F10,0), SV_SHORTCUT_MENUBAR)
+#ifdef UNX
+ ,
+ ImplReservedKey(KeyCode(KEY_1,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_2,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_3,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_4,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_5,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_6,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_7,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_8,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_9,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_0,KEY_SHIFT|KEY_MOD1), 0),
+ ImplReservedKey(KeyCode(KEY_ADD,KEY_SHIFT|KEY_MOD1), 0)
+#endif
+ };
+ static ReservedKeys aKeys
+ (
+ &ImplReservedKeys[0],
+ sizeof(ImplReservedKeys) / sizeof(ImplReservedKey)
+ );
+ return &aKeys;
+ }
+ };
+
+ struct ImplReservedKeys
+ : public rtl::StaticAggregate<ReservedKeys, ImplReservedKeysImpl> {};
+}
+
+
+// #include <usr/refl.hxx>
+class Reflection;
+
+
+
+extern "C" {
+ typedef UnoWrapperBase* (SAL_CALL *FN_TkCreateUnoWrapper)();
+}
+
+// =======================================================================
+
+// --------------
+// - ImplHotKey -
+// --------------
+
+struct ImplHotKey
+{
+ ImplHotKey* mpNext;
+ void* mpUserData;
+ KeyCode maKeyCode;
+ Link maLink;
+};
+
+// =======================================================================
+
+// -----------------
+// - ImplEventHook -
+// -----------------
+
+struct ImplEventHook
+{
+ ImplEventHook* mpNext;
+ void* mpUserData;
+ VCLEventHookProc mpProc;
+};
+
+// =======================================================================
+
+// ---------------------
+// - ImplPostEventData -
+// ---------------------
+
+struct ImplPostEventData
+{
+ ULONG mnEvent;
+ const Window* mpWin;
+ ULONG mnEventId;
+ KeyEvent maKeyEvent;
+ MouseEvent maMouseEvent;
+
+
+ ImplPostEventData( ULONG nEvent, const Window* pWin, const KeyEvent& rKeyEvent ) :
+ mnEvent( nEvent ), mpWin( pWin ), mnEventId( 0 ), maKeyEvent( rKeyEvent ) {}
+ ImplPostEventData( ULONG nEvent, const Window* pWin, const MouseEvent& rMouseEvent ) :
+ mnEvent( nEvent ), mpWin( pWin ), mnEventId( 0 ), maMouseEvent( rMouseEvent ) {}
+
+ ~ImplPostEventData() {}
+};
+
+typedef ::std::pair< Window*, ImplPostEventData* > ImplPostEventPair;
+
+static ::std::list< ImplPostEventPair > aPostedEventList;
+
+// =======================================================================
+
+Application* GetpApp()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData )
+ return NULL;
+ return pSVData->mpApp;
+}
+
+// -----------------------------------------------------------------------
+
+Application::Application()
+{
+ if( ! ImplGetSVData() )
+ ImplInitSVData();
+ ImplGetSVData()->mpApp = this;
+ InitSalData();
+}
+
+// -----------------------------------------------------------------------
+
+Application::~Application()
+{
+ ImplDeInitSVData();
+ DeInitSalData();
+ ImplGetSVData()->mpApp = NULL;
+ ImplDestroySVData();
+ GlobalDeInitTools();
+}
+
+// -----------------------------------------------------------------------
+
+void Application::InitAppRes( const ResId& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::QueryExit()
+{
+ WorkWindow* pAppWin = ImplGetSVData()->maWinData.mpAppWin;
+
+ // Aufruf des Close-Handlers des Applikationsfensters
+ if ( pAppWin )
+ return pAppWin->Close();
+ else
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::UserEvent( ULONG, void* )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::ShowStatusText( const XubString& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::ShowHelpStatusText( const XubString& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::ActivateExtHelp()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::DeactivateExtHelp()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::HideStatusText()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::HideHelpStatusText()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::FocusChanged()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::DataChanged( const DataChangedEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+void Application::Init()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::DeInit()
+{
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Application::GetCommandLineParamCount()
+{
+ vos::OStartupInfo aStartInfo;
+ return (USHORT)aStartInfo.getCommandArgCount();
+}
+
+// -----------------------------------------------------------------------
+
+XubString Application::GetCommandLineParam( USHORT nParam )
+{
+ vos::OStartupInfo aStartInfo;
+ rtl::OUString aParam;
+ aStartInfo.getCommandArg( nParam, aParam );
+ return XubString( aParam );
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& Application::GetAppFileName()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ DBG_ASSERT( pSVData->maAppData.mpAppFileName, "AppFileName vor SVMain ?!" );
+ if ( pSVData->maAppData.mpAppFileName )
+ return *pSVData->maAppData.mpAppFileName;
+
+ /*
+ * #91147# provide a fallback for people without initialized
+ * vcl here (like setup in responsefile mode)
+ */
+ static String aAppFileName;
+ if( !aAppFileName.Len() )
+ {
+ vos::OStartupInfo aStartInfo;
+ ::rtl::OUString aExeFileName;
+
+ aStartInfo.getExecutableFile( aExeFileName );
+
+ // convert path to native file format
+ rtl::OUString aNativeFileName;
+ osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
+ aAppFileName = aNativeFileName;
+ }
+
+ return aAppFileName;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Application::Exception( USHORT nError )
+{
+ switch ( nError & EXC_MAJORTYPE )
+ {
+ // Bei System machen wir nichts und lassen dem System den
+ // vortritt
+ case EXC_SYSTEM:
+ return 0;
+
+ case EXC_DISPLAY:
+ case EXC_REMOTE:
+ return 0;
+
+#ifdef DBG_UTIL
+ case EXC_RSCNOTLOADED:
+ Abort( XubString( RTL_CONSTASCII_USTRINGPARAM( "Resource not loaded" ) ) );
+ break;
+ case EXC_SYSOBJNOTCREATED:
+ Abort( XubString( RTL_CONSTASCII_USTRINGPARAM( "System Object not created" ) ) );
+ break;
+ default:
+ Abort( XubString( RTL_CONSTASCII_USTRINGPARAM( "Unknown Error" ) ) );
+ break;
+#else
+ default:
+ Abort( ImplGetSVEmptyStr() );
+ break;
+#endif
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::Abort( const XubString& rErrorText )
+{
+ SalAbort( rErrorText );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Application::GetReservedKeyCodeCount()
+{
+ return ImplReservedKeys::get()->second;
+}
+
+const KeyCode* Application::GetReservedKeyCode( ULONG i )
+{
+ if( i >= GetReservedKeyCodeCount() )
+ return NULL;
+ else
+ return &ImplReservedKeys::get()->first[i].mKeyCode;
+}
+
+String Application::GetReservedKeyCodeDescription( ULONG i )
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( ! pResMgr )
+ return String();
+ ImplReservedKey *pImplReservedKeys = ImplReservedKeys::get()->first;
+ if( i >= GetReservedKeyCodeCount() || ! pImplReservedKeys[i].mnResId )
+ return String();
+ else
+ return String( ResId( pImplReservedKeys[i].mnResId, *pResMgr ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::Execute()
+{
+ DBG_STARTAPPEXECUTE();
+
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mbInAppExecute = TRUE;
+
+ while ( !pSVData->maAppData.mbAppQuit )
+ Application::Yield();
+
+ pSVData->maAppData.mbInAppExecute = FALSE;
+
+ DBG_ENDAPPEXECUTE();
+}
+
+// -----------------------------------------------------------------------
+
+inline void ImplYield( bool i_bWait, bool i_bAllEvents )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // run timers that have timed out
+ if ( !pSVData->mbNoCallTimer )
+ while ( pSVData->mbNotAllTimerCalled )
+ Timer::ImplTimerCallbackProc();
+
+ pSVData->maAppData.mnDispatchLevel++;
+ // do not wait for events if application was already quit; in that
+ // case only dispatch events already available
+ // do not wait for events either if the app decided that it is too busy for timers
+ // (feature added for the slideshow)
+ pSVData->mpDefInst->Yield( i_bWait && !pSVData->maAppData.mbAppQuit && !pSVData->maAppData.mbNoYield, i_bAllEvents );
+ pSVData->maAppData.mnDispatchLevel--;
+
+ // flush lazy deleted objects
+ if( pSVData->maAppData.mnDispatchLevel == 0 )
+ vcl::LazyDelete::flush();
+
+ // the system timer events will not necesseraly come in in non waiting mode
+ // e.g. on aqua; need to trigger timer checks manually
+ if( pSVData->maAppData.mbNoYield && !pSVData->mbNoCallTimer )
+ {
+ do
+ {
+ Timer::ImplTimerCallbackProc();
+ }
+ while( pSVData->mbNotAllTimerCalled );
+ }
+
+ // call post yield listeners
+ if( pSVData->maAppData.mpPostYieldListeners )
+ pSVData->maAppData.mpPostYieldListeners->callListeners( NULL );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::Reschedule( bool i_bAllEvents )
+{
+ ImplYield( false, i_bAllEvents );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::Yield( bool i_bAllEvents )
+{
+ ImplYield( true, i_bAllEvents );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_STATIC_LINK_NOINSTANCE( ImplSVAppData, ImplQuitMsg, void*, EMPTYARG )
+{
+ ImplGetSVData()->maAppData.mbAppQuit = TRUE;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::Quit()
+{
+ Application::PostUserEvent( STATIC_LINK( NULL, ImplSVAppData, ImplQuitMsg ) );
+}
+
+// -----------------------------------------------------------------------
+
+vos::IMutex& Application::GetSolarMutex()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return *(pSVData->mpDefInst->GetYieldMutex());
+}
+
+// -----------------------------------------------------------------------
+
+vos::OThread::TThreadIdentifier Application::GetMainThreadIdentifier()
+{
+ return ImplGetSVData()->mnMainThreadId;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Application::ReleaseSolarMutex()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->mpDefInst->ReleaseYieldMutex();
+}
+
+// -----------------------------------------------------------------------
+
+void Application::AcquireSolarMutex( ULONG nCount )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpDefInst->AcquireYieldMutex( nCount );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsInMain()
+{
+ return ImplGetSVData()->maAppData.mbInAppMain;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsInExecute()
+{
+ return ImplGetSVData()->maAppData.mbInAppExecute;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsShutDown()
+{
+ return ImplGetSVData()->maAppData.mbAppQuit;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsInModalMode()
+{
+ return (ImplGetSVData()->maAppData.mnModalMode != 0);
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Application::GetModalModeCount()
+{
+ return ImplGetSVData()->maAppData.mnModalMode;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Application::GetDispatchLevel()
+{
+ return ImplGetSVData()->maAppData.mnDispatchLevel;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::AnyInput( USHORT nType )
+{
+ return (BOOL)ImplGetSVData()->mpDefInst->AnyInput( nType );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Application::GetLastInputInterval()
+{
+ return (Time::GetSystemTicks()-ImplGetSVData()->maAppData.mnLastInputTime);
+}
+
+// -----------------------------------------------------------------------
+
+extern int nImplSysDialog;
+
+BOOL Application::IsUICaptured()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ // Wenn Mouse gecaptured, oder im TrackingModus oder im Auswahlmodus
+ // eines FloatingWindows (wie Menus, Aufklapp-ToolBoxen) soll kein
+ // weiteres Fenster aufgezogen werden
+ // D&D aktive !!!
+ if ( pSVData->maWinData.mpCaptureWin || pSVData->maWinData.mpTrackWin ||
+ pSVData->maWinData.mpFirstFloat || nImplSysDialog )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsUserActive( USHORT nTest )
+{
+ if ( nTest & (USERACTIVE_MOUSEDRAG | USERACTIVE_INPUT) )
+ {
+ if ( IsUICaptured() )
+ return TRUE;
+ }
+
+ if ( nTest & USERACTIVE_INPUT )
+ {
+ if ( GetLastInputInterval() < 500 )
+ return TRUE;
+
+ if ( AnyInput( INPUT_KEYBOARD ) )
+ return TRUE;
+ }
+
+ if ( nTest & USERACTIVE_MODALDIALOG )
+ {
+ if ( ImplGetSVData()->maAppData.mnModalDialog )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SystemSettingsChanging( AllSettings& /*rSettings*/,
+ Window* /*pFrame*/ )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Application::MergeSystemSettings( AllSettings& rSettings )
+{
+ Window* pWindow = ImplGetSVData()->maWinData.mpFirstFrame;
+ if( ! pWindow )
+ pWindow = ImplGetDefaultWindow();
+ if( pWindow )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maAppData.mbSettingsInit )
+ {
+ // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
+ pWindow->ImplUpdateGlobalSettings( *pSVData->maAppData.mpSettings );
+ pSVData->maAppData.mbSettingsInit = TRUE;
+ }
+ // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
+ pWindow->ImplUpdateGlobalSettings( rSettings, FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool Application::ValidateSystemFont()
+{
+ Window* pWindow = ImplGetSVData()->maWinData.mpFirstFrame;
+ if( ! pWindow )
+ pWindow = ImplGetDefaultWindow();
+
+ if( pWindow )
+ {
+ AllSettings aSettings;
+ pWindow->ImplGetFrame()->UpdateSettings( aSettings );
+ return pWindow->ImplCheckUIFont( aSettings.GetStyleSettings().GetAppFont() );
+ }
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetSettings( const AllSettings& rSettings )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maAppData.mpSettings )
+ {
+ GetSettings();
+ *pSVData->maAppData.mpSettings = rSettings;
+ ResMgr::SetDefaultLocale( rSettings.GetUILocale() );
+ }
+ else
+ {
+ AllSettings aOldSettings = *pSVData->maAppData.mpSettings;
+ if( aOldSettings.GetUILanguage() != rSettings.GetUILanguage() && pSVData->mpResMgr )
+ {
+ delete pSVData->mpResMgr;
+ pSVData->mpResMgr = NULL;
+ }
+ ResMgr::SetDefaultLocale( rSettings.GetUILocale() );
+ *pSVData->maAppData.mpSettings = rSettings;
+ ULONG nChangeFlags = aOldSettings.GetChangeFlags( *pSVData->maAppData.mpSettings );
+ if ( nChangeFlags )
+ {
+ DataChangedEvent aDCEvt( DATACHANGED_SETTINGS, &aOldSettings, nChangeFlags );
+ GetpApp()->DataChanged( aDCEvt );
+
+ // notify data change handler
+ ImplCallEventListeners( VCLEVENT_APPLICATION_DATACHANGED, NULL, &aDCEvt);
+
+ // Update all windows
+ Window* pFirstFrame = pSVData->maWinData.mpFirstFrame;
+ // Daten, die neu berechnet werden muessen, zuruecksetzen
+ long nOldDPIX = 0;
+ long nOldDPIY = 0;
+ if ( pFirstFrame )
+ {
+ nOldDPIX = pFirstFrame->mnDPIX;
+ nOldDPIY = pFirstFrame->mnDPIY;
+ pSVData->maGDIData.mnAppFontX = 0;
+ }
+ Window* pFrame = pFirstFrame;
+ while ( pFrame )
+ {
+ // AppFont-Cache-Daten zuruecksetzen
+ pFrame->mpWindowImpl->mpFrameData->meMapUnit = MAP_PIXEL;
+
+ // UpdateSettings am ClientWindow aufrufen, damit
+ // die Daten nicht doppelt geupdatet werden
+ Window* pClientWin = pFrame;
+ while ( pClientWin->ImplGetClientWindow() )
+ pClientWin = pClientWin->ImplGetClientWindow();
+ pClientWin->UpdateSettings( rSettings, TRUE );
+
+ Window* pTempWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pTempWin )
+ {
+ // UpdateSettings am ClientWindow aufrufen, damit
+ // die Daten nicht doppelt geupdatet werden
+ pClientWin = pTempWin;
+ while ( pClientWin->ImplGetClientWindow() )
+ pClientWin = pClientWin->ImplGetClientWindow();
+ pClientWin->UpdateSettings( rSettings, TRUE );
+ pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
+ }
+
+ pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+
+ // Wenn sich die DPI-Aufloesung fuer Screen-Ausgaben
+ // geaendert hat, setzen wir auch bei allen
+ // Screen-Kompatiblen VirDev's die neue Aufloesung
+ pFirstFrame = pSVData->maWinData.mpFirstFrame;
+ if ( pFirstFrame )
+ {
+ if ( (pFirstFrame->mnDPIX != nOldDPIX) ||
+ (pFirstFrame->mnDPIY != nOldDPIY) )
+ {
+ VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
+ while ( pVirDev )
+ {
+ if ( pVirDev->mbScreenComp &&
+ (pVirDev->mnDPIX == nOldDPIX) &&
+ (pVirDev->mnDPIY == nOldDPIY) )
+ {
+ pVirDev->mnDPIX = pFirstFrame->mnDPIX;
+ pVirDev->mnDPIY = pFirstFrame->mnDPIY;
+ if ( pVirDev->IsMapMode() )
+ {
+ MapMode aMapMode = pVirDev->GetMapMode();
+ pVirDev->SetMapMode();
+ pVirDev->SetMapMode( aMapMode );
+ }
+ }
+
+ pVirDev = pVirDev->mpNext;
+ }
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const AllSettings& Application::GetSettings()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maAppData.mpSettings )
+ {
+ pSVData->maAppData.mpCfgListener = new LocaleConfigurationListener;
+ pSVData->maAppData.mpSettings = new AllSettings();
+ pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().AddListener( pSVData->maAppData.mpCfgListener );
+ }
+
+ return *(pSVData->maAppData.mpSettings);
+}
+
+// -----------------------------------------------------------------------
+
+void Application::NotifyAllWindows( DataChangedEvent& rDCEvt )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pFrame = pSVData->maWinData.mpFirstFrame;
+ while ( pFrame )
+ {
+ pFrame->NotifyAllChilds( rDCEvt );
+
+ Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pSysWin )
+ {
+ pSysWin->NotifyAllChilds( rDCEvt );
+ pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
+ }
+
+ pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Application::ImplCallEventListeners( ULONG nEvent, Window *pWin, void* pData )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ VclWindowEvent aEvent( pWin, nEvent, pData );
+
+ if ( pSVData->maAppData.mpEventListeners )
+ if ( !pSVData->maAppData.mpEventListeners->empty() )
+ pSVData->maAppData.mpEventListeners->Call( &aEvent );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::ImplCallEventListeners( VclSimpleEvent* pEvent )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maAppData.mpEventListeners )
+ if ( !pSVData->maAppData.mpEventListeners->empty() )
+ pSVData->maAppData.mpEventListeners->Call( pEvent );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::AddEventListener( const Link& rEventListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( !pSVData->maAppData.mpEventListeners )
+ pSVData->maAppData.mpEventListeners = new VclEventListeners;
+ pSVData->maAppData.mpEventListeners->push_back( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveEventListener( const Link& rEventListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->maAppData.mpEventListeners )
+ pSVData->maAppData.mpEventListeners->remove( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+void Application::AddKeyListener( const Link& rKeyListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( !pSVData->maAppData.mpKeyListeners )
+ pSVData->maAppData.mpKeyListeners = new VclEventListeners;
+ pSVData->maAppData.mpKeyListeners->push_back( rKeyListener );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveKeyListener( const Link& rKeyListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->maAppData.mpKeyListeners )
+ pSVData->maAppData.mpKeyListeners->remove( rKeyListener );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::HandleKey( ULONG nEvent, Window *pWin, KeyEvent* pKeyEvent )
+{
+ // let listeners process the key event
+ VclWindowEvent aEvent( pWin, nEvent, (void *) pKeyEvent );
+
+ ImplSVData* pSVData = ImplGetSVData();
+ BOOL bProcessed = FALSE;
+
+ if ( pSVData->maAppData.mpKeyListeners )
+ if ( !pSVData->maAppData.mpKeyListeners->empty() )
+ bProcessed = pSVData->maAppData.mpKeyListeners->Process( &aEvent );
+
+ return bProcessed;
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG Application::PostKeyEvent( ULONG nEvent, Window *pWin, KeyEvent* pKeyEvent )
+{
+ const ::vos::OGuard aGuard( GetSolarMutex() );
+ ULONG nEventId = 0;
+
+ if( pWin && pKeyEvent )
+ {
+ ImplPostEventData* pPostEventData = new ImplPostEventData( nEvent, pWin, *pKeyEvent );
+
+ PostUserEvent( nEventId,
+ STATIC_LINK( NULL, Application, PostEventHandler ),
+ pPostEventData );
+
+ if( nEventId )
+ {
+ pPostEventData->mnEventId = nEventId;
+ aPostedEventList.push_back( ImplPostEventPair( pWin, pPostEventData ) );
+ }
+ else
+ delete pPostEventData;
+ }
+
+ return nEventId;
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG Application::PostMouseEvent( ULONG nEvent, Window *pWin, MouseEvent* pMouseEvent )
+{
+ const ::vos::OGuard aGuard( GetSolarMutex() );
+ ULONG nEventId = 0;
+
+ if( pWin && pMouseEvent )
+ {
+ Point aTransformedPos( pMouseEvent->GetPosPixel() );
+
+ aTransformedPos.X() += pWin->mnOutOffX;
+ aTransformedPos.Y() += pWin->mnOutOffY;
+
+ const MouseEvent aTransformedEvent( aTransformedPos, pMouseEvent->GetClicks(), pMouseEvent->GetMode(),
+ pMouseEvent->GetButtons(), pMouseEvent->GetModifier() );
+
+ ImplPostEventData* pPostEventData = new ImplPostEventData( nEvent, pWin, aTransformedEvent );
+
+ PostUserEvent( nEventId,
+ STATIC_LINK( NULL, Application, PostEventHandler ),
+ pPostEventData );
+
+ if( nEventId )
+ {
+ pPostEventData->mnEventId = nEventId;
+ aPostedEventList.push_back( ImplPostEventPair( pWin, pPostEventData ) );
+ }
+ else
+ delete pPostEventData;
+ }
+
+ return nEventId;
+}
+
+// -----------------------------------------------------------------------------
+
+IMPL_STATIC_LINK_NOINSTANCE( Application, PostEventHandler, void*, pCallData )
+{
+ const ::vos::OGuard aGuard( GetSolarMutex() );
+ ImplPostEventData* pData = static_cast< ImplPostEventData * >( pCallData );
+ const void* pEventData;
+ ULONG nEvent;
+ const ULONG nEventId = pData->mnEventId;
+
+ switch( pData->mnEvent )
+ {
+ case VCLEVENT_WINDOW_MOUSEMOVE:
+ nEvent = SALEVENT_EXTERNALMOUSEMOVE;
+ pEventData = &pData->maMouseEvent;
+ break;
+
+ case VCLEVENT_WINDOW_MOUSEBUTTONDOWN:
+ nEvent = SALEVENT_EXTERNALMOUSEBUTTONDOWN;
+ pEventData = &pData->maMouseEvent;
+ break;
+
+ case VCLEVENT_WINDOW_MOUSEBUTTONUP:
+ nEvent = SALEVENT_EXTERNALMOUSEBUTTONUP;
+ pEventData = &pData->maMouseEvent;
+ break;
+
+ case VCLEVENT_WINDOW_KEYINPUT:
+ nEvent = SALEVENT_EXTERNALKEYINPUT;
+ pEventData = &pData->maKeyEvent;
+ break;
+
+ case VCLEVENT_WINDOW_KEYUP:
+ nEvent = SALEVENT_EXTERNALKEYUP;
+ pEventData = &pData->maKeyEvent;
+ break;
+
+ default:
+ nEvent = 0;
+ pEventData = NULL;
+ break;
+ };
+
+ if( pData->mpWin && pData->mpWin->mpWindowImpl->mpFrameWindow && pEventData )
+ ImplWindowFrameProc( pData->mpWin->mpWindowImpl->mpFrameWindow, NULL, (USHORT) nEvent, pEventData );
+
+ // remove this event from list of posted events, watch for destruction of internal data
+ ::std::list< ImplPostEventPair >::iterator aIter( aPostedEventList.begin() );
+
+ while( aIter != aPostedEventList.end() )
+ {
+ if( nEventId == (*aIter).second->mnEventId )
+ {
+ delete (*aIter).second;
+ aIter = aPostedEventList.erase( aIter );
+ }
+ else
+ ++aIter;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveMouseAndKeyEvents( Window* pWin )
+{
+ const ::vos::OGuard aGuard( GetSolarMutex() );
+
+ // remove all events for specific window, watch for destruction of internal data
+ ::std::list< ImplPostEventPair >::iterator aIter( aPostedEventList.begin() );
+
+ while( aIter != aPostedEventList.end() )
+ {
+ if( pWin == (*aIter).first )
+ {
+ if( (*aIter).second->mnEventId )
+ RemoveUserEvent( (*aIter).second->mnEventId );
+
+ delete (*aIter).second;
+ aIter = aPostedEventList.erase( aIter );
+ }
+ else
+ ++aIter;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsProcessedMouseOrKeyEvent( ULONG nEventId )
+{
+ const ::vos::OGuard aGuard( GetSolarMutex() );
+
+ // find event
+ ::std::list< ImplPostEventPair >::iterator aIter( aPostedEventList.begin() );
+
+ while( aIter != aPostedEventList.end() )
+ {
+ if( (*aIter).second->mnEventId == nEventId )
+ return FALSE;
+
+ else
+ ++aIter;
+ }
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Application::PostUserEvent( ULONG nEvent, void* pEventData )
+{
+ ULONG nEventId;
+ PostUserEvent( nEventId, nEvent, pEventData );
+ return nEventId;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Application::PostUserEvent( const Link& rLink, void* pCaller )
+{
+ ULONG nEventId;
+ PostUserEvent( nEventId, rLink, pCaller );
+ return nEventId;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::PostUserEvent( ULONG& rEventId, ULONG nEvent, void* pEventData )
+{
+ ImplSVEvent* pSVEvent = new ImplSVEvent;
+ pSVEvent->mnEvent = nEvent;
+ pSVEvent->mpData = pEventData;
+ pSVEvent->mpLink = NULL;
+ pSVEvent->mpWindow = NULL;
+ pSVEvent->mbCall = TRUE;
+ rEventId = (ULONG)pSVEvent;
+ Window* pDefWindow = ImplGetDefaultWindow();
+ if ( pDefWindow && pDefWindow->ImplGetFrame()->PostEvent( pSVEvent ) )
+ return TRUE;
+ else
+ {
+ rEventId = 0;
+ delete pSVEvent;
+ return FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::PostUserEvent( ULONG& rEventId, const Link& rLink, void* pCaller )
+{
+ ImplSVEvent* pSVEvent = new ImplSVEvent;
+ pSVEvent->mnEvent = 0;
+ pSVEvent->mpData = pCaller;
+ pSVEvent->mpLink = new Link( rLink );
+ pSVEvent->mpWindow = NULL;
+ pSVEvent->mbCall = TRUE;
+ rEventId = (ULONG)pSVEvent;
+ Window* pDefWindow = ImplGetDefaultWindow();
+ if ( pDefWindow && pDefWindow->ImplGetFrame()->PostEvent( pSVEvent ) )
+ return TRUE;
+ else
+ {
+ rEventId = 0;
+ delete pSVEvent;
+ return FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveUserEvent( ULONG nUserEvent )
+{
+ if(nUserEvent)
+ {
+ ImplSVEvent* pSVEvent = (ImplSVEvent*)nUserEvent;
+
+ DBG_ASSERT( !pSVEvent->mpWindow,
+ "Application::RemoveUserEvent(): Event is send to a window" );
+ DBG_ASSERT( pSVEvent->mbCall,
+ "Application::RemoveUserEvent(): Event is already removed" );
+
+ if ( pSVEvent->mpWindow )
+ {
+ if( ! pSVEvent->maDelData.IsDelete() )
+ pSVEvent->mpWindow->ImplRemoveDel( &(pSVEvent->maDelData) );
+ pSVEvent->mpWindow = NULL;
+ }
+
+ pSVEvent->mbCall = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::InsertIdleHdl( const Link& rLink, USHORT nPrio )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Falls er noch nicht existiert, dann anlegen
+ if ( !pSVData->maAppData.mpIdleMgr )
+ pSVData->maAppData.mpIdleMgr = new ImplIdleMgr;
+
+ return pSVData->maAppData.mpIdleMgr->InsertIdleHdl( rLink, nPrio );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveIdleHdl( const Link& rLink )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maAppData.mpIdleMgr )
+ pSVData->maAppData.mpIdleMgr->RemoveIdleHdl( rLink );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::EnableNoYieldMode( bool i_bNoYield )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mbNoYield = i_bNoYield;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::AddPostYieldListener( const Link& i_rListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->maAppData.mpPostYieldListeners )
+ pSVData->maAppData.mpPostYieldListeners = new VclEventListeners2();
+ pSVData->maAppData.mpPostYieldListeners->addListener( i_rListener );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemovePostYieldListener( const Link& i_rListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->maAppData.mpPostYieldListeners )
+ pSVData->maAppData.mpPostYieldListeners->removeListener( i_rListener );
+}
+
+// -----------------------------------------------------------------------
+
+WorkWindow* Application::GetAppWindow()
+{
+ return ImplGetSVData()->maWinData.mpAppWin;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Application::GetFocusWindow()
+{
+ return ImplGetSVData()->maWinData.mpFocusWin;
+}
+
+// -----------------------------------------------------------------------
+
+OutputDevice* Application::GetDefaultDevice()
+{
+ return ImplGetDefaultWindow();
+}
+
+// -----------------------------------------------------------------------
+
+Window* Application::GetFirstTopLevelWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->maWinData.mpFirstFrame;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Application::GetNextTopLevelWindow( Window* pWindow )
+{
+ return pWindow->mpWindowImpl->mpFrameData->mpNextFrame;
+}
+
+// -----------------------------------------------------------------------
+
+long Application::GetTopWindowCount()
+{
+ long nRet = 0;
+ ImplSVData* pSVData = ImplGetSVData();
+ Window *pWin = pSVData ? pSVData->maWinData.mpFirstFrame : NULL;
+ while( pWin )
+ {
+ if( pWin->ImplGetWindow()->IsTopWindow() )
+ nRet++;
+ pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Application::GetTopWindow( long nIndex )
+{
+ long nIdx = 0;
+ ImplSVData* pSVData = ImplGetSVData();
+ Window *pWin = pSVData ? pSVData->maWinData.mpFirstFrame : NULL;
+ while( pWin )
+ {
+ if( pWin->ImplGetWindow()->IsTopWindow() )
+ {
+ if( nIdx == nIndex )
+ return pWin->ImplGetWindow();
+ else
+ nIdx++;
+ }
+ pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Application::GetActiveTopWindow()
+{
+ Window *pWin = ImplGetSVData()->maWinData.mpFocusWin;
+ while( pWin )
+ {
+ if( pWin->IsTopWindow() )
+ return pWin;
+ pWin = pWin->mpWindowImpl->mpParent;
+ }
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetAppName( const XubString& rUniqueName )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Falls er noch nicht existiert, dann anlegen
+ if ( !pSVData->maAppData.mpAppName )
+ pSVData->maAppData.mpAppName = new XubString( rUniqueName );
+ else
+ *(pSVData->maAppData.mpAppName) = rUniqueName;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Application::GetAppName()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maAppData.mpAppName )
+ return *(pSVData->maAppData.mpAppName);
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetDisplayName( const UniString& rName )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Falls er noch nicht existiert, dann anlegen
+ if ( !pSVData->maAppData.mpDisplayName )
+ pSVData->maAppData.mpDisplayName = new UniString( rName );
+ else
+ *(pSVData->maAppData.mpDisplayName) = rName;
+}
+
+// -----------------------------------------------------------------------
+
+UniString Application::GetDisplayName()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maAppData.mpDisplayName )
+ return *(pSVData->maAppData.mpDisplayName);
+ else if ( pSVData->maWinData.mpAppWin )
+ return pSVData->maWinData.mpAppWin->GetText();
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+unsigned int Application::GetScreenCount()
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->GetDisplayScreenCount() : 0;
+}
+
+rtl::OUString Application::GetScreenName( unsigned int nScreen )
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->GetScreenName( nScreen ) : rtl::OUString();
+}
+
+bool Application::IsMultiDisplay()
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->IsMultiDisplay() : false;
+}
+
+unsigned int Application::GetDefaultDisplayNumber()
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->GetDefaultDisplayNumber() : 0;
+}
+
+Rectangle Application::GetScreenPosSizePixel( unsigned int nScreen )
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->GetDisplayScreenPosSizePixel( nScreen ) : Rectangle();
+}
+
+Rectangle Application::GetWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->GetDisplayWorkAreaPosSizePixel( nScreen ) : Rectangle();
+}
+
+namespace {
+unsigned long calcDistSquare( const Point& i_rPoint, const Rectangle& i_rRect )
+{
+ const Point aRectCenter( (i_rRect.Left() + i_rRect.Right())/2,
+ (i_rRect.Top() + i_rRect.Bottom())/ 2 );
+ const long nDX = aRectCenter.X() - i_rPoint.X();
+ const long nDY = aRectCenter.Y() - i_rPoint.Y();
+ return nDX*nDX + nDY*nDY;
+}
+}
+
+unsigned int Application::GetBestScreen( const Rectangle& i_rRect )
+{
+ if( IsMultiDisplay() )
+ return GetDefaultDisplayNumber();
+
+ const unsigned int nScreens = GetScreenCount();
+ unsigned int nBestMatchScreen = 0;
+ unsigned long nOverlap = 0;
+ for( unsigned int i = 0; i < nScreens; i++ )
+ {
+ const Rectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
+ // if a screen contains the rectangle completely it is obviously the best screen
+ if( aCurScreenRect.IsInside( i_rRect ) )
+ return i;
+ // next the screen which contains most of the area of the rect is the best
+ Rectangle aIntersection( aCurScreenRect.GetIntersection( i_rRect ) );
+ if( ! aIntersection.IsEmpty() )
+ {
+ const unsigned long nCurOverlap( aIntersection.GetWidth() * aIntersection.GetHeight() );
+ if( nCurOverlap > nOverlap )
+ {
+ nOverlap = nCurOverlap;
+ nBestMatchScreen = i;
+ }
+ }
+ }
+ if( nOverlap > 0 )
+ return nBestMatchScreen;
+
+ // finally the screen which center is nearest to the rect is the best
+ const Point aCenter( (i_rRect.Left() + i_rRect.Right())/2,
+ (i_rRect.Top() + i_rRect.Bottom())/2 );
+ unsigned long nDist = ULONG_MAX;
+ for( unsigned int i = 0; i < nScreens; i++ )
+ {
+ const Rectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
+ const unsigned long nCurDist( calcDistSquare( aCenter, aCurScreenRect ) );
+ if( nCurDist < nDist )
+ {
+ nBestMatchScreen = i;
+ nDist = nCurDist;
+ }
+ }
+ return nBestMatchScreen;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::InsertAccel( Accelerator* pAccel )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( !pSVData->maAppData.mpAccelMgr )
+ pSVData->maAppData.mpAccelMgr = new ImplAccelManager();
+ return pSVData->maAppData.mpAccelMgr->InsertAccel( pAccel );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveAccel( Accelerator* pAccel )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maAppData.mpAccelMgr )
+ pSVData->maAppData.mpAccelMgr->RemoveAccel( pAccel );
+}
+
+// -----------------------------------------------------------------------
+
+void Application::FlushAccel()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maAppData.mpAccelMgr )
+ pSVData->maAppData.mpAccelMgr->FlushAccel();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::CallAccel( const KeyCode& rKeyCode, USHORT nRepeat )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maAppData.mpAccelMgr )
+ {
+ if ( pSVData->maAppData.mpAccelMgr->IsAccelKey( rKeyCode, nRepeat ) )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetHelp( Help* pHelp )
+{
+ ImplGetSVData()->maAppData.mpHelp = pHelp;
+}
+
+// -----------------------------------------------------------------------
+
+Help* Application::GetHelp()
+{
+ return ImplGetSVData()->maAppData.mpHelp;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::EnableAutoHelpId( BOOL bEnabled )
+{
+ ImplGetSVData()->maHelpData.mbAutoHelpId = bEnabled;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsAutoHelpIdEnabled()
+{
+ return ImplGetSVData()->maHelpData.mbAutoHelpId;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::EnableAutoMnemonic( BOOL bEnabled )
+{
+ AllSettings aSettings = GetSettings();
+ StyleSettings aStyle = aSettings.GetStyleSettings();
+ aStyle.SetAutoMnemonic( bEnabled );
+ aSettings.SetStyleSettings( aStyle );
+ SetSettings( aSettings );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsAutoMnemonicEnabled()
+{
+ return GetSettings().GetStyleSettings().GetAutoMnemonic();
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetDialogScaleX( short nScale )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mnDialogScaleX = nScale;
+ pSVData->maGDIData.mnAppFontX = pSVData->maGDIData.mnRealAppFontX;
+ if ( nScale )
+ pSVData->maGDIData.mnAppFontX += (pSVData->maGDIData.mnAppFontX*nScale)/100;
+}
+
+// -----------------------------------------------------------------------
+
+short Application::GetDialogScaleX()
+{
+ return ImplGetSVData()->maAppData.mnDialogScaleX;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetDefDialogParent( Window* pWindow )
+{
+ ImplGetSVData()->maWinData.mpDefDialogParent = pWindow;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Application::GetDefDialogParent()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ // #103442# find some useful dialog parent if there
+ // was no default set
+ // NOTE: currently even the default is not used
+ if( FALSE && pSVData->maWinData.mpDefDialogParent != NULL )
+ return pSVData->maWinData.mpDefDialogParent;
+ else
+ {
+ // always use the topmost parent of the candidate
+ // window to avoid using dialogs or floaters
+ // as DefDialogParent
+
+ // current focus frame
+ Window *pWin = NULL;
+ if( (pWin = pSVData->maWinData.mpFocusWin) != NULL )
+ {
+ while( pWin->mpWindowImpl && pWin->mpWindowImpl->mpParent )
+ pWin = pWin->mpWindowImpl->mpParent;
+
+ if( (pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0 )
+ {
+ // check for corrupted window hierarchy, #122232#, may be we now crash somewhere else
+ if( !pWin->mpWindowImpl )
+ {
+ DBG_ERROR( "Window hierarchy corrupted!" );
+ pSVData->maWinData.mpFocusWin = NULL; // avoid further access
+ return NULL;
+ }
+
+ // MAV: before the implementation has used only decorated windows,
+ // but it is not true in case of ActiveX or plugin scenario,
+ // so this check is commented out
+ // if( pWin->mpWindowImpl->mpFrameWindow->GetStyle() & (WB_MOVEABLE | WB_SIZEABLE) )
+ return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
+ // else
+ // return NULL;
+ }
+ }
+ // last active application frame
+ if( NULL != (pWin = pSVData->maWinData.mpActiveApplicationFrame) )
+ {
+ return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
+ }
+ else
+ {
+ // first visible top window (may be totally wrong....)
+ pWin = pSVData->maWinData.mpFirstFrame;
+ while( pWin )
+ {
+ if( pWin->ImplGetWindow()->IsTopWindow() &&
+ pWin->mpWindowImpl->mbReallyVisible &&
+ (pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0
+ )
+ {
+ while( pWin->mpWindowImpl->mpParent )
+ pWin = pWin->mpWindowImpl->mpParent;
+ return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
+ }
+ pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ // use the desktop
+ return NULL;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Application::EnableDialogCancel( BOOL bDialogCancel )
+{
+ ImplGetSVData()->maAppData.mbDialogCancel = bDialogCancel;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsDialogCancelEnabled()
+{
+ return ImplGetSVData()->maAppData.mbDialogCancel;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetSystemWindowMode( USHORT nMode )
+{
+ ImplGetSVData()->maAppData.mnSysWinMode = nMode;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Application::GetSystemWindowMode()
+{
+ return ImplGetSVData()->maAppData.mnSysWinMode;
+}
+
+// -----------------------------------------------------------------------
+
+const String& Application::GetFontPath()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( !pSVData->maAppData.mpFontPath )
+ {
+ if( const char* pFontPath = ::getenv( "SAL_FONTPATH_PRIVATE" ) )
+ pSVData->maAppData.mpFontPath = new String( String::CreateFromAscii( pFontPath ) );
+ }
+
+ if( pSVData->maAppData.mpFontPath )
+ return *(pSVData->maAppData.mpFontPath);
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetFontPath( const String& rPath )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // if it doesn't exist create a new one
+ if( !pSVData->maAppData.mpFontPath )
+ pSVData->maAppData.mpFontPath = new String( rPath );
+ else
+ *(pSVData->maAppData.mpFontPath) = rPath;
+}
+
+// -----------------------------------------------------------------------
+
+UniqueItemId Application::CreateUniqueId()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( !pSVData->maAppData.mpUniqueIdCont )
+ pSVData->maAppData.mpUniqueIdCont = new UniqueIdContainer( UNIQUEID_SV_BEGIN );
+ return pSVData->maAppData.mpUniqueIdCont->CreateId();
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit > Application::GetVCLToolkit()
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit > xT;
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper( TRUE );
+ if ( pWrapper )
+ xT = pWrapper->GetVCLToolkit();
+ return xT;
+}
+
+// -----------------------------------------------------------------------
+
+extern "C" { static void SAL_CALL thisModule() {} }
+
+UnoWrapperBase* Application::GetUnoWrapper( BOOL bCreateIfNotExist )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ static BOOL bAlreadyTriedToCreate = FALSE;
+ if ( !pSVData->mpUnoWrapper && bCreateIfNotExist && !bAlreadyTriedToCreate )
+ {
+ ::rtl::OUString aLibName = ::vcl::unohelper::CreateLibraryName( "tk", TRUE );
+ oslModule hTkLib = osl_loadModuleRelative(
+ &thisModule, aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if ( hTkLib )
+ {
+ ::rtl::OUString aFunctionName( RTL_CONSTASCII_USTRINGPARAM( "CreateUnoWrapper" ) );
+ FN_TkCreateUnoWrapper fnCreateWrapper = (FN_TkCreateUnoWrapper)osl_getFunctionSymbol( hTkLib, aFunctionName.pData );
+ if ( fnCreateWrapper )
+ {
+ pSVData->mpUnoWrapper = fnCreateWrapper();
+ }
+ }
+ DBG_ASSERT( pSVData->mpUnoWrapper, "UnoWrapper could not be created!" );
+ bAlreadyTriedToCreate = TRUE;
+ }
+ return pSVData->mpUnoWrapper;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetUnoWrapper( UnoWrapperBase* pWrapper )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ DBG_ASSERT( !pSVData->mpUnoWrapper, "SetUnoWrapper: Wrapper allready exists" );
+ pSVData->mpUnoWrapper = pWrapper;
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::awt::XDisplayConnection > Application::GetDisplayConnection()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if( !pSVData->mxDisplayConnection.is() )
+ pSVData->mxDisplayConnection.set( new ::vcl::DisplayConnection );
+
+ return pSVData->mxDisplayConnection;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::SetFilterHdl( const Link& rLink )
+{
+ ImplGetSVData()->maGDIData.mpGrfConverter->SetFilterHdl( rLink );
+}
+
+// -----------------------------------------------------------------------
+
+const Link& Application::GetFilterHdl()
+{
+ return ImplGetSVData()->maGDIData.mpGrfConverter->GetFilterHdl();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplCallHotKey( const KeyCode& rKeyCode )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplHotKey* pHotKeyData = pSVData->maAppData.mpFirstHotKey;
+ while ( pHotKeyData )
+ {
+ if ( pHotKeyData->maKeyCode.IsDefinedKeyCodeEqual( rKeyCode ) )
+ {
+ pHotKeyData->maLink.Call( pHotKeyData->mpUserData );
+ return TRUE;
+ }
+
+ pHotKeyData = pHotKeyData->mpNext;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFreeHotKeyData()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplHotKey* pTempHotKeyData;
+ ImplHotKey* pHotKeyData = pSVData->maAppData.mpFirstHotKey;
+ while ( pHotKeyData )
+ {
+ pTempHotKeyData = pHotKeyData->mpNext;
+ delete pHotKeyData;
+ pHotKeyData = pTempHotKeyData;
+ }
+
+ pSVData->maAppData.mpFirstHotKey = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Application::AddHotKey( const KeyCode& rKeyCode, const Link& rLink, void* pData )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplHotKey* pHotKeyData = new ImplHotKey;
+ pHotKeyData->mpUserData = pData;
+ pHotKeyData->maKeyCode = rKeyCode;
+ pHotKeyData->maLink = rLink;
+ pHotKeyData->mpNext = pSVData->maAppData.mpFirstHotKey;
+ pSVData->maAppData.mpFirstHotKey = pHotKeyData;
+ return (ULONG)pHotKeyData;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveHotKey( ULONG nId )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplHotKey* pFindHotKeyData = (ImplHotKey*)nId;
+ ImplHotKey* pPrevHotKeyData = NULL;
+ ImplHotKey* pHotKeyData = pSVData->maAppData.mpFirstHotKey;
+ while ( pHotKeyData )
+ {
+ if ( pHotKeyData == pFindHotKeyData )
+ {
+ if ( pPrevHotKeyData )
+ pPrevHotKeyData->mpNext = pFindHotKeyData->mpNext;
+ else
+ pSVData->maAppData.mpFirstHotKey = pFindHotKeyData->mpNext;
+ delete pFindHotKeyData;
+ break;
+ }
+
+ pPrevHotKeyData = pHotKeyData;
+ pHotKeyData = pHotKeyData->mpNext;
+ }
+
+ DBG_ASSERT( pHotKeyData, "Application::RemoveHotKey() - HotKey is not added" );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFreeEventHookData()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplEventHook* pTempEventHookData;
+ ImplEventHook* pEventHookData = pSVData->maAppData.mpFirstEventHook;
+ while ( pEventHookData )
+ {
+ pTempEventHookData = pEventHookData->mpNext;
+ delete pEventHookData;
+ pEventHookData = pTempEventHookData;
+ }
+
+ pSVData->maAppData.mpFirstEventHook = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Application::AddEventHook( VCLEventHookProc pProc, void* pData )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplEventHook* pEventHookData = new ImplEventHook;
+ pEventHookData->mpUserData = pData;
+ pEventHookData->mpProc = pProc;
+ pEventHookData->mpNext = pSVData->maAppData.mpFirstEventHook;
+ pSVData->maAppData.mpFirstEventHook = pEventHookData;
+ return (ULONG)pEventHookData;
+}
+
+// -----------------------------------------------------------------------
+
+void Application::RemoveEventHook( ULONG nId )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplEventHook* pFindEventHookData = (ImplEventHook*)nId;
+ ImplEventHook* pPrevEventHookData = NULL;
+ ImplEventHook* pEventHookData = pSVData->maAppData.mpFirstEventHook;
+ while ( pEventHookData )
+ {
+ if ( pEventHookData == pFindEventHookData )
+ {
+ if ( pPrevEventHookData )
+ pPrevEventHookData->mpNext = pFindEventHookData->mpNext;
+ else
+ pSVData->maAppData.mpFirstEventHook = pFindEventHookData->mpNext;
+ delete pFindEventHookData;
+ break;
+ }
+
+ pPrevEventHookData = pEventHookData;
+ pEventHookData = pEventHookData->mpNext;
+ }
+
+ DBG_ASSERT( pEventHookData, "Application::RemoveEventHook() - EventHook is not added" );
+}
+
+// -----------------------------------------------------------------------
+
+long Application::CallEventHooks( NotifyEvent& rEvt )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ long nRet = 0;
+ ImplEventHook* pTempEventHookData;
+ ImplEventHook* pEventHookData = pSVData->maAppData.mpFirstEventHook;
+ while ( pEventHookData )
+ {
+ pTempEventHookData = pEventHookData->mpNext;
+ nRet = pEventHookData->mpProc( rEvt, pEventHookData->mpUserData );
+ if ( nRet )
+ break;
+ pEventHookData = pTempEventHookData;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+long Application::CallPreNotify( NotifyEvent& rEvt )
+{
+ return ImplCallPreNotify( rEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long Application::CallEvent( NotifyEvent& rEvt )
+{
+ return ImplCallEvent( rEvt );
+}
+
+// -----------------------------------------------------------------------
+
+const LocaleDataWrapper& Application::GetAppLocaleDataWrapper()
+{
+ return GetSettings().GetLocaleDataWrapper();
+}
+
+// -----------------------------------------------------------------------
+
+void Application::EnableHeadlessMode( BOOL bEnable )
+{
+ EnableDialogCancel( bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Application::IsHeadlessModeEnabled()
+{
+ return IsDialogCancelEnabled();
+}
+
+// -----------------------------------------------------------------------
+
+void Application::ShowNativeErrorBox(const String& sTitle ,
+ const String& sMessage)
+{
+ int btn = ImplGetSalSystem()->ShowNativeMessageBox (
+ sTitle,
+ sMessage,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK);
+ if (btn != SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK) {
+ OSL_TRACE("ShowNativeMessageBox returned %d\n", btn);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool Application::CanToggleImeStatusWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->mpImeStatus )
+ pSVData->mpImeStatus = pSVData->mpDefInst->CreateI18NImeStatus();
+ return pSVData->mpImeStatus->canToggle();
+}
+
+void Application::ShowImeStatusWindow(bool bShow)
+{
+ ImplGetSVData()->maAppData.meShowImeStatusWindow = bShow
+ ? ImplSVAppData::ImeStatusWindowMode_SHOW
+ : ImplSVAppData::ImeStatusWindowMode_HIDE;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->mpImeStatus )
+ pSVData->mpImeStatus = pSVData->mpDefInst->CreateI18NImeStatus();
+ pSVData->mpImeStatus->toggle();
+}
+
+bool Application::GetShowImeStatusWindowDefault()
+{
+ rtl_TextEncodingInfo aInfo;
+ aInfo.StructSize = sizeof aInfo;
+ return rtl_getTextEncodingInfo(osl_getThreadTextEncoding(), &aInfo)
+ && aInfo.MaximumCharSize > 1;
+}
+
+const ::rtl::OUString& Application::GetDesktopEnvironment()
+{
+ return SalGetDesktopEnvironment();
+}
+
+void Application::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType)
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpDefInst->AddToRecentDocumentList(rFileUrl, rMimeType);
+}
+
+BOOL Application::IsAccessibilityEnabled()
+{
+ return FALSE;
+}
+
+BOOL InitAccessBridge( BOOL bShowCancel, BOOL &rCancelled )
+{
+ BOOL bRet = true;
+
+// Disable Java bridge on UNIX
+#if defined UNX
+ (void) bShowCancel; // unsued
+ (void) rCancelled; // unused
+#else
+ bRet = ImplInitAccessBridge( bShowCancel, rCancelled );
+
+ if( !bRet && bShowCancel && !rCancelled )
+ {
+ // disable accessibility if the user chooses to continue
+ AllSettings aSettings = Application::GetSettings();
+ MiscSettings aMisc = aSettings.GetMiscSettings();
+ aMisc.SetEnableATToolSupport( FALSE );
+ aSettings.SetMiscSettings( aMisc );
+ Application::SetSettings( aSettings );
+ }
+#endif // !UNX
+
+ return bRet;
+}
+
+// MT: AppProperty, AppEvent was in oldsv.cxx, but is still needed...
+// ------------------------------------------------------------------------
+
+TYPEINIT0(ApplicationProperty)
+
+// ------------------------------------------------------------------------
+
+static PropertyHandler* pHandler=NULL;
+
+void Application::Property( ApplicationProperty& rProp )
+{
+ if ( pHandler )
+ pHandler->Property( rProp );
+}
+
+void Application::SetPropertyHandler( PropertyHandler* p )
+{
+ if ( pHandler )
+ delete pHandler;
+ pHandler = p;
+}
+
+
+
+void Application::AppEvent( const ApplicationEvent& /*rAppEvent*/ )
+{
+}
diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx
new file mode 100644
index 000000000000..f8b0d1d3379f
--- /dev/null
+++ b/vcl/source/app/svdata.cxx
@@ -0,0 +1,537 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <string.h>
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salinst.hxx>
+#include <vcl/salframe.hxx>
+
+#ifndef _VOS_MUTEX_HXX
+#include <vos/mutex.hxx>
+#endif
+
+#include <osl/process.h>
+#include <osl/file.hxx>
+#include <uno/current_context.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <tools/debug.hxx>
+#include <unotools/fontcfg.hxx>
+#include <vcl/configsettings.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/window.h>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/unohelp.hxx>
+#include <vcl/button.hxx> // for Button::GetStandardText
+#include <vcl/dockwin.hxx> // for DockingManager
+#include <vcl/salimestatus.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/awt/XExtendedToolkit.hpp>
+#include <com/sun/star/java/JavaNotConfiguredException.hpp>
+#include <com/sun/star/java/JavaVMCreationFailureException.hpp>
+#include <com/sun/star/java/MissingJavaRuntimeException.hpp>
+#include <com/sun/star/java/JavaDisabledException.hpp>
+
+#include <com/sun/star/lang/XComponent.hpp>
+
+#include <stdio.h>
+#include <vcl/salsys.hxx>
+#include <vcl/svids.hrc>
+#include <rtl/instance.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+using namespace rtl;
+
+// =======================================================================
+
+namespace
+{
+ struct private_aImplSVData :
+ public rtl::Static<ImplSVData, private_aImplSVData> {};
+}
+
+// static SV-Data
+ImplSVData* pImplSVData = NULL;
+
+SalSystem* ImplGetSalSystem()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->mpSalSystem )
+ pSVData->mpSalSystem = pSVData->mpDefInst->CreateSalSystem();
+ return pSVData->mpSalSystem;
+}
+
+
+static String& ReplaceJavaErrorMessages( String& rString )
+{
+ rString.SearchAndReplaceAllAscii( "%OK", Button::GetStandardText( BUTTON_OK ) );
+ rString.SearchAndReplaceAllAscii( "%IGNORE", Button::GetStandardText( BUTTON_IGNORE ) );
+ rString.SearchAndReplaceAllAscii( "%CANCEL", Button::GetStandardText( BUTTON_CANCEL ) );
+
+ return rString;
+}
+
+// =======================================================================
+
+void ImplInitSVData()
+{
+ pImplSVData = &private_aImplSVData::get();
+
+ // init global instance data
+ memset( pImplSVData, 0, sizeof( ImplSVData ) );
+ pImplSVData->maHelpData.mbAutoHelpId = sal_True;
+ pImplSVData->maHelpData.mbAutoHelpId = sal_True;
+ pImplSVData->maNWFData.maMenuBarHighlightTextColor = Color( COL_TRANSPARENT );
+
+ // find out whether we are running in the testtool
+ // in this case we need some special workarounds
+ sal_uInt32 nArgs = osl_getCommandArgCount();
+ for( sal_uInt32 i = 0; i < nArgs; i++ )
+ {
+ rtl::OUString aArg;
+ osl_getCommandArg( i, &aArg.pData );
+ if( aArg.equalsAscii( "-enableautomation" ) )
+ {
+ pImplSVData->mbIsTestTool = true;
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDeInitSVData()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // delete global instance data
+ if( pSVData->mpSettingsConfigItem )
+ delete pSVData->mpSettingsConfigItem;
+
+ if( pSVData->mpDockingManager )
+ delete pSVData->mpDockingManager;
+
+ if( pSVData->maGDIData.mpDefaultFontConfiguration )
+ delete pSVData->maGDIData.mpDefaultFontConfiguration;
+ if( pSVData->maGDIData.mpFontSubstConfiguration )
+ delete pSVData->maGDIData.mpFontSubstConfiguration;
+
+ if ( pSVData->maAppData.mpMSFTempFileName )
+ {
+ if ( pSVData->maAppData.mxMSF.is() )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > xComp( pSVData->maAppData.mxMSF, ::com::sun::star::uno::UNO_QUERY );
+ xComp->dispose();
+ pSVData->maAppData.mxMSF = NULL;
+ }
+
+ ::rtl::OUString aFileUrl;
+ ::osl::File::getFileURLFromSystemPath( *pSVData->maAppData.mpMSFTempFileName, aFileUrl );
+ osl::File::remove( aFileUrl );
+ delete pSVData->maAppData.mpMSFTempFileName;
+ pSVData->maAppData.mpMSFTempFileName = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDestroySVData()
+{
+ pImplSVData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Window* ImplGetDefaultWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpAppWin )
+ return pSVData->maWinData.mpAppWin;
+
+ // First test if we already have a default window.
+ // Don't only place a single if..else inside solar mutex lockframe
+ // because then we might have to wait for the solar mutex what is not neccessary
+ // if we already have a default window.
+
+ if ( !pSVData->mpDefaultWin )
+ {
+ Application::GetSolarMutex().acquire();
+
+ // Test again because the thread who released the solar mutex could have called
+ // the same method
+
+ if ( !pSVData->mpDefaultWin && !pSVData->mbDeInit )
+ {
+ DBG_WARNING( "ImplGetDefaultWindow(): No AppWindow" );
+ pSVData->mpDefaultWin = new WorkWindow( 0, WB_DEFAULTWIN );
+ pSVData->mpDefaultWin->SetText( OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL ImplGetDefaultWindow" ) ) );
+ }
+ Application::GetSolarMutex().release();
+ }
+
+ return pSVData->mpDefaultWin;
+}
+
+// -----------------------------------------------------------------------
+
+#define VCL_CREATERESMGR_NAME( Name ) #Name
+
+ResMgr* ImplGetResMgr()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->mpResMgr )
+ {
+ ::com::sun::star::lang::Locale aLocale = Application::GetSettings().GetUILocale();
+ pSVData->mpResMgr = ResMgr::SearchCreateResMgr( VCL_CREATERESMGR_NAME( vcl ), aLocale );
+
+ static bool bMessageOnce = false;
+ if( !pSVData->mpResMgr && ! bMessageOnce )
+ {
+ bMessageOnce = true;
+ const char* pMsg =
+ "Missing vcl resource. This indicates that files vital to localization are missing. "
+ "You might have a corrupt installation.";
+ fprintf( stderr, "%s\n", pMsg );
+ ErrorBox aBox( NULL, WB_OK | WB_DEF_OK, rtl::OUString( pMsg, strlen( pMsg ), RTL_TEXTENCODING_ASCII_US ) );
+ aBox.Execute();
+ }
+ }
+ return pSVData->mpResMgr;
+}
+
+ResId VclResId( sal_Int32 nId )
+{
+ ResMgr* pMgr = ImplGetResMgr();
+ if( ! pMgr )
+ throw std::bad_alloc();
+
+ return ResId( nId, *pMgr );
+}
+
+DockingManager* ImplGetDockingManager()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->mpDockingManager )
+ pSVData->mpDockingManager = new DockingManager();
+
+ return pSVData->mpDockingManager;
+}
+
+class AccessBridgeCurrentContext: public cppu::WeakImplHelper1< com::sun::star::uno::XCurrentContext >
+{
+public:
+ AccessBridgeCurrentContext(
+ const com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > &context ) :
+ m_prevContext( context ) {}
+
+ // XCurrentContext
+ virtual com::sun::star::uno::Any SAL_CALL getValueByName( const rtl::OUString& Name )
+ throw (com::sun::star::uno::RuntimeException);
+private:
+ com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > m_prevContext;
+};
+
+com::sun::star::uno::Any AccessBridgeCurrentContext::getValueByName( const rtl::OUString & Name )
+ throw (com::sun::star::uno::RuntimeException)
+{
+ com::sun::star::uno::Any ret;
+ if( Name.equalsAscii( "java-vm.interaction-handler" ) )
+ {
+ // Currently, for accessbility no interaction handler shall be offered.
+ // There may be introduced later on a handler using native toolkits
+ // jbu->obr: Instantiate here your interaction handler
+ }
+ else if( m_prevContext.is() )
+ {
+ ret = m_prevContext->getValueByName( Name );
+ }
+ return ret;
+}
+
+
+bool ImplInitAccessBridge(BOOL bAllowCancel, BOOL &rCancelled)
+{
+ rCancelled = FALSE;
+
+ bool bErrorMessage = true;
+
+ // Note:
+ // if bAllowCancel is TRUE we were called from application startup
+ // where we will disable any Java errorboxes and show our own accessibility dialog if Java throws an exception
+ // if bAllowCancel is FALSE we were called from Tools->Options
+ // where we will see Java errorboxes, se we do not show our dialogs in addition to Java's
+
+ try
+ {
+ bool bSuccess = true;
+
+ // No error messages when env var is set ..
+ static const char* pEnv = getenv("SAL_ACCESSIBILITY_ENABLED" );
+ if( pEnv && *pEnv )
+ {
+ bErrorMessage = false;
+ }
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->mxAccessBridge.is() )
+ {
+ Reference< XMultiServiceFactory > xFactory(vcl::unohelper::GetMultiServiceFactory());
+
+ if( xFactory.is() )
+ {
+ Reference< XExtendedToolkit > xToolkit =
+ Reference< XExtendedToolkit >(Application::GetVCLToolkit(), UNO_QUERY);
+
+ Sequence< Any > arguments(1);
+ arguments[0] = makeAny(xToolkit);
+
+ // Disable default java error messages on startup, because they were probably unreadable
+ // for a disabled user. Use native message boxes which are accessible without java support.
+ // No need to do this when activated by Tools-Options dialog ..
+ if( bAllowCancel )
+ {
+ // customize the java-not-available-interaction-handler entry within the
+ // current context when called at startup.
+ com::sun::star::uno::ContextLayer layer(
+ new AccessBridgeCurrentContext( com::sun::star::uno::getCurrentContext() ) );
+
+ pSVData->mxAccessBridge = xFactory->createInstanceWithArguments(
+ OUString::createFromAscii( "com.sun.star.accessibility.AccessBridge" ),
+ arguments
+ );
+ }
+ else
+ {
+ pSVData->mxAccessBridge = xFactory->createInstanceWithArguments(
+ OUString::createFromAscii( "com.sun.star.accessibility.AccessBridge" ),
+ arguments
+ );
+ }
+
+ if( !pSVData->mxAccessBridge.is() )
+ bSuccess = false;
+ }
+ }
+
+ return bSuccess;
+ }
+
+ catch(::com::sun::star::java::JavaNotConfiguredException e)
+ {
+ ResMgr *pResMgr = ImplGetResMgr();
+ if( bErrorMessage && bAllowCancel && pResMgr )
+ {
+ String aTitle(ResId(SV_ACCESSERROR_JAVA_NOT_CONFIGURED, *pResMgr));
+ String aMessage(ResId(SV_ACCESSERROR_JAVA_MSG, *pResMgr));
+
+ aMessage += String(" ", 1, RTL_TEXTENCODING_ASCII_US);
+ aMessage += String(ResId(SV_ACCESSERROR_OK_CANCEL_MSG, *pResMgr));
+
+ int ret = ImplGetSalSystem()->ShowNativeMessageBox(
+ aTitle,
+ ReplaceJavaErrorMessages(aMessage),
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL);
+
+ // Do not change the setting in case the user chooses to cancel
+ if( SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL == ret )
+ rCancelled = TRUE;
+ }
+
+ return false;
+ }
+
+ catch(::com::sun::star::java::JavaVMCreationFailureException e)
+ {
+ ResMgr *pResMgr = ImplGetResMgr();
+ if( bErrorMessage && bAllowCancel && pResMgr )
+ {
+ String aTitle(ResId(SV_ACCESSERROR_FAULTY_JAVA, *pResMgr));
+ String aMessage(ResId(SV_ACCESSERROR_JAVA_MSG, *pResMgr));
+
+ aMessage += String(" ", 1, RTL_TEXTENCODING_ASCII_US);
+ aMessage += String(ResId(SV_ACCESSERROR_OK_CANCEL_MSG, *pResMgr));
+
+ int ret = ImplGetSalSystem()->ShowNativeMessageBox(
+ aTitle,
+ ReplaceJavaErrorMessages(aMessage),
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL);
+
+ // Do not change the setting in case the user chooses to cancel
+ if( SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL == ret )
+ rCancelled = TRUE;
+ }
+
+ return false;
+ }
+
+ catch(::com::sun::star::java::MissingJavaRuntimeException e)
+ {
+ ResMgr *pResMgr = ImplGetResMgr();
+ if( bErrorMessage && bAllowCancel && pResMgr )
+ {
+ String aTitle(ResId(SV_ACCESSERROR_MISSING_JAVA, *pResMgr));
+ String aMessage(ResId(SV_ACCESSERROR_JAVA_MSG, *pResMgr));
+
+ aMessage += String(" ", 1, RTL_TEXTENCODING_ASCII_US);
+ aMessage += String(ResId(SV_ACCESSERROR_OK_CANCEL_MSG, *pResMgr));
+
+ int ret = ImplGetSalSystem()->ShowNativeMessageBox(
+ aTitle,
+ ReplaceJavaErrorMessages(aMessage),
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL);
+
+ // Do not change the setting in case the user chooses to cancel
+ if( SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL == ret )
+ rCancelled = TRUE;
+ }
+
+ return false;
+ }
+
+ catch(::com::sun::star::java::JavaDisabledException e)
+ {
+ ResMgr *pResMgr = ImplGetResMgr();
+ if( bErrorMessage && bAllowCancel && pResMgr )
+ {
+ String aTitle(ResId(SV_ACCESSERROR_JAVA_DISABLED, *pResMgr));
+ String aMessage(ResId(SV_ACCESSERROR_JAVA_MSG, *pResMgr));
+
+ aMessage += String(" ", 1, RTL_TEXTENCODING_ASCII_US);
+ aMessage += String(ResId(SV_ACCESSERROR_OK_CANCEL_MSG, *pResMgr));
+
+ int ret = ImplGetSalSystem()->ShowNativeMessageBox(
+ aTitle,
+ ReplaceJavaErrorMessages(aMessage),
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL);
+
+ // Do not change the setting in case the user chooses to cancel
+ if( SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL == ret )
+ rCancelled = TRUE;
+ }
+
+ return false;
+ }
+
+
+ catch(::com::sun::star::uno::RuntimeException e)
+ {
+ ResMgr *pResMgr = ImplGetResMgr();
+ if( bErrorMessage && pResMgr )
+ {
+ String aTitle;
+ String aMessage(ResId(SV_ACCESSERROR_BRIDGE_MSG, *pResMgr));
+
+ if( 0 == e.Message.compareTo(::rtl::OUString::createFromAscii("ClassNotFound"), 13) )
+ {
+ aTitle = String(ResId(SV_ACCESSERROR_MISSING_BRIDGE, *pResMgr));
+ }
+ else if( 0 == e.Message.compareTo(::rtl::OUString::createFromAscii("NoSuchMethod"), 12) )
+ {
+ aTitle = String(ResId(SV_ACCESSERROR_WRONG_VERSION, *pResMgr));
+ }
+
+ if( aTitle.Len() != 0 )
+ {
+ if( bAllowCancel )
+ {
+ // Something went wrong initializing the Java AccessBridge (on Windows) during the
+ // startup. Since the office will be probably unusable for a disabled user, we offer
+ // to terminate directly.
+ aMessage += String(" ", 1, RTL_TEXTENCODING_ASCII_US);
+ aMessage += String(ResId(SV_ACCESSERROR_OK_CANCEL_MSG, *pResMgr));
+
+ int ret = ImplGetSalSystem()->ShowNativeMessageBox(
+ aTitle,
+ ReplaceJavaErrorMessages(aMessage),
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL);
+
+ // Do not change the setting in case the user chooses to cancel
+ if( SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL == ret )
+ rCancelled = TRUE;
+ }
+ else
+ {
+ // The user tried to activate accessibility support using Tools-Options dialog,
+ // so we don't offer to terminate here !
+ ImplGetSalSystem()->ShowNativeMessageBox(
+ aTitle,
+ ReplaceJavaErrorMessages(aMessage),
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK,
+ SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ catch (...)
+ {
+ return false;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Window* ImplFindWindow( const SalFrame* pFrame, Point& rSalFramePos )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pFrameWindow = pSVData->maWinData.mpFirstFrame;
+ while ( pFrameWindow )
+ {
+ if ( pFrameWindow->ImplGetFrame() == pFrame )
+ {
+ Window* pWindow = pFrameWindow->ImplFindWindow( rSalFramePos );
+ if ( !pWindow )
+ pWindow = pFrameWindow->ImplGetWindow();
+ rSalFramePos = pWindow->ImplFrameToOutput( rSalFramePos );
+ return pWindow;
+ }
+ pFrameWindow = pFrameWindow->ImplGetFrameData()->mpNextFrame;
+ }
+
+ return NULL;
+}
+
+void LocaleConfigurationListener::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 nHint )
+{
+ AllSettings::LocaleSettingsChanged( nHint );
+}
+
diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx
new file mode 100644
index 000000000000..4efa2b659e7c
--- /dev/null
+++ b/vcl/source/app/svmain.cxx
@@ -0,0 +1,638 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifdef WNT
+#include <tools/prewin.h>
+#include <process.h> // for _beginthreadex
+#include <ole2.h> // for _beginthreadex
+#include <tools/postwin.h>
+#endif
+
+// [ed 5/14/02 Add in explicit check for quartz graphics. OS X will define
+// unx for both quartz and X11 graphics, but we include svunx.h only if we're
+// building X11 graphics layers.
+
+#if defined UNX && ! defined QUARTZ
+#include "svunx.h"
+#endif
+
+#include "svsys.h"
+#include "vcl/salinst.hxx"
+#include "vcl/salwtype.hxx"
+#include "vos/signal.hxx"
+#include "tools/tools.h"
+#include "tools/debug.hxx"
+#include "tools/unqid.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/dbggui.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/wrkwin.hxx"
+#include "vcl/cvtgrf.hxx"
+#include "vcl/image.hxx"
+#include "tools/resmgr.hxx"
+#include "vcl/accmgr.hxx"
+#include "vcl/idlemgr.hxx"
+#include "vcl/outdev.h"
+#include "vcl/outfont.hxx"
+#include "vcl/print.h"
+#include "vcl/settings.hxx"
+#include "vcl/unowrap.hxx"
+#include "vcl/salsys.hxx"
+#include "vcl/saltimer.hxx"
+#include "vcl/salimestatus.hxx"
+#include "vcl/impimagetree.hxx"
+#include "vcl/xconnection.hxx"
+
+#include "vos/process.hxx"
+#include "osl/file.hxx"
+#include "comphelper/processfactory.hxx"
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/lang/XComponent.hpp"
+#include "rtl/logfile.hxx"
+#include <unotools/syslocaleoptions.hxx>
+#include "unotools/fontcfg.hxx"
+#include "vcl/configsettings.hxx"
+#include "vcl/lazydelete.hxx"
+
+#include "cppuhelper/implbase1.hxx"
+#include "uno/current_context.hxx"
+
+#if OSL_DEBUG_LEVEL > 0
+#include <typeinfo>
+#include "rtl/strbuf.hxx"
+#endif
+
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+
+
+// =======================================================================
+
+class ImplVCLExceptionHandler : public ::vos::OSignalHandler
+{
+public:
+ virtual ::vos::OSignalHandler::TSignalAction SAL_CALL signal( ::vos::OSignalHandler::TSignalInfo* pInfo );
+};
+
+// -----------------------------------------------------------------------
+
+::vos::OSignalHandler::TSignalAction SAL_CALL ImplVCLExceptionHandler::signal( ::vos::OSignalHandler::TSignalInfo* pInfo )
+{
+ static BOOL bIn = FALSE;
+
+ // Wenn wir nocheinmal abstuerzen, verabschieden wir uns gleich
+ if ( !bIn )
+ {
+ USHORT nVCLException = 0;
+
+ // UAE
+ if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
+ (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
+ (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
+ (pInfo->Signal == osl_Signal_DebugBreak) )
+ nVCLException = EXC_SYSTEM;
+
+ // RC
+ if ((pInfo->Signal == osl_Signal_User) &&
+ (pInfo->UserSignal == OSL_SIGNAL_USER_RESOURCEFAILURE) )
+ nVCLException = EXC_RSCNOTLOADED;
+
+ // DISPLAY-Unix
+ if ((pInfo->Signal == osl_Signal_User) &&
+ (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
+ nVCLException = EXC_DISPLAY;
+
+ // Remote-Client
+ if ((pInfo->Signal == osl_Signal_User) &&
+ (pInfo->UserSignal == OSL_SIGNAL_USER_RVPCONNECTIONERROR) )
+ nVCLException = EXC_REMOTE;
+
+ if ( nVCLException )
+ {
+ bIn = TRUE;
+
+ ::vos::OGuard aLock(&Application::GetSolarMutex());
+
+ // Timer nicht mehr anhalten, da ansonsten die UAE-Box
+ // auch nicht mehr gepaintet wird
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->mpApp )
+ {
+ USHORT nOldMode = Application::GetSystemWindowMode();
+ Application::SetSystemWindowMode( nOldMode & ~SYSTEMWINDOW_MODE_NOAUTOMODE );
+ pSVData->mpApp->Exception( nVCLException );
+ Application::SetSystemWindowMode( nOldMode );
+ }
+ bIn = FALSE;
+
+ return vos::OSignalHandler::TAction_CallNextHandler;
+ }
+ }
+
+ return vos::OSignalHandler::TAction_CallNextHandler;
+}
+
+// =======================================================================
+BOOL ImplSVMain()
+{
+ // The 'real' SVMain()
+ RTL_LOGFILE_CONTEXT( aLog, "vcl (ss112471) ::SVMain" );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ DBG_ASSERT( pSVData->mpApp, "no instance of class Application" );
+
+ Reference<XMultiServiceFactory> xMS;
+
+
+ BOOL bInit = InitVCL( xMS );
+
+ if( bInit )
+ {
+ // Application-Main rufen
+ pSVData->maAppData.mbInAppMain = TRUE;
+ pSVData->mpApp->Main();
+ pSVData->maAppData.mbInAppMain = FALSE;
+ }
+
+ if( pSVData->mxDisplayConnection.is() )
+ {
+ vcl::DisplayConnection* pConnection =
+ dynamic_cast<vcl::DisplayConnection*>(pSVData->mxDisplayConnection.get());
+
+ if( pConnection )
+ pConnection->dispatchDowningEvent();
+ pSVData->mxDisplayConnection.clear();
+ }
+
+ // This is a hack to work around the problem of the asynchronous nature
+ // of bridging accessibility through Java: on shutdown there might still
+ // be some events in the AWT EventQueue, which need the SolarMutex which
+ // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
+ // here ..
+ Reference< XComponent > xComponent(pSVData->mxAccessBridge, UNO_QUERY);
+ if( xComponent.is() )
+ {
+ ULONG nCount = Application::ReleaseSolarMutex();
+ xComponent->dispose();
+ Application::AcquireSolarMutex(nCount);
+ pSVData->mxAccessBridge.clear();
+ }
+
+ DeInitVCL();
+ return bInit;
+}
+
+BOOL SVMain()
+{
+ // #i47888# allow for alternative initialization as required for e.g. MacOSX
+ extern BOOL ImplSVMainHook( BOOL* );
+
+ BOOL bInit;
+ if( ImplSVMainHook( &bInit ) )
+ return bInit;
+ else
+ return ImplSVMain();
+}
+// This variable is set, when no Application object is instantiated
+// before SVInit is called
+static Application * pOwnSvApp = NULL;
+// Exception handler. pExceptionHandler != NULL => VCL already inited
+ImplVCLExceptionHandler * pExceptionHandler = NULL;
+
+class Application_Impl : public Application
+{
+public:
+ void Main(){};
+};
+
+class DesktopEnvironmentContext: public cppu::WeakImplHelper1< com::sun::star::uno::XCurrentContext >
+{
+public:
+ DesktopEnvironmentContext( const com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > & ctx)
+ : m_xNextContext( ctx ) {}
+
+ // XCurrentContext
+ virtual com::sun::star::uno::Any SAL_CALL getValueByName( const rtl::OUString& Name )
+ throw (com::sun::star::uno::RuntimeException);
+
+private:
+ com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > m_xNextContext;
+};
+
+Any SAL_CALL DesktopEnvironmentContext::getValueByName( const rtl::OUString& Name) throw (RuntimeException)
+{
+ Any retVal;
+
+ if ( 0 == Name.compareToAscii( "system.desktop-environment" ) )
+ {
+ retVal = makeAny( Application::GetDesktopEnvironment() );
+ }
+ else if( m_xNextContext.is() )
+ {
+ // Call next context in chain if found
+ retVal = m_xNextContext->getValueByName( Name );
+ }
+ return retVal;
+}
+
+BOOL InitVCL( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & rSMgr )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "vcl (ss112471) ::InitVCL" );
+
+ if( pExceptionHandler != NULL )
+ return FALSE;
+
+ if( ! ImplGetSVData() )
+ ImplInitSVData();
+
+ if( !ImplGetSVData()->mpApp )
+ {
+ pOwnSvApp = new Application_Impl();
+ }
+ InitSalMain();
+
+ /*AllSettings aAS;
+ Application::SetSettings( aAS );// ???
+ */
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // SV bei den Tools anmelden
+ InitTools();
+
+ DBG_ASSERT( !pSVData->maAppData.mxMSF.is(), "VCL service factory already set" );
+ pSVData->maAppData.mxMSF = rSMgr;
+
+ // Main-Thread-Id merken
+ pSVData->mnMainThreadId = ::vos::OThread::getCurrentIdentifier();
+
+ vos::OStartupInfo aStartInfo;
+ rtl::OUString aExeFileName;
+
+
+ // Sal initialisieren
+ RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ ::CreateSalInstance" );
+ pSVData->mpDefInst = CreateSalInstance();
+ if ( !pSVData->mpDefInst )
+ return FALSE;
+ RTL_LOGFILE_CONTEXT_TRACE( aLog, "} ::CreateSalInstance" );
+
+ // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
+ com::sun::star::uno::setCurrentContext(
+ new DesktopEnvironmentContext( com::sun::star::uno::getCurrentContext() ) );
+
+ // Initialize application instance (should be done after initialization of VCL SAL part)
+ if( pSVData->mpApp )
+ // call init to initialize application class
+ // soffice/sfx implementation creates the global service manager
+ pSVData->mpApp->Init();
+
+ // Den AppFileName gleich holen und absolut machen, bevor das
+ // WorkingDirectory sich aendert...
+ aStartInfo.getExecutableFile( aExeFileName );
+
+ // convert path to native file format
+ rtl::OUString aNativeFileName;
+ osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
+ pSVData->maAppData.mpAppFileName = new String( aNativeFileName );
+
+ // Initialize global data
+ pSVData->maGDIData.mpScreenFontList = new ImplDevFontList;
+ pSVData->maGDIData.mpScreenFontCache = new ImplFontCache( FALSE );
+ pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
+
+ // Exception-Handler setzen
+ pExceptionHandler = new ImplVCLExceptionHandler();
+
+ // Debug-Daten initialisieren
+ DBGGUI_INIT();
+
+ return TRUE;
+}
+
+void DeInitVCL()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mbDeInit = TRUE;
+
+ vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
+
+ // give ime status a chance to destroy its own windows
+ delete pSVData->mpImeStatus;
+ pSVData->mpImeStatus = NULL;
+
+ #if OSL_DEBUG_LEVEL > 0
+ rtl::OStringBuffer aBuf( 256 );
+ aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
+ long nTopWindowCount = Application::GetTopWindowCount();
+ long nBadTopWindows = nTopWindowCount;
+ for( long i = 0; i < nTopWindowCount; i++ )
+ {
+ Window* pWin = Application::GetTopWindow( i );
+ // default window will be destroyed further down
+ // but may still be useful during deinit up to that point
+ if( pWin == pSVData->mpDefaultWin )
+ nBadTopWindows--;
+ else
+ {
+ aBuf.append( "text = \"" );
+ aBuf.append( rtl::OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
+ aBuf.append( "\" type = \"" );
+ aBuf.append( typeid(*pWin).name() );
+ aBuf.append( "\"\n" );
+ }
+ }
+ DBG_ASSERT( nBadTopWindows==0, aBuf.getStr() );
+ #endif
+
+ ImplImageTreeSingletonRef()->shutDown();
+
+ delete pExceptionHandler;
+ pExceptionHandler = NULL;
+
+ // Debug Daten zuruecksetzen
+ DBGGUI_DEINIT();
+
+ // free global data
+ delete pSVData->maGDIData.mpGrfConverter;
+
+ if( pSVData->mpSettingsConfigItem )
+ delete pSVData->mpSettingsConfigItem, pSVData->mpSettingsConfigItem = NULL;
+ if( pSVData->maGDIData.mpDefaultFontConfiguration )
+ delete pSVData->maGDIData.mpDefaultFontConfiguration, pSVData->maGDIData.mpDefaultFontConfiguration = NULL;
+ if( pSVData->maGDIData.mpFontSubstConfiguration )
+ delete pSVData->maGDIData.mpFontSubstConfiguration, pSVData->maGDIData.mpFontSubstConfiguration = NULL;
+
+ if ( pSVData->maAppData.mpIdleMgr )
+ delete pSVData->maAppData.mpIdleMgr;
+ Timer::ImplDeInitTimer();
+
+ if ( pSVData->maWinData.mpMsgBoxImgList )
+ {
+ delete pSVData->maWinData.mpMsgBoxImgList;
+ pSVData->maWinData.mpMsgBoxImgList = NULL;
+ }
+ if ( pSVData->maWinData.mpMsgBoxHCImgList )
+ {
+ delete pSVData->maWinData.mpMsgBoxHCImgList;
+ pSVData->maWinData.mpMsgBoxHCImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpCheckImgList )
+ {
+ delete pSVData->maCtrlData.mpCheckImgList;
+ pSVData->maCtrlData.mpCheckImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpRadioImgList )
+ {
+ delete pSVData->maCtrlData.mpRadioImgList;
+ pSVData->maCtrlData.mpRadioImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpPinImgList )
+ {
+ delete pSVData->maCtrlData.mpPinImgList;
+ pSVData->maCtrlData.mpPinImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpSplitHPinImgList )
+ {
+ delete pSVData->maCtrlData.mpSplitHPinImgList;
+ pSVData->maCtrlData.mpSplitHPinImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpSplitVPinImgList )
+ {
+ delete pSVData->maCtrlData.mpSplitVPinImgList;
+ pSVData->maCtrlData.mpSplitVPinImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpSplitHArwImgList )
+ {
+ delete pSVData->maCtrlData.mpSplitHArwImgList;
+ pSVData->maCtrlData.mpSplitHArwImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpSplitVArwImgList )
+ {
+ delete pSVData->maCtrlData.mpSplitVArwImgList;
+ pSVData->maCtrlData.mpSplitVArwImgList = NULL;
+ }
+ if ( pSVData->maCtrlData.mpDisclosurePlus )
+ {
+ delete pSVData->maCtrlData.mpDisclosurePlus;
+ pSVData->maCtrlData.mpDisclosurePlus = NULL;
+ }
+ if ( pSVData->maCtrlData.mpDisclosurePlusHC )
+ {
+ delete pSVData->maCtrlData.mpDisclosurePlusHC;
+ pSVData->maCtrlData.mpDisclosurePlusHC = NULL;
+ }
+ if ( pSVData->maCtrlData.mpDisclosureMinus )
+ {
+ delete pSVData->maCtrlData.mpDisclosureMinus;
+ pSVData->maCtrlData.mpDisclosureMinus = NULL;
+ }
+ if ( pSVData->maCtrlData.mpDisclosureMinusHC )
+ {
+ delete pSVData->maCtrlData.mpDisclosureMinusHC;
+ pSVData->maCtrlData.mpDisclosureMinusHC = NULL;
+ }
+ if ( pSVData->mpDefaultWin )
+ {
+ delete pSVData->mpDefaultWin;
+ pSVData->mpDefaultWin = NULL;
+ }
+
+ // #114285# Moved here from ImplDeInitSVData...
+ if ( pSVData->mpUnoWrapper )
+ {
+ pSVData->mpUnoWrapper->Destroy();
+ pSVData->mpUnoWrapper = NULL;
+ }
+
+ pSVData->maAppData.mxMSF.clear();
+
+ if( pSVData->mpApp )
+ // call deinit to deinitialize application class
+ // soffice/sfx implementation disposes the global service manager
+ // Warning: After this call you can't call uno services
+ pSVData->mpApp->DeInit();
+
+ if ( pSVData->maAppData.mpSettings )
+ {
+ if ( pSVData->maAppData.mpCfgListener )
+ {
+ pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
+ delete pSVData->maAppData.mpCfgListener;
+ }
+
+ delete pSVData->maAppData.mpSettings;
+ pSVData->maAppData.mpSettings = NULL;
+ }
+ if ( pSVData->maAppData.mpAccelMgr )
+ {
+ delete pSVData->maAppData.mpAccelMgr;
+ pSVData->maAppData.mpAccelMgr = NULL;
+ }
+ if ( pSVData->maAppData.mpUniqueIdCont )
+ {
+ delete pSVData->maAppData.mpUniqueIdCont;
+ pSVData->maAppData.mpUniqueIdCont = NULL;
+ }
+ if ( pSVData->maAppData.mpAppFileName )
+ {
+ delete pSVData->maAppData.mpAppFileName;
+ pSVData->maAppData.mpAppFileName = NULL;
+ }
+ if ( pSVData->maAppData.mpAppName )
+ {
+ delete pSVData->maAppData.mpAppName;
+ pSVData->maAppData.mpAppName = NULL;
+ }
+ if ( pSVData->maAppData.mpDisplayName )
+ {
+ delete pSVData->maAppData.mpDisplayName;
+ pSVData->maAppData.mpDisplayName = NULL;
+ }
+ if ( pSVData->maAppData.mpEventListeners )
+ {
+ delete pSVData->maAppData.mpEventListeners;
+ pSVData->maAppData.mpEventListeners = NULL;
+ }
+ if ( pSVData->maAppData.mpKeyListeners )
+ {
+ delete pSVData->maAppData.mpKeyListeners;
+ pSVData->maAppData.mpKeyListeners = NULL;
+ }
+
+ if ( pSVData->maAppData.mpFirstHotKey )
+ ImplFreeHotKeyData();
+ if ( pSVData->maAppData.mpFirstEventHook )
+ ImplFreeEventHookData();
+
+ ImplDeletePrnQueueList();
+ delete pSVData->maGDIData.mpScreenFontList;
+ pSVData->maGDIData.mpScreenFontList = NULL;
+ delete pSVData->maGDIData.mpScreenFontCache;
+ pSVData->maGDIData.mpScreenFontCache = NULL;
+ ImplFreeOutDevFontData();
+
+ if ( pSVData->mpResMgr )
+ {
+ delete pSVData->mpResMgr;
+ pSVData->mpResMgr = NULL;
+ }
+
+ ResMgr::DestroyAllResMgr();
+
+ // destroy all Sal interfaces before destorying the instance
+ // and thereby unloading the plugin
+ delete pSVData->mpSalSystem;
+ pSVData->mpSalSystem = NULL;
+ delete pSVData->mpSalTimer;
+ pSVData->mpSalTimer = NULL;
+
+ // Sal deinitialisieren
+ DestroySalInstance( pSVData->mpDefInst );
+
+ DeInitTools();
+
+ DeInitSalMain();
+
+ if( pOwnSvApp )
+ {
+ delete pOwnSvApp;
+ pOwnSvApp = NULL;
+ }
+}
+
+// only one call is allowed
+struct WorkerThreadData
+{
+ oslWorkerFunction pWorker;
+ void * pThreadData;
+ WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
+ : pWorker( pWorker_ )
+ , pThreadData( pThreadData_ )
+ {
+ }
+};
+
+#ifdef WNT
+static HANDLE hThreadID = 0;
+static unsigned __stdcall _threadmain( void *pArgs )
+{
+ OleInitialize( NULL );
+ ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
+ delete (WorkerThreadData*)pArgs;
+ OleUninitialize();
+ hThreadID = 0;
+ return 0;
+}
+#else
+static oslThread hThreadID = 0;
+extern "C"
+{
+static void SAL_CALL MainWorkerFunction( void* pArgs )
+{
+ ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
+ delete (WorkerThreadData*)pArgs;
+ hThreadID = 0;
+}
+} // extern "C"
+#endif
+
+void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
+{
+#ifdef WNT
+ // sal thread alway call CoInitializeEx, so a sysdepen implementation is necessary
+
+ unsigned uThreadID;
+ hThreadID = (HANDLE)_beginthreadex(
+ NULL, // no security handle
+ 0, // stacksize 0 means default
+ _threadmain, // thread worker function
+ new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
+ 0, // 0 means: create immediatly otherwise use CREATE_SUSPENDED
+ &uThreadID ); // thread id to fill
+#else
+ hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
+#endif
+}
+
+void JoinMainLoopThread()
+{
+ if( hThreadID )
+ {
+#ifdef WNT
+ WaitForSingleObject(hThreadID, INFINITE);
+#else
+ osl_joinWithThread(hThreadID);
+ osl_destroyThread( hThreadID );
+#endif
+ }
+}
diff --git a/vcl/source/app/svmainhook.cxx b/vcl/source/app/svmainhook.cxx
new file mode 100644
index 000000000000..413b28b3affb
--- /dev/null
+++ b/vcl/source/app/svmainhook.cxx
@@ -0,0 +1,116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/tools.h>
+
+#ifndef MACOSX
+
+BOOL ImplSVMainHook( BOOL * )
+{
+ return FALSE; // indicate that ImplSVMainHook is not implemented
+}
+
+#else
+// MACOSX cocoa implementation of ImplSVMainHook is in aqua/source/app/salinst.cxx
+#ifndef QUARTZ // MACOSX (X11) needs the CFRunLoop()
+#include <osl/thread.h>
+#include <premac.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <postmac.h>
+#include <unistd.h>
+
+extern BOOL ImplSVMain();
+
+// ============================================================================
+
+
+static void SourceContextCallBack( void *pInfo )
+{
+}
+
+struct ThreadContext
+{
+ BOOL* pRet;
+ CFRunLoopRef* pRunLoopRef;
+};
+
+static void RunSVMain(void *pData)
+{
+ ThreadContext* tcx = reinterpret_cast<ThreadContext*>(pData);
+
+ // busy waiting (ok in this case) until the run loop is
+ // running
+ while (!CFRunLoopIsWaiting(*tcx->pRunLoopRef))
+ usleep(100);
+
+ *tcx->pRet = ImplSVMain();
+
+ // Force exit since some JVMs won't shutdown when only exit() is invoked
+ _exit( 0 );
+}
+
+BOOL ImplSVMainHook( BOOL *pbInit )
+{
+ // Mac OS X requires that any Cocoa code have a CFRunLoop started in the
+ // primordial thread. Since all of the AWT classes in Java 1.4 and higher
+ // are written in Cocoa, we need to start the CFRunLoop here and run
+ // ImplSVMain() in a secondary thread.
+ // See http://developer.apple.com/samplecode/simpleJavaLauncher/listing3.html
+ // for further details and an example
+
+ CFRunLoopRef runLoopRef = CFRunLoopGetCurrent();
+ ThreadContext tcx;
+ tcx.pRet = pbInit; // the return value
+ tcx.pRunLoopRef = &runLoopRef;
+ oslThread hThreadID = osl_createThread(RunSVMain, &tcx);
+
+ // Start the CFRunLoop
+ CFRunLoopSourceContext aSourceContext;
+ aSourceContext.version = 0;
+ aSourceContext.info = NULL;
+ aSourceContext.retain = NULL;
+ aSourceContext.release = NULL;
+ aSourceContext.copyDescription = NULL;
+ aSourceContext.equal = NULL;
+ aSourceContext.hash = NULL;
+ aSourceContext.schedule = NULL;
+ aSourceContext.cancel = NULL;
+ aSourceContext.perform = &SourceContextCallBack;
+ CFRunLoopSourceRef aSourceRef = CFRunLoopSourceCreate(NULL, 0, &aSourceContext);
+ CFRunLoopAddSource(runLoopRef, aSourceRef, kCFRunLoopCommonModes);
+ CFRunLoopRun();
+
+ osl_joinWithThread( hThreadID );
+ osl_destroyThread( hThreadID );
+
+ return TRUE; // indicate that ImplSVMainHook is implemented
+}
+
+#endif // MACOSX
+#endif
diff --git a/vcl/source/app/timer.cxx b/vcl/source/app/timer.cxx
new file mode 100644
index 000000000000..356608e7fbfc
--- /dev/null
+++ b/vcl/source/app/timer.cxx
@@ -0,0 +1,380 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/saltimer.hxx>
+#include <tools/time.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/salinst.hxx>
+#include <tools/debug.hxx>
+#include <vcl/timer.hxx>
+
+
+
+// =======================================================================
+
+#define MAX_TIMER_PERIOD ((ULONG)0xFFFFFFFF)
+
+// ---------------------
+// - TimeManager-Types -
+// ---------------------
+
+struct ImplTimerData
+{
+ ImplTimerData* mpNext; // Pointer to the next Instance
+ Timer* mpSVTimer; // Pointer to SV Timer instance
+ ULONG mnUpdateTime; // Last Update Time
+ ULONG mnTimerUpdate; // TimerCallbackProcs on stack
+ BOOL mbDelete; // Wurde Timer waehren Update() geloescht
+ BOOL mbInTimeout; // Befinden wir uns im Timeout-Handler
+};
+
+// =======================================================================
+
+void Timer::ImplDeInitTimer()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplTimerData* pTimerData = pSVData->mpFirstTimerData;
+
+ if ( pTimerData )
+ {
+ do
+ {
+ ImplTimerData* pTempTimerData = pTimerData;
+ if ( pTimerData->mpSVTimer )
+ {
+ pTimerData->mpSVTimer->mbActive = FALSE;
+ pTimerData->mpSVTimer->mpTimerData = NULL;
+ }
+ pTimerData = pTimerData->mpNext;
+ delete pTempTimerData;
+ }
+ while ( pTimerData );
+
+ pSVData->mpFirstTimerData = NULL;
+ pSVData->mnTimerPeriod = 0;
+ delete pSVData->mpSalTimer;
+ pSVData->mpSalTimer = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplStartTimer( ImplSVData* pSVData, ULONG nMS )
+{
+ if ( !nMS )
+ nMS = 1;
+
+ if ( nMS != pSVData->mnTimerPeriod )
+ {
+ pSVData->mnTimerPeriod = nMS;
+ pSVData->mpSalTimer->Start( nMS );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Timer::ImplTimerCallbackProc()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplTimerData* pTimerData;
+ ImplTimerData* pPrevTimerData;
+ ULONG nMinPeriod = MAX_TIMER_PERIOD;
+ ULONG nDeltaTime;
+ ULONG nTime = Time::GetSystemTicks();
+
+ if ( pSVData->mbNoCallTimer )
+ return;
+
+ pSVData->mnTimerUpdate++;
+ pSVData->mbNotAllTimerCalled = TRUE;
+
+ // Suche Timer raus, wo der Timeout-Handler gerufen werden muss
+ pTimerData = pSVData->mpFirstTimerData;
+ while ( pTimerData )
+ {
+ // Wenn Timer noch nicht neu ist und noch nicht geloescht wurde
+ // und er sich nicht im Timeout-Handler befindet,
+ // dann den Handler rufen, wenn die Zeit abgelaufen ist
+ if ( (pTimerData->mnTimerUpdate < pSVData->mnTimerUpdate) &&
+ !pTimerData->mbDelete && !pTimerData->mbInTimeout )
+ {
+ // Zeit abgelaufen
+ if ( (pTimerData->mnUpdateTime+pTimerData->mpSVTimer->mnTimeout) <= nTime )
+ {
+ // Neue Updatezeit setzen
+ pTimerData->mnUpdateTime = nTime;
+
+ // kein AutoTimer, dann anhalten
+ if ( !pTimerData->mpSVTimer->mbAuto )
+ {
+ pTimerData->mpSVTimer->mbActive = FALSE;
+ pTimerData->mbDelete = TRUE;
+ }
+
+ // call Timeout
+ pTimerData->mbInTimeout = TRUE;
+ pTimerData->mpSVTimer->Timeout();
+ pTimerData->mbInTimeout = FALSE;
+ }
+ }
+
+ pTimerData = pTimerData->mpNext;
+ }
+
+ // Neue Zeit ermitteln
+ ULONG nNewTime = Time::GetSystemTicks();
+ pPrevTimerData = NULL;
+ pTimerData = pSVData->mpFirstTimerData;
+ while ( pTimerData )
+ {
+ // Befindet sich Timer noch im Timeout-Handler, dann ignorieren
+ if ( pTimerData->mbInTimeout )
+ {
+ pPrevTimerData = pTimerData;
+ pTimerData = pTimerData->mpNext;
+ }
+ // Wurde Timer zwischenzeitlich zerstoert ?
+ else if ( pTimerData->mbDelete )
+ {
+ if ( pPrevTimerData )
+ pPrevTimerData->mpNext = pTimerData->mpNext;
+ else
+ pSVData->mpFirstTimerData = pTimerData->mpNext;
+ if ( pTimerData->mpSVTimer )
+ pTimerData->mpSVTimer->mpTimerData = NULL;
+ ImplTimerData* pTempTimerData = pTimerData;
+ pTimerData = pTimerData->mpNext;
+ delete pTempTimerData;
+ }
+ else
+ {
+ pTimerData->mnTimerUpdate = 0;
+ // kleinste Zeitspanne ermitteln
+ if ( pTimerData->mnUpdateTime == nTime )
+ {
+ nDeltaTime = pTimerData->mpSVTimer->mnTimeout;
+ if ( nDeltaTime < nMinPeriod )
+ nMinPeriod = nDeltaTime;
+ }
+ else
+ {
+ nDeltaTime = pTimerData->mnUpdateTime + pTimerData->mpSVTimer->mnTimeout;
+ if ( nDeltaTime < nNewTime )
+ nMinPeriod = 1;
+ else
+ {
+ nDeltaTime -= nNewTime;
+ if ( nDeltaTime < nMinPeriod )
+ nMinPeriod = nDeltaTime;
+ }
+ }
+ pPrevTimerData = pTimerData;
+ pTimerData = pTimerData->mpNext;
+ }
+ }
+
+ // Wenn keine Timer mehr existieren, dann Clock loeschen
+ if ( !pSVData->mpFirstTimerData )
+ {
+ pSVData->mpSalTimer->Stop();
+ pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
+ }
+ else
+ ImplStartTimer( pSVData, nMinPeriod );
+
+ pSVData->mnTimerUpdate--;
+ pSVData->mbNotAllTimerCalled = FALSE;
+}
+
+// =======================================================================
+
+Timer::Timer()
+{
+ mpTimerData = NULL;
+ mnTimeout = 1;
+ mbAuto = FALSE;
+ mbActive = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Timer::Timer( const Timer& rTimer )
+{
+ mpTimerData = NULL;
+ mnTimeout = rTimer.mnTimeout;
+ mbAuto = FALSE;
+ mbActive = FALSE;
+ maTimeoutHdl = rTimer.maTimeoutHdl;
+
+ if ( rTimer.IsActive() )
+ Start();
+}
+
+// -----------------------------------------------------------------------
+
+Timer::~Timer()
+{
+ if ( mpTimerData )
+ {
+ mpTimerData->mbDelete = TRUE;
+ mpTimerData->mpSVTimer = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Timer::Timeout()
+{
+ maTimeoutHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Timer::SetTimeout( ULONG nNewTimeout )
+{
+ mnTimeout = nNewTimeout;
+
+ // Wenn Timer aktiv, dann Clock erneuern
+ if ( mbActive )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->mnTimerUpdate && (mnTimeout < pSVData->mnTimerPeriod) )
+ ImplStartTimer( pSVData, mnTimeout );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Timer::Start()
+{
+ mbActive = TRUE;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !mpTimerData )
+ {
+ if ( !pSVData->mpFirstTimerData )
+ {
+ pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
+ if( ! pSVData->mpSalTimer )
+ {
+ pSVData->mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
+ pSVData->mpSalTimer->SetCallback( ImplTimerCallbackProc );
+ }
+ }
+
+ // insert timer and start
+ mpTimerData = new ImplTimerData;
+ mpTimerData->mpSVTimer = this;
+ mpTimerData->mnUpdateTime = Time::GetSystemTicks();
+ mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
+ mpTimerData->mbDelete = FALSE;
+ mpTimerData->mbInTimeout = FALSE;
+
+ // !!!!! Wegen SFX hinten einordnen !!!!!
+ ImplTimerData* pPrev = NULL;
+ ImplTimerData* pData = pSVData->mpFirstTimerData;
+ while ( pData )
+ {
+ pPrev = pData;
+ pData = pData->mpNext;
+ }
+ mpTimerData->mpNext = NULL;
+ if ( pPrev )
+ pPrev->mpNext = mpTimerData;
+ else
+ pSVData->mpFirstTimerData = mpTimerData;
+
+ if ( mnTimeout < pSVData->mnTimerPeriod )
+ ImplStartTimer( pSVData, mnTimeout );
+ }
+ else if( !mpTimerData->mpSVTimer ) // TODO: remove when guilty found
+ {
+ DBG_ERROR( "Timer::Start() on a destroyed Timer!" );
+ }
+ else
+ {
+ mpTimerData->mnUpdateTime = Time::GetSystemTicks();
+ mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
+ mpTimerData->mbDelete = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Timer::Stop()
+{
+ mbActive = FALSE;
+
+ if ( mpTimerData )
+ mpTimerData->mbDelete = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+Timer& Timer::operator=( const Timer& rTimer )
+{
+ if ( IsActive() )
+ Stop();
+
+ mbActive = FALSE;
+ mnTimeout = rTimer.mnTimeout;
+ maTimeoutHdl = rTimer.maTimeoutHdl;
+
+ if ( rTimer.IsActive() )
+ Start();
+
+ return *this;
+}
+
+// =======================================================================
+
+AutoTimer::AutoTimer()
+{
+ mbAuto = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+AutoTimer::AutoTimer( const AutoTimer& rTimer ) : Timer( rTimer )
+{
+ mbAuto = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+AutoTimer& AutoTimer::operator=( const AutoTimer& rTimer )
+{
+ Timer::operator=( rTimer );
+ return *this;
+}
diff --git a/vcl/source/app/unohelp.cxx b/vcl/source/app/unohelp.cxx
new file mode 100644
index 000000000000..237156a5f9f7
--- /dev/null
+++ b/vcl/source/app/unohelp.cxx
@@ -0,0 +1,242 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+
+
+#include <vcl/unohelp.hxx>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/processfactory.hxx>
+
+#ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#endif
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+
+#ifndef _COM_SUN_STAR_UTIL_XCOLLATOR_HPP_
+#include <com/sun/star/i18n/XCollator.hpp>
+#endif
+#include <com/sun/star/awt/XExtendedToolkit.hpp>
+#include <com/sun/star/accessibility/AccessibleEventObject.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+
+#include <cppuhelper/servicefactory.hxx>
+
+#include <tools/tempfile.hxx>
+#include <osl/file.hxx>
+
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::rtl;
+
+#define DOSTRING( x ) #x
+#define STRING( x ) DOSTRING( x )
+
+struct VCLRegServiceInfo
+{
+ const sal_Char* pLibName;
+ sal_Bool bHasSUPD;
+};
+
+static VCLRegServiceInfo aVCLComponentsArray[] =
+{
+ {"i18n", sal_True},
+ {"i18npool", sal_True},
+#ifdef UNX
+#ifdef MACOSX
+ {"dtransaqua", sal_True},
+#else
+ {"dtransX11", sal_True},
+#endif
+#endif
+#if defined(WNT) || defined(OS2)
+ {"sysdtrans", sal_False},
+#endif
+ {"dtrans", sal_False},
+ {"mcnttype", sal_False},
+ {"ftransl", sal_False},
+ {"dnd", sal_False},
+ {NULL, sal_False}
+};
+
+uno::Reference< lang::XMultiServiceFactory > vcl::unohelper::GetMultiServiceFactory()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maAppData.mxMSF.is() )
+ {
+ pSVData->maAppData.mxMSF = ::comphelper::getProcessServiceFactory();
+ }
+ if ( !pSVData->maAppData.mxMSF.is() )
+ {
+ TempFile aTempFile;
+ OUString aTempFileName;
+ osl::FileBase::getSystemPathFromFileURL( aTempFile.GetName(), aTempFileName );
+ pSVData->maAppData.mpMSFTempFileName = new String(aTempFileName);
+
+ try
+ {
+ pSVData->maAppData.mxMSF = ::cppu::createRegistryServiceFactory( aTempFileName, rtl::OUString(), sal_False );
+ uno::Reference < registry::XImplementationRegistration > xReg(
+ pSVData->maAppData.mxMSF->createInstance( OUString::createFromAscii( "com.sun.star.registry.ImplementationRegistration" )), uno::UNO_QUERY );
+
+ if( xReg.is() )
+ {
+ sal_Int32 nCompCount = 0;
+ while ( aVCLComponentsArray[ nCompCount ].pLibName )
+ {
+ OUString aComponentPathString = CreateLibraryName( aVCLComponentsArray[ nCompCount ].pLibName, aVCLComponentsArray[ nCompCount ].bHasSUPD );
+ if (aComponentPathString.getLength() )
+ {
+ try
+ {
+ xReg->registerImplementation(
+ OUString::createFromAscii( "com.sun.star.loader.SharedLibrary" ),aComponentPathString, NULL );
+ }
+ catch( ::com::sun::star::uno::Exception & )
+ {
+ }
+ }
+ nCompCount++;
+ }
+ }
+ }
+ catch( ::com::sun::star::uno::Exception & )
+ {
+ delete pSVData->maAppData.mpMSFTempFileName;
+ pSVData->maAppData.mpMSFTempFileName = NULL;
+ }
+ }
+ return pSVData->maAppData.mxMSF;
+}
+
+
+uno::Reference < i18n::XBreakIterator > vcl::unohelper::CreateBreakIterator()
+{
+ uno::Reference < i18n::XBreakIterator > xB;
+ uno::Reference< lang::XMultiServiceFactory > xMSF = GetMultiServiceFactory();
+ if ( xMSF.is() )
+ {
+ uno::Reference < uno::XInterface > xI = xMSF->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) );
+ if ( xI.is() )
+ {
+ uno::Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XBreakIterator >*)0) );
+ x >>= xB;
+ }
+ }
+ return xB;
+}
+
+uno::Reference < i18n::XCharacterClassification > vcl::unohelper::CreateCharacterClassification()
+{
+ uno::Reference < i18n::XCharacterClassification > xB;
+ uno::Reference< lang::XMultiServiceFactory > xMSF = GetMultiServiceFactory();
+ if ( xMSF.is() )
+ {
+ uno::Reference < uno::XInterface > xI = xMSF->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.i18n.CharacterClassification" ) );
+ if ( xI.is() )
+ {
+ uno::Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XCharacterClassification >*)0) );
+ x >>= xB;
+ }
+ }
+ return xB;
+}
+
+uno::Reference < i18n::XCollator > vcl::unohelper::CreateCollator()
+{
+ uno::Reference < i18n::XCollator > xB;
+ uno::Reference< lang::XMultiServiceFactory > xMSF = GetMultiServiceFactory();
+ if ( xMSF.is() )
+ {
+ uno::Reference < uno::XInterface > xI = xMSF->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.i18n.Collator" ) );
+ if ( xI.is() )
+ {
+ uno::Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XCollator >*)0) );
+ x >>= xB;
+ }
+ }
+ return xB;
+}
+
+::rtl::OUString vcl::unohelper::CreateLibraryName( const sal_Char* pModName, BOOL bSUPD )
+{
+ // create variable library name suffixes
+ OUString aDLLSuffix = OUString::createFromAscii( STRING(DLLPOSTFIX) );
+
+ OUString aLibName;
+
+#if defined( WNT) || defined(OS2)
+ aLibName = OUString::createFromAscii( pModName );
+ if ( bSUPD )
+ {
+ aLibName += aDLLSuffix;
+ }
+ aLibName += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".dll" ));
+#else
+ aLibName = OUString( RTL_CONSTASCII_USTRINGPARAM( "lib" ));
+ aLibName += OUString::createFromAscii( pModName );
+ if ( bSUPD )
+ {
+ aLibName += aDLLSuffix;
+ }
+#ifdef MACOSX
+ aLibName += OUString( RTL_CONSTASCII_USTRINGPARAM( ".dylib" ));
+#else
+ aLibName += OUString( RTL_CONSTASCII_USTRINGPARAM( ".so" ));
+#endif
+#endif
+
+ return aLibName;
+}
+
+void vcl::unohelper::NotifyAccessibleStateEventGlobally( const ::com::sun::star::accessibility::AccessibleEventObject& rEventObject )
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::awt::XExtendedToolkit > xExtToolkit( Application::GetVCLToolkit(), uno::UNO_QUERY );
+ if ( xExtToolkit.is() )
+ {
+ // Only for focus events
+ sal_Int16 nType = ::com::sun::star::accessibility::AccessibleStateType::INVALID;
+ rEventObject.NewValue >>= nType;
+ if ( nType == ::com::sun::star::accessibility::AccessibleStateType::FOCUSED )
+ xExtToolkit->fireFocusGained( rEventObject.Source );
+ else
+ {
+ rEventObject.OldValue >>= nType;
+ if ( nType == ::com::sun::star::accessibility::AccessibleStateType::FOCUSED )
+ xExtToolkit->fireFocusLost( rEventObject.Source );
+ }
+
+ }
+}
diff --git a/vcl/source/app/unohelp2.cxx b/vcl/source/app/unohelp2.cxx
new file mode 100644
index 000000000000..5b6d7c73416a
--- /dev/null
+++ b/vcl/source/app/unohelp2.cxx
@@ -0,0 +1,112 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/unohelp2.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+
+
+using namespace ::com::sun::star;
+
+namespace vcl { namespace unohelper {
+
+ TextDataObject::TextDataObject( const String& rText ) : maText( rText )
+ {
+ }
+
+ TextDataObject::~TextDataObject()
+ {
+ }
+
+ void TextDataObject::CopyStringTo( const String& rContent,
+ const uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
+ {
+ DBG_ASSERT( rxClipboard.is(), "TextDataObject::CopyStringTo: invalid clipboard!" );
+ if ( !rxClipboard.is() )
+ return;
+
+ TextDataObject* pDataObj = new TextDataObject( rContent );
+
+ const sal_uInt32 nRef = Application::ReleaseSolarMutex();
+ try
+ {
+ rxClipboard->setContents( pDataObj, NULL );
+
+ uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY );
+ if( xFlushableClipboard.is() )
+ xFlushableClipboard->flushClipboard();
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ Application::AcquireSolarMutex( nRef );
+ }
+
+ // ::com::sun::star::uno::XInterface
+ uno::Any TextDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException)
+ {
+ uno::Any aRet = ::cppu::queryInterface( rType, SAL_STATIC_CAST( datatransfer::XTransferable*, this ) );
+ return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
+ }
+
+ // ::com::sun::star::datatransfer::XTransferable
+ uno::Any TextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException)
+ {
+ uno::Any aAny;
+
+ ULONG nT = SotExchange::GetFormat( rFlavor );
+ if ( nT == SOT_FORMAT_STRING )
+ {
+ aAny <<= (::rtl::OUString)GetString();
+ }
+ else
+ {
+ throw datatransfer::UnsupportedFlavorException();
+ }
+ return aAny;
+ }
+
+ uno::Sequence< datatransfer::DataFlavor > TextDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException)
+ {
+ uno::Sequence< datatransfer::DataFlavor > aDataFlavors(1);
+ SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[0] );
+ return aDataFlavors;
+ }
+
+ sal_Bool TextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException)
+ {
+ ULONG nT = SotExchange::GetFormat( rFlavor );
+ return ( nT == SOT_FORMAT_STRING );
+ }
+
+}} // namespace vcl::unohelper
diff --git a/vcl/source/app/vclevent.cxx b/vcl/source/app/vclevent.cxx
new file mode 100644
index 000000000000..0c98da48e6d0
--- /dev/null
+++ b/vcl/source/app/vclevent.cxx
@@ -0,0 +1,151 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/vclevent.hxx"
+#include "vcl/svdata.hxx"
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::accessibility::XAccessible;
+
+TYPEINIT0(VclSimpleEvent);
+TYPEINIT1(VclWindowEvent, VclSimpleEvent);
+TYPEINIT1(VclMenuEvent, VclSimpleEvent);
+
+VclAccessibleEvent::VclAccessibleEvent( ULONG n, const Reference<XAccessible>& rxAccessible ) :
+ VclSimpleEvent(n),
+ mxAccessible(rxAccessible)
+{
+}
+
+VclAccessibleEvent::~VclAccessibleEvent()
+{
+}
+
+Reference<XAccessible> VclAccessibleEvent::GetAccessible() const
+{
+ return mxAccessible;
+}
+
+void VclEventListeners::Call( VclSimpleEvent* pEvent ) const
+{
+ // Copy the list, because this can be destroyed when calling a Link...
+ std::list<Link> aCopy( *this );
+ std::list<Link>::iterator aIter( aCopy.begin() );
+ if( pEvent->IsA( VclWindowEvent::StaticType() ) )
+ {
+ VclWindowEvent* pWinEvent = static_cast<VclWindowEvent*>(pEvent);
+ ImplDelData aDel( pWinEvent->GetWindow() );
+ while ( aIter != aCopy.end() && ! aDel.IsDead() )
+ {
+ (*aIter).Call( pEvent );
+ aIter++;
+ }
+ }
+ else
+ {
+ while ( aIter != aCopy.end() )
+ {
+ (*aIter).Call( pEvent );
+ aIter++;
+ }
+ }
+}
+
+BOOL VclEventListeners::Process( VclSimpleEvent* pEvent ) const
+{
+ BOOL bProcessed = FALSE;
+ // Copy the list, because this can be destroyed when calling a Link...
+ std::list<Link> aCopy( *this );
+ std::list<Link>::iterator aIter( aCopy.begin() );
+ while ( aIter != aCopy.end() )
+ {
+ if( (*aIter).Call( pEvent ) != 0 )
+ {
+ bProcessed = TRUE;
+ break;
+ }
+ aIter++;
+ }
+ return bProcessed;
+}
+
+VclEventListeners2::VclEventListeners2()
+{
+}
+
+VclEventListeners2::~VclEventListeners2()
+{
+}
+
+void VclEventListeners2::addListener( const Link& i_rLink )
+{
+ // ensure uniqueness
+ for( std::list< Link >::const_iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it )
+ {
+ if( *it == i_rLink )
+ return;
+ }
+ m_aListeners.push_back( i_rLink );
+}
+
+void VclEventListeners2::removeListener( const Link& i_rLink )
+{
+ size_t n = m_aIterators.size();
+ for( size_t i = 0; i < n; i++ )
+ {
+ if( m_aIterators[i].m_aIt != m_aListeners.end() && *m_aIterators[i].m_aIt == i_rLink )
+ {
+ m_aIterators[i].m_bWasInvalidated = true;
+ ++m_aIterators[i].m_aIt;
+ }
+ }
+ m_aListeners.remove( i_rLink );
+}
+
+void VclEventListeners2::callListeners( VclSimpleEvent* i_pEvent )
+{
+ vcl::DeletionListener aDel( this );
+
+ m_aIterators.push_back(ListenerIt(m_aListeners.begin()));
+ size_t nIndex = m_aIterators.size() - 1;
+ while( ! aDel.isDeleted() && m_aIterators[ nIndex ].m_aIt != m_aListeners.end() )
+ {
+ m_aIterators[ nIndex ].m_aIt->Call( i_pEvent );
+ if( m_aIterators[ nIndex ].m_bWasInvalidated )
+ // check if the current element was removed and the iterator increased in the meantime
+ m_aIterators[ nIndex ].m_bWasInvalidated = false;
+ else
+ ++m_aIterators[ nIndex ].m_aIt;
+ }
+ m_aIterators.pop_back();
+}
+
diff --git a/vcl/source/components/display.cxx b/vcl/source/components/display.cxx
new file mode 100644
index 000000000000..6d7653968229
--- /dev/null
+++ b/vcl/source/components/display.cxx
@@ -0,0 +1,345 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <vcl/svapp.hxx>
+
+#include <cppuhelper/implbase3.hxx>
+#include <cppuhelper/implbase4.hxx>
+
+#include <vector>
+#include <tools/debug.hxx>
+
+
+using ::rtl::OUString;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+
+// -----------------------------------------------------------------------
+
+namespace vcl
+{
+
+class DisplayInfo : public ::cppu::WeakAggImplHelper3< XPropertySet, XPropertySetInfo, XServiceInfo >
+{
+public:
+ DisplayInfo( sal_uInt32 nDisplay );
+
+ // XPropertySet
+ virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (RuntimeException);
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException);
+ virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+
+ // XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties( ) throw (RuntimeException);
+ virtual Property SAL_CALL getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException);
+ virtual ::sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) throw (RuntimeException);
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) throw (RuntimeException);
+ virtual ::sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (RuntimeException);
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException);
+
+private:
+ sal_uInt32 mnDisplay;
+};
+
+static const char* pScreenAreaName = "ScreenArea";
+static const char* pWorkAreaName = "WorkArea";
+static const char* pScreenName = "ScreenName";
+
+// --------------------------------------------------------------------
+
+DisplayInfo::DisplayInfo( sal_uInt32 nDisplay )
+: mnDisplay( nDisplay )
+{
+}
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL DisplayInfo::getPropertySetInfo( ) throw (RuntimeException)
+{
+ return this;
+}
+
+void SAL_CALL DisplayInfo::setPropertyValue( const OUString& /*aPropertyName* */, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+ throw PropertyVetoException();
+}
+
+Any SAL_CALL DisplayInfo::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ Rectangle aRect;
+ if( PropertyName.equalsAscii( pScreenAreaName ) )
+ {
+ aRect = Application::GetScreenPosSizePixel( mnDisplay );
+ }
+ else if( PropertyName.equalsAscii( pWorkAreaName ) )
+ {
+ aRect = Application::GetWorkAreaPosSizePixel( mnDisplay );
+ }
+ else if( PropertyName.equalsAscii( pScreenName ) )
+ {
+ return Any( Application::GetScreenName( mnDisplay ) );
+ }
+ else
+ throw UnknownPropertyException();
+
+ return Any( com::sun::star::awt::Rectangle( aRect.Left(), aRect.Top(), aRect.getWidth(), aRect.getHeight() ) );
+}
+
+void SAL_CALL DisplayInfo::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+void SAL_CALL DisplayInfo::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+void SAL_CALL DisplayInfo::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+void SAL_CALL DisplayInfo::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+
+// XPropertySetInfo
+Sequence< Property > SAL_CALL DisplayInfo::getProperties( ) throw (RuntimeException)
+{
+ Sequence< Property > aProps(2);
+ aProps[0] = getPropertyByName( OUString::createFromAscii( pScreenAreaName ) );
+ aProps[1] = getPropertyByName( OUString::createFromAscii( pWorkAreaName ) );
+ return aProps;
+}
+
+Property SAL_CALL DisplayInfo::getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException)
+{
+ if( aName.equalsAscii( pScreenAreaName ) ||
+ aName.equalsAscii( pWorkAreaName ) )
+ return Property( aName, 0, ::getCppuType( (::com::sun::star::awt::Rectangle const *)0 ), PropertyAttribute::READONLY );
+ throw UnknownPropertyException();
+}
+
+::sal_Bool SAL_CALL DisplayInfo::hasPropertyByName( const OUString& Name ) throw (RuntimeException)
+{
+ return Name.equalsAscii( pScreenAreaName ) ||
+ Name.equalsAscii( pWorkAreaName );
+}
+
+// XServiceInfo
+OUString SAL_CALL DisplayInfo::getImplementationName( ) throw (RuntimeException)
+{
+ static OUString aImplementationName( RTL_CONSTASCII_USTRINGPARAM( "vcl::DisplayInfo" ) );
+ return aImplementationName;
+}
+
+::sal_Bool SAL_CALL DisplayInfo::supportsService( const OUString& ServiceName ) throw (RuntimeException)
+{
+ Sequence< OUString > aSN( getSupportedServiceNames() );
+ for( sal_Int32 nService = 0; nService < aSN.getLength(); nService++ )
+ {
+ if( aSN[nService] == ServiceName )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+Sequence< OUString > SAL_CALL DisplayInfo::getSupportedServiceNames( ) throw (RuntimeException)
+{
+ static OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DisplayInfo" ) );
+ static Sequence< OUString > aServiceNames( &aServiceName, 1 );
+ return aServiceNames;
+}
+
+// ====================================================================
+
+class DisplayAccess : public ::cppu::WeakAggImplHelper4< XPropertySet, XPropertySetInfo, XIndexAccess, XServiceInfo >
+{
+public:
+ DisplayAccess ();
+
+ // XPropertySet
+ virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (RuntimeException);
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException);
+ virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
+
+ // XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties( ) throw (RuntimeException);
+ virtual Property SAL_CALL getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException);
+ virtual ::sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) throw (RuntimeException);
+
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount() throw (RuntimeException);
+ virtual Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException);
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType( ) throw (RuntimeException);
+ virtual ::sal_Bool SAL_CALL hasElements( ) throw (RuntimeException);
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) throw (RuntimeException);
+ virtual ::sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (RuntimeException);
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException);
+};
+
+Sequence< OUString > DisplayAccess_getSupportedServiceNames()
+{
+ static OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DisplayAccess" ) );
+ static Sequence< OUString > aServiceNames( &aServiceName, 1 );
+ return aServiceNames;
+}
+
+OUString DisplayAccess_getImplementationName()
+{
+ return OUString( RTL_CONSTASCII_USTRINGPARAM( "vcl::DisplayAccess" ) );
+}
+
+Reference< XInterface > SAL_CALL DisplayAccess_createInstance( const Reference< XMultiServiceFactory >& )
+{
+ return static_cast< ::cppu::OWeakObject * >( new DisplayAccess );
+}
+
+DisplayAccess::DisplayAccess()
+{
+}
+
+static const char* pMultiDisplayName = "MultiDisplay";
+static const char* pDefaultDisplayName = "DefaultDisplay";
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL DisplayAccess::getPropertySetInfo( ) throw (RuntimeException)
+{
+ return this;
+}
+
+void SAL_CALL DisplayAccess::setPropertyValue( const OUString& /*aPropertyName* */, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+ throw PropertyVetoException();
+}
+
+Any SAL_CALL DisplayAccess::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ Any aRet;
+ if( PropertyName.equalsAscii( pMultiDisplayName ) )
+ {
+ aRet <<= sal_Bool( Application::IsMultiDisplay() );
+ }
+ else if( PropertyName.equalsAscii( pDefaultDisplayName ) )
+ {
+ aRet <<= sal_Int32( Application::GetDefaultDisplayNumber() );
+ }
+ else
+ throw UnknownPropertyException();
+
+ return aRet;
+}
+
+void SAL_CALL DisplayAccess::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+void SAL_CALL DisplayAccess::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+void SAL_CALL DisplayAccess::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+void SAL_CALL DisplayAccess::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
+
+// XPropertySetInfo
+Sequence< Property > SAL_CALL DisplayAccess::getProperties( ) throw (RuntimeException)
+{
+ Sequence< Property > aProps(2);
+ aProps[0] = getPropertyByName( OUString::createFromAscii( pMultiDisplayName ) );
+ aProps[1] = getPropertyByName( OUString::createFromAscii( pDefaultDisplayName ) );
+ return aProps;
+}
+
+Property SAL_CALL DisplayAccess::getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException)
+{
+ if( aName.equalsAscii( pMultiDisplayName ) )
+ return Property( aName, 0, ::getCppuType( (sal_Bool const *)0 ), PropertyAttribute::READONLY );
+
+ if( aName.equalsAscii( pDefaultDisplayName ) )
+ return Property( aName, 0, ::getCppuType( (sal_Int32 const *)0 ), PropertyAttribute::READONLY );
+ throw UnknownPropertyException();
+}
+
+::sal_Bool SAL_CALL DisplayAccess::hasPropertyByName( const OUString& Name ) throw (RuntimeException)
+{
+ return Name.equalsAscii( pMultiDisplayName ) ||
+ Name.equalsAscii( pDefaultDisplayName );
+}
+
+// XIndexAccess
+::sal_Int32 SAL_CALL DisplayAccess::getCount() throw (RuntimeException)
+{
+ return Application::GetScreenCount();
+}
+
+Any SAL_CALL DisplayAccess::getByIndex( ::sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
+{
+ if( (Index < 0) || (Index >= getCount()) )
+ throw IndexOutOfBoundsException();
+
+ return makeAny( Reference< XPropertySet >( new DisplayInfo( Index ) ) );
+}
+
+// XElementAccess
+Type SAL_CALL DisplayAccess::getElementType( ) throw (RuntimeException)
+{
+ return XPropertySet::static_type();
+}
+
+::sal_Bool SAL_CALL DisplayAccess::hasElements() throw (RuntimeException)
+{
+ return true;
+}
+
+// XServiceInfo
+OUString SAL_CALL DisplayAccess::getImplementationName( ) throw (RuntimeException)
+{
+ return DisplayAccess_getImplementationName();
+}
+
+::sal_Bool SAL_CALL DisplayAccess::supportsService( const OUString& ServiceName ) throw (RuntimeException)
+{
+ Sequence< OUString > aSN( DisplayAccess_getSupportedServiceNames() );
+ for( sal_Int32 nService = 0; nService < aSN.getLength(); nService++ )
+ {
+ if( aSN[nService] == ServiceName )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+Sequence< OUString > SAL_CALL DisplayAccess::getSupportedServiceNames( ) throw (RuntimeException)
+{
+ return DisplayAccess_getSupportedServiceNames();
+}
+
+} // namespace vcl
diff --git a/vcl/source/components/dtranscomp.cxx b/vcl/source/components/dtranscomp.cxx
new file mode 100644
index 000000000000..9c88deccec23
--- /dev/null
+++ b/vcl/source/components/dtranscomp.cxx
@@ -0,0 +1,552 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "com/sun/star/lang/XServiceInfo.hpp"
+#include "com/sun/star/lang/XSingleServiceFactory.hpp"
+#include "com/sun/star/lang/XInitialization.hpp"
+#include "com/sun/star/lang/DisposedException.hpp"
+#include "com/sun/star/datatransfer/XTransferable.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboard.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboardEx.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboardListener.hpp"
+#include "com/sun/star/datatransfer/dnd/XDragSource.hpp"
+#include "com/sun/star/datatransfer/dnd/XDropTarget.hpp"
+#include "com/sun/star/datatransfer/dnd/DNDConstants.hpp"
+
+#include "vcl/svapp.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/salinst.hxx"
+#include "vos/mutex.hxx"
+#include "osl/mutex.hxx"
+
+#include "cppuhelper/compbase1.hxx"
+#include "cppuhelper/compbase2.hxx"
+#include "cppuhelper/compbase3.hxx"
+#include "cppuhelper/implbase1.hxx"
+
+using rtl::OUString;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+
+// -----------------------------------------------------------------------
+
+namespace vcl
+{
+// generic implementation to satisfy SalInstance
+class GenericClipboard :
+ public cppu::WeakComponentImplHelper3 <
+ datatransfer::clipboard::XClipboardEx,
+ datatransfer::clipboard::XClipboardNotifier,
+ XServiceInfo
+ >
+{
+ osl::Mutex m_aMutex;
+ Reference< ::com::sun::star::datatransfer::XTransferable > m_aContents;
+ Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner > m_aOwner;
+ std::list< Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > m_aListeners;
+
+ void fireChangedContentsEvent();
+ void clearContents();
+
+public:
+
+ GenericClipboard() : cppu::WeakComponentImplHelper3<
+ datatransfer::clipboard::XClipboardEx,
+ datatransfer::clipboard::XClipboardNotifier,
+ XServiceInfo
+ >( m_aMutex )
+ {}
+ virtual ~GenericClipboard();
+
+ /*
+ * XServiceInfo
+ */
+
+ virtual rtl::OUString SAL_CALL getImplementationName() throw( RuntimeException );
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( RuntimeException );
+ virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( RuntimeException );
+
+ static rtl::OUString getImplementationName_static();
+ static Sequence< rtl::OUString > getSupportedServiceNames_static();
+
+ /*
+ * XClipboard
+ */
+
+ virtual Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents()
+ throw(RuntimeException);
+
+ virtual void SAL_CALL setContents(
+ const Reference< ::com::sun::star::datatransfer::XTransferable >& xTrans,
+ const Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw(RuntimeException);
+
+ virtual ::rtl::OUString SAL_CALL getName()
+ throw(RuntimeException);
+
+ /*
+ * XClipboardEx
+ */
+
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities()
+ throw(RuntimeException);
+
+ /*
+ * XClipboardNotifier
+ */
+ virtual void SAL_CALL addClipboardListener(
+ const Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException);
+
+ virtual void SAL_CALL removeClipboardListener(
+ const Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException);
+};
+
+GenericClipboard::~GenericClipboard()
+{
+}
+
+rtl::OUString GenericClipboard::getImplementationName_static()
+{
+ return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.datatransfer.VCLGenericClipboard" ) );
+}
+
+Sequence< rtl::OUString > GenericClipboard::getSupportedServiceNames_static()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.clipboard.SystemClipboard");
+ return aRet;
+}
+
+rtl::OUString GenericClipboard::getImplementationName() throw( RuntimeException )
+{
+ return getImplementationName_static();
+}
+
+Sequence< rtl::OUString > GenericClipboard::getSupportedServiceNames() throw( RuntimeException )
+{
+ return getSupportedServiceNames_static();
+}
+
+sal_Bool GenericClipboard::supportsService( const ::rtl::OUString& ServiceName ) throw( RuntimeException )
+{
+ Sequence< OUString > aServices( getSupportedServiceNames() );
+ sal_Int32 nServices = aServices.getLength();
+ for( sal_Int32 i = 0; i < nServices; i++ )
+ {
+ if( aServices[i] == ServiceName )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+Reference< ::com::sun::star::datatransfer::XTransferable > GenericClipboard::getContents() throw( RuntimeException )
+{
+ return m_aContents;
+}
+
+void GenericClipboard::setContents(
+ const Reference< ::com::sun::star::datatransfer::XTransferable >& xTrans,
+ const Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw( RuntimeException )
+{
+ osl::ClearableMutexGuard aGuard( m_aMutex );
+ Reference< datatransfer::clipboard::XClipboardOwner > xOldOwner( m_aOwner );
+ Reference< datatransfer::XTransferable > xOldContents( m_aContents );
+ m_aContents = xTrans;
+ m_aOwner = xClipboardOwner;
+
+ std::list< Reference< datatransfer::clipboard::XClipboardListener > > xListeners( m_aListeners );
+ datatransfer::clipboard::ClipboardEvent aEv;
+ aEv.Contents = m_aContents;
+
+ aGuard.clear();
+
+ if( xOldOwner.is() && xOldOwner != xClipboardOwner )
+ xOldOwner->lostOwnership( this, xOldContents );
+ for( std::list< Reference< datatransfer::clipboard::XClipboardListener > >::iterator it =
+ xListeners.begin(); it != xListeners.end() ; ++it )
+ {
+ (*it)->changedContents( aEv );
+ }
+}
+
+rtl::OUString GenericClipboard::getName() throw( RuntimeException )
+{
+ return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CLIPBOARD" ) );
+}
+
+sal_Int8 GenericClipboard::getRenderingCapabilities() throw( RuntimeException )
+{
+ return 0;
+}
+
+void GenericClipboard::addClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
+ throw( RuntimeException )
+{
+ osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ m_aListeners.push_back( listener );
+}
+
+void GenericClipboard::removeClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
+ throw( RuntimeException )
+{
+ osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ m_aListeners.remove( listener );
+}
+
+// ------------------------------------------------------------------------
+
+class ClipboardFactory : public ::cppu::WeakComponentImplHelper1<
+ com::sun::star::lang::XSingleServiceFactory
+>
+{
+ osl::Mutex m_aMutex;
+public:
+ ClipboardFactory();
+ virtual ~ClipboardFactory();
+
+ /*
+ * XSingleServiceFactory
+ */
+ virtual Reference< XInterface > SAL_CALL createInstance() throw();
+ virtual Reference< XInterface > SAL_CALL createInstanceWithArguments( const Sequence< Any >& rArgs ) throw();
+};
+
+// ------------------------------------------------------------------------
+
+ClipboardFactory::ClipboardFactory() :
+ cppu::WeakComponentImplHelper1<
+ com::sun::star::lang::XSingleServiceFactory
+>( m_aMutex )
+{
+}
+
+// ------------------------------------------------------------------------
+
+ClipboardFactory::~ClipboardFactory()
+{
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > ClipboardFactory::createInstance() throw()
+{
+ return createInstanceWithArguments( Sequence< Any >() );
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > ClipboardFactory::createInstanceWithArguments( const Sequence< Any >& arguments ) throw()
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ Reference< XInterface > xResult = ImplGetSVData()->mpDefInst->CreateClipboard( arguments );
+ return xResult;
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > SAL_CALL Clipboard_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.clipboard.SystemClipboard");
+ return aRet;
+}
+
+OUString SAL_CALL Clipboard_getImplementationName()
+{
+ #if defined UNX
+ return OUString( RTL_CONSTASCII_USTRINGPARAM(
+ #if ! defined QUARTZ
+ "com.sun.star.datatransfer.X11ClipboardSupport"
+ #else
+ "com.sun.star.datatransfer.clipboard.AquaClipboard"
+ #endif
+ ) );
+ #else
+ return GenericClipboard::getImplementationName_static();
+ #endif
+}
+
+Reference< XSingleServiceFactory > SAL_CALL Clipboard_createFactory( const Reference< XMultiServiceFactory > & )
+{
+ return Reference< XSingleServiceFactory >( new ClipboardFactory() );
+}
+
+/*
+* generic DragSource dummy
+*/
+class GenericDragSource : public cppu::WeakComponentImplHelper2<
+ datatransfer::dnd::XDragSource,
+ XInitialization
+ >
+{
+ osl::Mutex m_aMutex;
+public:
+ GenericDragSource() : cppu::WeakComponentImplHelper2< datatransfer::dnd::XDragSource, XInitialization >( m_aMutex ) {}
+ virtual ~GenericDragSource();
+
+ // XDragSource
+ virtual sal_Bool SAL_CALL isDragImageSupported() throw();
+ virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw();
+ virtual void SAL_CALL startDrag(
+ const datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const Reference< datatransfer::XTransferable >& transferable,
+ const Reference< datatransfer::dnd::XDragSourceListener >& listener
+ ) throw();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ static Sequence< OUString > getSupportedServiceNames_static()
+ {
+ Sequence< OUString > aRet( 1 );
+ aRet[0] = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.GenericDragSource" );
+ return aRet;
+ }
+
+ static OUString getImplementationName_static()
+ {
+ return OUString::createFromAscii( "com.sun.star.datatransfer.dnd.VclGenericDragSource" );
+ }
+};
+
+GenericDragSource::~GenericDragSource()
+{
+}
+
+sal_Bool GenericDragSource::isDragImageSupported() throw()
+{
+ return sal_False;
+}
+
+sal_Int32 GenericDragSource::getDefaultCursor( sal_Int8 ) throw()
+{
+ return 0;
+}
+
+void GenericDragSource::startDrag( const datatransfer::dnd::DragGestureEvent&,
+ sal_Int8 /*sourceActions*/, sal_Int32 /*cursor*/, sal_Int32 /*image*/,
+ const Reference< datatransfer::XTransferable >&,
+ const Reference< datatransfer::dnd::XDragSourceListener >& listener
+ ) throw()
+{
+ datatransfer::dnd::DragSourceDropEvent aEv;
+ aEv.DropAction = datatransfer::dnd::DNDConstants::ACTION_COPY;
+ aEv.DropSuccess = sal_False;
+ listener->dragDropEnd( aEv );
+}
+
+void GenericDragSource::initialize( const Sequence< Any >& ) throw( Exception )
+{
+}
+
+
+Sequence< OUString > SAL_CALL DragSource_getSupportedServiceNames()
+{
+ #if defined UNX
+ static OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM(
+ #if ! defined QUARTZ
+ "com.sun.star.datatransfer.dnd.X11DragSource"
+ #else
+ "com.sun.star.datatransfer.dnd.OleDragSource"
+ #endif
+ ) );
+ static Sequence< OUString > aServiceNames( &aServiceName, 1 );
+ return aServiceNames;
+ #else
+ return GenericDragSource::getSupportedServiceNames_static();
+ #endif
+}
+
+OUString SAL_CALL DragSource_getImplementationName()
+{
+ #if defined UNX
+ return OUString( RTL_CONSTASCII_USTRINGPARAM(
+ #if ! defined QUARTZ
+ "com.sun.star.datatransfer.dnd.XdndSupport"
+ #else
+ "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1"
+ #endif
+ ) );
+ #else
+ return GenericDragSource::getImplementationName_static();
+ #endif
+}
+
+Reference< XInterface > SAL_CALL DragSource_createInstance( const Reference< XMultiServiceFactory >& )
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ Reference< XInterface > xResult = ImplGetSVData()->mpDefInst->CreateDragSource();
+ return xResult;
+}
+
+/*
+* generic DragSource dummy
+*/
+
+class GenericDropTarget : public cppu::WeakComponentImplHelper2<
+ datatransfer::dnd::XDropTarget,
+ XInitialization
+ >
+{
+ osl::Mutex m_aMutex;
+public:
+ GenericDropTarget() : cppu::WeakComponentImplHelper2<
+ datatransfer::dnd::XDropTarget,
+ XInitialization
+ > ( m_aMutex )
+ {}
+ virtual ~GenericDropTarget();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& args ) throw ( Exception );
+
+ // XDropTarget
+ virtual void SAL_CALL addDropTargetListener( const Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw();
+ virtual void SAL_CALL removeDropTargetListener( const Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw();
+ virtual sal_Bool SAL_CALL isActive() throw();
+ virtual void SAL_CALL setActive( sal_Bool active ) throw();
+ virtual sal_Int8 SAL_CALL getDefaultActions() throw();
+ virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) throw();
+
+ static Sequence< OUString > getSupportedServiceNames_static()
+ {
+ Sequence< OUString > aRet( 1 );
+ aRet[0] = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.GenericDropTarget" );
+ return aRet;
+ }
+
+ static OUString getImplementationName_static()
+ {
+ return OUString::createFromAscii( "com.sun.star.datatransfer.dnd.VclGenericDropTarget" );
+ }
+};
+
+GenericDropTarget::~GenericDropTarget()
+{
+}
+
+void GenericDropTarget::initialize( const Sequence< Any >& ) throw( Exception )
+{
+}
+
+void GenericDropTarget::addDropTargetListener( const Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw()
+{
+}
+
+void GenericDropTarget::removeDropTargetListener( const Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw()
+{
+}
+
+sal_Bool GenericDropTarget::isActive() throw()
+{
+ return sal_False;
+}
+
+void GenericDropTarget::setActive( sal_Bool ) throw()
+{
+}
+
+sal_Int8 GenericDropTarget::getDefaultActions() throw()
+{
+ return 0;
+}
+
+void GenericDropTarget::setDefaultActions( sal_Int8) throw()
+{
+}
+
+Sequence< OUString > SAL_CALL DropTarget_getSupportedServiceNames()
+{
+ #if defined UNX
+ static OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM(
+ #if ! defined QUARTZ
+ "com.sun.star.datatransfer.dnd.X11DropTarget"
+ #else
+ "com.sun.star.datatransfer.dnd.OleDropTarget"
+ #endif
+ ) );
+ static Sequence< OUString > aServiceNames( &aServiceName, 1 );
+ return aServiceNames;
+ #else
+ return GenericDropTarget::getSupportedServiceNames_static();
+ #endif
+}
+
+OUString SAL_CALL DropTarget_getImplementationName()
+{
+ #if defined UNX
+ return OUString( RTL_CONSTASCII_USTRINGPARAM(
+ #if ! defined QUARTZ
+ "com.sun.star.datatransfer.dnd.XdndDropTarget"
+ #else
+ "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"
+ #endif
+ ) );
+ #else
+ return GenericDropTarget::getImplementationName_static();
+ #endif
+}
+
+Reference< XInterface > SAL_CALL DropTarget_createInstance( const Reference< XMultiServiceFactory >& )
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ Reference< XInterface > xResult = ImplGetSVData()->mpDefInst->CreateDropTarget();
+ return xResult;
+}
+
+
+} // namespace vcl
+
+/*
+* SalInstance generic
+*/
+Reference< XInterface > SalInstance::CreateClipboard( const Sequence< Any >& )
+{
+ return Reference< XInterface >( ( cppu::OWeakObject * )new vcl::GenericClipboard() );
+}
+
+Reference< XInterface > SalInstance::CreateDragSource()
+{
+ return Reference< XInterface >( ( cppu::OWeakObject * )new vcl::GenericDragSource() );
+}
+
+Reference< XInterface > SalInstance::CreateDropTarget()
+{
+ return Reference< XInterface >( ( cppu::OWeakObject * )new vcl::GenericDropTarget() );
+}
+
diff --git a/vcl/source/components/factory.cxx b/vcl/source/components/factory.cxx
new file mode 100644
index 000000000000..6bed493cacde
--- /dev/null
+++ b/vcl/source/components/factory.cxx
@@ -0,0 +1,200 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#ifndef _OSL_MUTEX_HXX
+#include <osl/mutex.hxx>
+#endif
+#ifndef _RTL_USTRBUF_HXX
+#include <rtl/ustrbuf.hxx>
+#endif
+#include <uno/dispatcher.h> // declaration of generic uno interface
+#include <uno/mapping.hxx> // mapping stuff
+#include <cppuhelper/factory.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <vcl/dllapi.h>
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+
+
+// service implementation
+
+extern Sequence< OUString > SAL_CALL vcl_session_getSupportedServiceNames();
+extern OUString SAL_CALL vcl_session_getImplementationName();
+extern Reference< XInterface > SAL_CALL vcl_session_createInstance( const Reference< XMultiServiceFactory > & );
+
+namespace vcl
+{
+extern Sequence< OUString > SAL_CALL DisplayAccess_getSupportedServiceNames();
+extern OUString SAL_CALL DisplayAccess_getImplementationName();
+extern Reference< XInterface > SAL_CALL DisplayAccess_createInstance( const Reference< XMultiServiceFactory > & );
+
+extern Sequence< OUString > SAL_CALL FontIdentificator_getSupportedServiceNames();
+extern OUString SAL_CALL FontIdentificator_getImplementationName();
+extern Reference< XInterface > SAL_CALL FontIdentificator_createInstance( const Reference< XMultiServiceFactory > & );
+
+extern Sequence< OUString > SAL_CALL Clipboard_getSupportedServiceNames();
+extern OUString SAL_CALL Clipboard_getImplementationName();
+extern Reference< XSingleServiceFactory > SAL_CALL Clipboard_createFactory( const Reference< XMultiServiceFactory > & );
+
+extern Sequence< OUString > SAL_CALL DragSource_getSupportedServiceNames();
+extern OUString SAL_CALL DragSource_getImplementationName();
+extern Reference< XInterface > SAL_CALL DragSource_createInstance( const Reference< XMultiServiceFactory > & );
+
+extern Sequence< OUString > SAL_CALL DropTarget_getSupportedServiceNames();
+extern OUString SAL_CALL DropTarget_getImplementationName();
+extern Reference< XInterface > SAL_CALL DropTarget_createInstance( const Reference< XMultiServiceFactory > & );
+}
+
+extern "C" {
+
+ VCL_DLLPUBLIC void SAL_CALL component_getImplementationEnvironment(
+ const sal_Char** ppEnvTypeName,
+ uno_Environment** /*ppEnv*/ )
+ {
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+ }
+
+ VCL_DLLPUBLIC sal_Bool SAL_CALL component_writeInfo( void* /*pServiceManager*/, void* pXUnoKey )
+ {
+ if( pXUnoKey )
+ {
+ try
+ {
+ Reference< ::com::sun::star::registry::XRegistryKey > xKey( reinterpret_cast< ::com::sun::star::registry::XRegistryKey* >( pXUnoKey ) );
+
+ OUStringBuffer aImplName(64);
+ aImplName.appendAscii( "/" );
+ aImplName.append( vcl_session_getImplementationName() );
+ aImplName.appendAscii( "/UNO/SERVICES/" );
+ aImplName.append( vcl_session_getSupportedServiceNames()[0] );
+ xKey->createKey( aImplName.makeStringAndClear() );
+
+ aImplName.appendAscii( "/" );
+ aImplName.append( vcl::DisplayAccess_getImplementationName() );
+ aImplName.appendAscii( "/UNO/SERVICES/" );
+ aImplName.append( vcl::DisplayAccess_getSupportedServiceNames()[0] );
+ xKey->createKey( aImplName.makeStringAndClear() );
+
+ aImplName.appendAscii( "/" );
+ aImplName.append( vcl::FontIdentificator_getImplementationName() );
+ aImplName.appendAscii( "/UNO/SERVICES/" );
+ aImplName.append( vcl::FontIdentificator_getSupportedServiceNames()[0] );
+ xKey->createKey( aImplName.makeStringAndClear() );
+
+ #if defined UNX
+ aImplName.appendAscii( "/" );
+ aImplName.append( vcl::Clipboard_getImplementationName() );
+ aImplName.appendAscii( "/UNO/SERVICES/" );
+ aImplName.append( vcl::Clipboard_getSupportedServiceNames()[0] );
+ xKey->createKey( aImplName.makeStringAndClear() );
+
+ aImplName.appendAscii( "/" );
+ aImplName.append( vcl::DragSource_getImplementationName() );
+ aImplName.appendAscii( "/UNO/SERVICES/" );
+ aImplName.append( vcl::DragSource_getSupportedServiceNames()[0] );
+ xKey->createKey( aImplName.makeStringAndClear() );
+
+ aImplName.appendAscii( "/" );
+ aImplName.append( vcl::DropTarget_getImplementationName() );
+ aImplName.appendAscii( "/UNO/SERVICES/" );
+ aImplName.append( vcl::DropTarget_getSupportedServiceNames()[0] );
+ xKey->createKey( aImplName.makeStringAndClear() );
+ #endif
+
+ return sal_True;
+ }
+ catch( ::com::sun::star::registry::InvalidRegistryException& )
+ {
+ }
+ }
+ return sal_False;
+ }
+
+ VCL_DLLPUBLIC void* SAL_CALL component_getFactory(
+ const sal_Char* pImplementationName,
+ void* pXUnoSMgr,
+ void* /*pXUnoKey*/
+ )
+ {
+ void* pRet = 0;
+
+ if( pXUnoSMgr )
+ {
+ Reference< ::com::sun::star::lang::XMultiServiceFactory > xMgr(
+ reinterpret_cast< ::com::sun::star::lang::XMultiServiceFactory* >( pXUnoSMgr )
+ );
+ Reference< ::com::sun::star::lang::XSingleServiceFactory > xFactory;
+ if( vcl_session_getImplementationName().equalsAscii( pImplementationName ) )
+ {
+ xFactory = ::cppu::createSingleFactory(
+ xMgr, vcl_session_getImplementationName(), vcl_session_createInstance,
+ vcl_session_getSupportedServiceNames() );
+ }
+ else if( vcl::DisplayAccess_getImplementationName().equalsAscii( pImplementationName ) )
+ {
+ xFactory = ::cppu::createSingleFactory(
+ xMgr, vcl::DisplayAccess_getImplementationName(), vcl::DisplayAccess_createInstance,
+ vcl::DisplayAccess_getSupportedServiceNames() );
+ }
+ else if( vcl::FontIdentificator_getImplementationName().equalsAscii( pImplementationName ) )
+ {
+ xFactory = ::cppu::createSingleFactory(
+ xMgr, vcl::FontIdentificator_getImplementationName(), vcl::FontIdentificator_createInstance,
+ vcl::FontIdentificator_getSupportedServiceNames() );
+ }
+ else if( vcl::Clipboard_getImplementationName().equalsAscii( pImplementationName ) )
+ {
+ xFactory = vcl::Clipboard_createFactory( xMgr );
+ }
+ else if( vcl::DragSource_getImplementationName().equalsAscii( pImplementationName ) )
+ {
+ xFactory = ::cppu::createSingleFactory(
+ xMgr, vcl::DragSource_getImplementationName(), vcl::DragSource_createInstance,
+ vcl::DragSource_getSupportedServiceNames() );
+ }
+ else if( vcl::DropTarget_getImplementationName().equalsAscii( pImplementationName ) )
+ {
+ xFactory = ::cppu::createSingleFactory(
+ xMgr, vcl::DropTarget_getImplementationName(), vcl::DropTarget_createInstance,
+ vcl::DropTarget_getSupportedServiceNames() );
+ }
+ if( xFactory.is() )
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ }
+ return pRet;
+ }
+
+} /* extern "C" */
diff --git a/vcl/source/components/fontident.cxx b/vcl/source/components/fontident.cxx
new file mode 100644
index 000000000000..ad309e4f2560
--- /dev/null
+++ b/vcl/source/components/fontident.cxx
@@ -0,0 +1,211 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XMaterialHolder.hpp>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include "vcl/svapp.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/font.hxx"
+
+#include <cppuhelper/implbase3.hxx>
+
+#include <tools/debug.hxx>
+
+
+using ::rtl::OUString;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::awt;
+
+// -----------------------------------------------------------------------
+
+namespace vcl
+{
+
+class FontIdentificator : public ::cppu::WeakAggImplHelper3< XMaterialHolder, XInitialization, XServiceInfo >
+{
+ Font m_aFont;
+public:
+FontIdentificator() {}
+ virtual ~FontIdentificator();
+
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) throw (RuntimeException);
+ virtual ::sal_Bool SAL_CALL supportsService( const OUString& ) throw (RuntimeException);
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException);
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& ) throw (Exception, RuntimeException);
+
+ // XMaterialHolder
+ virtual Any SAL_CALL getMaterial() throw(RuntimeException);
+
+};
+
+// --------------------------------------------------------------------
+
+FontIdentificator::~FontIdentificator()
+{
+}
+
+void SAL_CALL FontIdentificator::initialize( const Sequence<Any>& i_rArgs ) throw(Exception,RuntimeException)
+{
+ if( !ImplGetSVData() )
+ return; // VCL not initialized
+
+ sal_uInt32 nArgs = i_rArgs.getLength();
+ const Any* pArgs = i_rArgs.getConstArray();
+ Sequence< sal_Int8 > aFontBuf;
+ for( sal_uInt32 i = 0; i < nArgs; i++ )
+ {
+ if( pArgs[i] >>= aFontBuf )
+ {
+ m_aFont = Font::identifyFont( aFontBuf.getConstArray(), aFontBuf.getLength() );
+ break;
+ }
+ }
+}
+
+Any SAL_CALL FontIdentificator::getMaterial() throw(RuntimeException)
+{
+ if( !ImplGetSVData() )
+ return Any(); // VCL not initialized
+
+ FontDescriptor aFD;
+ aFD.Name = m_aFont.GetName();
+ aFD.Height = 0;
+ aFD.Width = 0;
+ aFD.StyleName = m_aFont.GetStyleName();
+ aFD.CharSet = 0;
+ aFD.CharacterWidth = 0;
+ aFD.Underline = 0;
+ aFD.Strikeout = 0;
+ aFD.Orientation = 0;
+ aFD.Kerning = sal_False;
+ aFD.WordLineMode = sal_False;
+ aFD.Type = 0;
+ switch( m_aFont.GetFamily() )
+ {
+ case FAMILY_DECORATIVE: aFD.Family = com::sun::star::awt::FontFamily::DECORATIVE;break;
+ case FAMILY_MODERN: aFD.Family = com::sun::star::awt::FontFamily::MODERN;break;
+ case FAMILY_ROMAN: aFD.Family = com::sun::star::awt::FontFamily::ROMAN;break;
+ case FAMILY_SCRIPT: aFD.Family = com::sun::star::awt::FontFamily::SCRIPT;break;
+ case FAMILY_SWISS: aFD.Family = com::sun::star::awt::FontFamily::SWISS;break;
+ case FAMILY_SYSTEM: aFD.Family = com::sun::star::awt::FontFamily::SYSTEM;break;
+ default:
+ aFD.Family = com::sun::star::awt::FontFamily::DONTKNOW;
+ break;
+ }
+ switch( m_aFont.GetPitch() )
+ {
+ case PITCH_VARIABLE: aFD.Pitch = com::sun::star::awt::FontPitch::VARIABLE;break;
+ case PITCH_FIXED: aFD.Pitch = com::sun::star::awt::FontPitch::FIXED;break;
+ default:
+ aFD.Pitch = com::sun::star::awt::FontPitch::DONTKNOW;
+ break;
+ }
+ switch( m_aFont.GetWeight() )
+ {
+ case WEIGHT_THIN: aFD.Weight = com::sun::star::awt::FontWeight::THIN;break;
+ case WEIGHT_ULTRALIGHT: aFD.Weight = com::sun::star::awt::FontWeight::ULTRALIGHT;break;
+ case WEIGHT_LIGHT: aFD.Weight = com::sun::star::awt::FontWeight::LIGHT;break;
+ case WEIGHT_SEMILIGHT: aFD.Weight = com::sun::star::awt::FontWeight::SEMILIGHT;break;
+ case WEIGHT_MEDIUM:
+ case WEIGHT_NORMAL: aFD.Weight = com::sun::star::awt::FontWeight::NORMAL;break;
+ case WEIGHT_SEMIBOLD: aFD.Weight = com::sun::star::awt::FontWeight::SEMIBOLD;break;
+ case WEIGHT_BOLD: aFD.Weight = com::sun::star::awt::FontWeight::BOLD;break;
+ case WEIGHT_ULTRABOLD: aFD.Weight = com::sun::star::awt::FontWeight::ULTRABOLD;break;
+ case WEIGHT_BLACK: aFD.Weight = com::sun::star::awt::FontWeight::BLACK;break;
+ default:
+ aFD.Weight = com::sun::star::awt::FontWeight::DONTKNOW;
+ break;
+ }
+ switch( m_aFont.GetItalic() )
+ {
+ case ITALIC_OBLIQUE: aFD.Slant = com::sun::star::awt::FontSlant_OBLIQUE;break;
+ case ITALIC_NORMAL: aFD.Slant = com::sun::star::awt::FontSlant_ITALIC;break;
+ default:
+ aFD.Slant = com::sun::star::awt::FontSlant_DONTKNOW;
+ break;
+ }
+ return makeAny( aFD );
+}
+
+Sequence< OUString > FontIdentificator_getSupportedServiceNames()
+{
+ static OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.FontIdentificator" ) );
+ static Sequence< OUString > aServiceNames( &aServiceName, 1 );
+ return aServiceNames;
+}
+
+OUString FontIdentificator_getImplementationName()
+{
+ return OUString( RTL_CONSTASCII_USTRINGPARAM( "vcl::FontIdentificator" ) );
+}
+
+Reference< XInterface > SAL_CALL FontIdentificator_createInstance( const Reference< XMultiServiceFactory >& )
+{
+ return static_cast< ::cppu::OWeakObject * >( new FontIdentificator );
+}
+
+
+// XServiceInfo
+OUString SAL_CALL FontIdentificator::getImplementationName() throw (RuntimeException)
+{
+ return FontIdentificator_getImplementationName();
+}
+
+sal_Bool SAL_CALL FontIdentificator::supportsService( const OUString& i_rServiceName ) throw (RuntimeException)
+{
+ Sequence< OUString > aSN( FontIdentificator_getSupportedServiceNames() );
+ for( sal_Int32 nService = 0; nService < aSN.getLength(); nService++ )
+ {
+ if( aSN[nService] == i_rServiceName )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+Sequence< OUString > SAL_CALL FontIdentificator::getSupportedServiceNames() throw (RuntimeException)
+{
+ return FontIdentificator_getSupportedServiceNames();
+}
+
+} // namespace vcl
diff --git a/vcl/source/components/makefile.mk b/vcl/source/components/makefile.mk
new file mode 100644
index 000000000000..e30975dbc099
--- /dev/null
+++ b/vcl/source/components/makefile.mk
@@ -0,0 +1,51 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=components
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/display.obj \
+ $(SLO)$/dtranscomp.obj \
+ $(SLO)$/fontident.obj \
+ $(SLO)$/factory.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx
new file mode 100644
index 000000000000..d4f29e224e7b
--- /dev/null
+++ b/vcl/source/control/button.cxx
@@ -0,0 +1,4522 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/debug.hxx>
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+#include <vcl/svdata.hxx>
+#ifndef _SV_IAMGE_HXX
+#include <vcl/image.hxx>
+#endif
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/dialog.hxx>
+#include <vcl/fixed.hxx>
+#include <tools/poly.hxx>
+#include <vcl/button.hxx>
+#include <vcl/window.h>
+#include <vcl/controldata.hxx>
+#ifndef _SV_NATIVEWIDGET_HXX
+#include <vcl/salnativewidgets.hxx>
+#endif
+#include <vcl/edit.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+
+
+
+// =======================================================================
+
+#define PUSHBUTTON_VIEW_STYLE (WB_3DLOOK | \
+ WB_LEFT | WB_CENTER | WB_RIGHT | \
+ WB_TOP | WB_VCENTER | WB_BOTTOM | \
+ WB_WORDBREAK | WB_NOLABEL | \
+ WB_DEFBUTTON | WB_NOLIGHTBORDER | \
+ WB_RECTSTYLE | WB_SMALLSTYLE | \
+ WB_TOGGLE )
+#define RADIOBUTTON_VIEW_STYLE (WB_3DLOOK | \
+ WB_LEFT | WB_CENTER | WB_RIGHT | \
+ WB_TOP | WB_VCENTER | WB_BOTTOM | \
+ WB_WORDBREAK | WB_NOLABEL)
+#define CHECKBOX_VIEW_STYLE (WB_3DLOOK | \
+ WB_LEFT | WB_CENTER | WB_RIGHT | \
+ WB_TOP | WB_VCENTER | WB_BOTTOM | \
+ WB_WORDBREAK | WB_NOLABEL)
+
+// =======================================================================
+
+class ImplCommonButtonData
+{
+public:
+ Rectangle maFocusRect;
+ Rectangle maSymbolRect;
+ USHORT mnButtonState;
+ BOOL mbSmallSymbol;
+
+ Image maImage;
+ Image maImageHC;
+ BitmapEx* mpBitmapEx;
+ BitmapEx* mpBitmapExHC;
+ ImageAlign meImageAlign;
+ SymbolAlign meSymbolAlign;
+
+public:
+ ImplCommonButtonData();
+ ~ImplCommonButtonData();
+};
+
+// -----------------------------------------------------------------------
+ImplCommonButtonData::ImplCommonButtonData()
+{
+ mnButtonState = 0;
+ mbSmallSymbol = FALSE;
+
+ mpBitmapEx = NULL;
+ mpBitmapExHC = NULL;
+ meImageAlign = IMAGEALIGN_TOP;
+ meSymbolAlign = SYMBOLALIGN_LEFT;
+}
+
+// -----------------------------------------------------------------------
+ImplCommonButtonData::~ImplCommonButtonData()
+{
+ delete mpBitmapEx;
+ delete mpBitmapExHC;
+}
+
+// =======================================================================
+
+Button::Button( WindowType nType ) :
+ Control( nType )
+{
+ mpButtonData = new ImplCommonButtonData;
+}
+
+// -----------------------------------------------------------------------
+
+Button::Button( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_BUTTON )
+{
+ mpButtonData = new ImplCommonButtonData;
+ ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Button::Button( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_BUTTON )
+{
+ rResId.SetRT( RSC_BUTTON );
+ mpButtonData = new ImplCommonButtonData;
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle, NULL );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+Button::~Button()
+{
+ delete mpButtonData;
+}
+
+// -----------------------------------------------------------------------
+
+void Button::Click()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_BUTTON_CLICK, maClickHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+XubString Button::GetStandardText( StandardButtonType eButton )
+{
+ static struct
+ {
+ sal_uInt32 nResId;
+ const char* pDefText;
+ } aResIdAry[BUTTON_COUNT] =
+ {
+ { SV_BUTTONTEXT_OK, "~OK" },
+ { SV_BUTTONTEXT_CANCEL, "~Cancel" },
+ { SV_BUTTONTEXT_YES, "~Yes" },
+ { SV_BUTTONTEXT_NO, "~No" },
+ { SV_BUTTONTEXT_RETRY, "~Retry" },
+ { SV_BUTTONTEXT_HELP, "~Help" },
+ { SV_BUTTONTEXT_CLOSE, "~Close" },
+ { SV_BUTTONTEXT_MORE, "~More" },
+ { SV_BUTTONTEXT_IGNORE, "~Ignore" },
+ { SV_BUTTONTEXT_ABORT, "~Abort" },
+ { SV_BUTTONTEXT_LESS, "~Less" }
+ };
+
+ String aText;
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ {
+ ResId aResId( aResIdAry[(USHORT)eButton].nResId, *pResMgr );
+ aText = String( aResId );
+ }
+ else
+ {
+ ByteString aT( aResIdAry[(USHORT)eButton].pDefText );
+ aText = String( aT, RTL_TEXTENCODING_ASCII_US );
+ }
+ return aText;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Button::GetStandardHelpText( StandardButtonType /* eButton */ )
+{
+ XubString aHelpText;
+ return aHelpText;
+}
+// -----------------------------------------------------------------------
+BOOL Button::SetModeImage( const Image& rImage, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ {
+ if ( rImage != mpButtonData->maImage )
+ {
+ delete mpButtonData->mpBitmapEx;
+
+ mpButtonData->mpBitmapEx = NULL;
+ mpButtonData->maImage = rImage;
+
+ StateChanged( STATE_CHANGE_DATA );
+ }
+ }
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ if( rImage != mpButtonData->maImageHC )
+ {
+ delete mpButtonData->mpBitmapExHC;
+
+ mpButtonData->mpBitmapExHC = NULL;
+ mpButtonData->maImageHC = rImage;
+
+ StateChanged( STATE_CHANGE_DATA );
+ }
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+const Image Button::GetModeImage( BmpColorMode eMode ) const
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ {
+ return mpButtonData->maImage;
+ }
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ return mpButtonData->maImageHC;
+ }
+ else
+ return Image();
+}
+
+// -----------------------------------------------------------------------
+BOOL Button::HasImage() const
+{
+ return !!(mpButtonData->maImage);
+}
+
+// -----------------------------------------------------------------------
+void Button::SetImageAlign( ImageAlign eAlign )
+{
+ if ( mpButtonData->meImageAlign != eAlign )
+ {
+ mpButtonData->meImageAlign = eAlign;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+ImageAlign Button::GetImageAlign() const
+{
+ return mpButtonData->meImageAlign;
+}
+
+// -----------------------------------------------------------------------
+BOOL Button::SetModeBitmap( const BitmapEx& rBitmap, BmpColorMode eMode )
+{
+ if ( SetModeImage( rBitmap, eMode ) )
+ {
+ if( eMode == BMP_COLOR_NORMAL )
+ {
+ if ( !mpButtonData->mpBitmapEx )
+ mpButtonData->mpBitmapEx = new BitmapEx( rBitmap );
+ }
+ else if ( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ if ( !mpButtonData->mpBitmapExHC )
+ mpButtonData->mpBitmapExHC = new BitmapEx( rBitmap );
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+BitmapEx Button::GetModeBitmap( BmpColorMode eMode ) const
+{
+ BitmapEx aBmp;
+
+ if ( eMode == BMP_COLOR_NORMAL )
+ {
+ if ( mpButtonData->mpBitmapEx )
+ aBmp = *( mpButtonData->mpBitmapEx );
+ }
+ else if ( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ if ( mpButtonData->mpBitmapExHC )
+ aBmp = *( mpButtonData->mpBitmapExHC );
+ }
+
+ return aBmp;
+}
+
+// -----------------------------------------------------------------------
+void Button::SetFocusRect( const Rectangle& rFocusRect )
+{
+ ImplSetFocusRect( rFocusRect );
+}
+
+// -----------------------------------------------------------------------
+const Rectangle& Button::GetFocusRect() const
+{
+ return ImplGetFocusRect();
+}
+
+// -----------------------------------------------------------------------
+
+const Rectangle& Button::ImplGetSymbolRect() const
+{
+ return mpButtonData->maSymbolRect;
+}
+
+void Button::ImplSetSymbolRect( const Rectangle& i_rRect )
+{
+ mpButtonData->maSymbolRect = i_rRect;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Button::ImplGetTextStyle( XubString& rText, WinBits nWinStyle,
+ ULONG nDrawFlags )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ USHORT nTextStyle = FixedText::ImplGetTextStyle( nWinStyle & ~WB_DEFBUTTON );
+
+ if ( nDrawFlags & WINDOW_DRAW_NOMNEMONIC )
+ {
+ if ( nTextStyle & TEXT_DRAW_MNEMONIC )
+ {
+ rText = GetNonMnemonicString( rText );
+ nTextStyle &= ~TEXT_DRAW_MNEMONIC;
+ }
+ }
+
+ if ( !(nDrawFlags & WINDOW_DRAW_NODISABLE) )
+ {
+ if ( !IsEnabled() )
+ nTextStyle |= TEXT_DRAW_DISABLE;
+ }
+
+ if ( (nDrawFlags & WINDOW_DRAW_MONO) ||
+ (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ nTextStyle |= TEXT_DRAW_MONO;
+
+ return nTextStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void Button::ImplDrawAlignedImage( OutputDevice* pDev, Point& rPos,
+ Size& rSize, BOOL bLayout,
+ ULONG nImageSep, ULONG nDrawFlags,
+ USHORT nTextStyle, Rectangle *pSymbolRect,
+ bool bAddImageSep )
+{
+ XubString aText( GetText() );
+ BOOL bDrawImage = HasImage() && ! ( ImplGetButtonState() & BUTTON_DRAW_NOIMAGE );
+ BOOL bDrawText = aText.Len() && ! ( ImplGetButtonState() & BUTTON_DRAW_NOTEXT );
+ BOOL bHasSymbol = pSymbolRect ? TRUE : FALSE;
+
+ // No text and no image => nothing to do => return
+ if ( !bDrawImage && !bDrawText && !bHasSymbol )
+ return;
+
+ WinBits nWinStyle = GetStyle();
+ Rectangle aOutRect( rPos, rSize );
+ MetricVector *pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String *pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+ ImageAlign eImageAlign = mpButtonData->meImageAlign;
+ Size aImageSize = mpButtonData->maImage.GetSizePixel();
+
+ if ( ( nDrawFlags & WINDOW_DRAW_NOMNEMONIC ) &&
+ ( nTextStyle & TEXT_DRAW_MNEMONIC ) )
+ {
+ aText = GetNonMnemonicString( aText );
+ nTextStyle &= ~TEXT_DRAW_MNEMONIC;
+ }
+
+ aImageSize.Width() = CalcZoom( aImageSize.Width() );
+ aImageSize.Height() = CalcZoom( aImageSize.Height() );
+
+ // Drawing text or symbol only is simple, use style and output rectangle
+ if ( bHasSymbol && !bDrawImage && !bDrawText )
+ {
+ *pSymbolRect = aOutRect;
+ return;
+ }
+ else if ( bDrawText && !bDrawImage && !bHasSymbol )
+ {
+ DrawControlText( *pDev, aOutRect, aText, nTextStyle, pVector, pDisplayText );
+
+ ImplSetFocusRect( aOutRect );
+ rSize = aOutRect.GetSize();
+ rPos = aOutRect.TopLeft();
+
+ return;
+ }
+
+ // check for HC mode ( image only! )
+ Image *pImage = &(mpButtonData->maImage);
+ BitmapEx *pBitmapEx = mpButtonData->mpBitmapEx;
+
+ if( !!(mpButtonData->maImageHC) )
+ {
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ pImage = &(mpButtonData->maImageHC);
+ pBitmapEx = mpButtonData->mpBitmapExHC;
+ }
+ }
+
+ if ( pBitmapEx && ( pDev->GetOutDevType() == OUTDEV_PRINTER ) )
+ {
+ // Die Groesse richtet sich nach dem Bildschirm, soll auf
+ // dem Drucker genau so aussehen...
+ MapMode aMap100thMM( MAP_100TH_MM );
+ aImageSize = PixelToLogic( aImageSize, aMap100thMM );
+ aImageSize = pDev->LogicToPixel( aImageSize, aMap100thMM );
+ }
+
+ Size aTextSize;
+ Size aSymbolSize;
+ Size aMax;
+ Point aImagePos = rPos;
+ Point aTextPos = rPos;
+ Rectangle aUnion = Rectangle( aImagePos, aImageSize );
+ Rectangle aSymbol;
+ long nSymbolHeight = 0;
+
+ if ( bDrawText || bHasSymbol )
+ {
+ // Get the size of the text output area ( the symbol will be drawn in
+ // this area as well, so the symbol rectangle will be calculated here, too )
+
+ Rectangle aRect = Rectangle( Point(), rSize );
+ Size aTSSize;
+
+ if ( bHasSymbol )
+ {
+ if ( bDrawText )
+ {
+ nSymbolHeight = pDev->GetTextHeight();
+ if ( mpButtonData->mbSmallSymbol )
+ nSymbolHeight = nSymbolHeight * 3 / 4;
+
+ aSymbol = Rectangle( Point(), Size( nSymbolHeight, nSymbolHeight ) );
+ ImplCalcSymbolRect( aSymbol );
+ aRect.Left() += 3 * nSymbolHeight / 2;
+ aTSSize.Width() = 3 * nSymbolHeight / 2;
+ }
+ else
+ {
+ aSymbol = Rectangle( Point(), rSize );
+ ImplCalcSymbolRect( aSymbol );
+ aTSSize.Width() = aSymbol.GetWidth();
+ }
+ aTSSize.Height() = aSymbol.GetHeight();
+ aSymbolSize = aSymbol.GetSize();
+ }
+
+ if ( bDrawText )
+ {
+ if ( ( eImageAlign == IMAGEALIGN_LEFT_TOP ) ||
+ ( eImageAlign == IMAGEALIGN_LEFT ) ||
+ ( eImageAlign == IMAGEALIGN_LEFT_BOTTOM ) ||
+ ( eImageAlign == IMAGEALIGN_RIGHT_TOP ) ||
+ ( eImageAlign == IMAGEALIGN_RIGHT ) ||
+ ( eImageAlign == IMAGEALIGN_RIGHT_BOTTOM ) )
+ {
+ aRect.Right() -= ( aImageSize.Width() + nImageSep );
+ }
+ else if ( ( eImageAlign == IMAGEALIGN_TOP_LEFT ) ||
+ ( eImageAlign == IMAGEALIGN_TOP ) ||
+ ( eImageAlign == IMAGEALIGN_TOP_RIGHT ) ||
+ ( eImageAlign == IMAGEALIGN_BOTTOM_LEFT ) ||
+ ( eImageAlign == IMAGEALIGN_BOTTOM ) ||
+ ( eImageAlign == IMAGEALIGN_BOTTOM_RIGHT ) )
+ {
+ aRect.Bottom() -= ( aImageSize.Height() + nImageSep );
+ }
+
+ aRect = pDev->GetTextRect( aRect, aText, nTextStyle );
+ aTextSize = aRect.GetSize();
+
+ aTSSize.Width() += aTextSize.Width();
+
+ if ( aTSSize.Height() < aTextSize.Height() )
+ aTSSize.Height() = aTextSize.Height();
+
+ if( bAddImageSep && bDrawImage )
+ {
+ long nDiff = (aImageSize.Height() - aTextSize.Height()) / 3;
+ if( nDiff > 0 )
+ nImageSep += nDiff;
+ }
+ }
+
+ aMax.Width() = aTSSize.Width() > aImageSize.Width() ? aTSSize.Width() : aImageSize.Width();
+ aMax.Height() = aTSSize.Height() > aImageSize.Height() ? aTSSize.Height() : aImageSize.Height();
+
+ // Now calculate the output area for the image and the text acording to the image align flags
+
+ if ( ( eImageAlign == IMAGEALIGN_LEFT ) ||
+ ( eImageAlign == IMAGEALIGN_RIGHT ) )
+ {
+ aImagePos.Y() = rPos.Y() + ( aMax.Height() - aImageSize.Height() ) / 2;
+ aTextPos.Y() = rPos.Y() + ( aMax.Height() - aTSSize.Height() ) / 2;
+ }
+ else if ( ( eImageAlign == IMAGEALIGN_LEFT_BOTTOM ) ||
+ ( eImageAlign == IMAGEALIGN_RIGHT_BOTTOM ) )
+ {
+ aImagePos.Y() = rPos.Y() + aMax.Height() - aImageSize.Height();
+ aTextPos.Y() = rPos.Y() + aMax.Height() - aTSSize.Height();
+ }
+ else if ( ( eImageAlign == IMAGEALIGN_TOP ) ||
+ ( eImageAlign == IMAGEALIGN_BOTTOM ) )
+ {
+ aImagePos.X() = rPos.X() + ( aMax.Width() - aImageSize.Width() ) / 2;
+ aTextPos.X() = rPos.X() + ( aMax.Width() - aTSSize.Width() ) / 2;
+ }
+ else if ( ( eImageAlign == IMAGEALIGN_TOP_RIGHT ) ||
+ ( eImageAlign == IMAGEALIGN_BOTTOM_RIGHT ) )
+ {
+ aImagePos.X() = rPos.X() + aMax.Width() - aImageSize.Width();
+ aTextPos.X() = rPos.X() + aMax.Width() - aTSSize.Width();
+ }
+
+ if ( ( eImageAlign == IMAGEALIGN_LEFT_TOP ) ||
+ ( eImageAlign == IMAGEALIGN_LEFT ) ||
+ ( eImageAlign == IMAGEALIGN_LEFT_BOTTOM ) )
+ {
+ aTextPos.X() = rPos.X() + aImageSize.Width() + nImageSep;
+ }
+ else if ( ( eImageAlign == IMAGEALIGN_RIGHT_TOP ) ||
+ ( eImageAlign == IMAGEALIGN_RIGHT ) ||
+ ( eImageAlign == IMAGEALIGN_RIGHT_BOTTOM ) )
+ {
+ aImagePos.X() = rPos.X() + aTSSize.Width() + nImageSep;
+ }
+ else if ( ( eImageAlign == IMAGEALIGN_TOP_LEFT ) ||
+ ( eImageAlign == IMAGEALIGN_TOP ) ||
+ ( eImageAlign == IMAGEALIGN_TOP_RIGHT ) )
+ {
+ aTextPos.Y() = rPos.Y() + aImageSize.Height() + nImageSep;
+ }
+ else if ( ( eImageAlign == IMAGEALIGN_BOTTOM_LEFT ) ||
+ ( eImageAlign == IMAGEALIGN_BOTTOM ) ||
+ ( eImageAlign == IMAGEALIGN_BOTTOM_RIGHT ) )
+ {
+ aImagePos.Y() = rPos.Y() + aTSSize.Height() + nImageSep;
+ }
+ else if ( eImageAlign == IMAGEALIGN_CENTER )
+ {
+ aImagePos.X() = rPos.X() + ( aMax.Width() - aImageSize.Width() ) / 2;
+ aImagePos.Y() = rPos.Y() + ( aMax.Height() - aImageSize.Height() ) / 2;
+ aTextPos.X() = rPos.X() + ( aMax.Width() - aTSSize.Width() ) / 2;
+ aTextPos.Y() = rPos.Y() + ( aMax.Height() - aTSSize.Height() ) / 2;
+ }
+ aUnion = Rectangle( aImagePos, aImageSize );
+ aUnion.Union( Rectangle( aTextPos, aTSSize ) );
+ }
+
+ // Now place the combination of text and image in the output area of the button
+ // according to the window style (WinBits)
+ long nXOffset = 0;
+ long nYOffset = 0;
+
+ if ( nWinStyle & WB_CENTER )
+ {
+ nXOffset = ( rSize.Width() - aUnion.GetWidth() ) / 2;
+ }
+ else if ( nWinStyle & WB_RIGHT )
+ {
+ nXOffset = rSize.Width() - aUnion.GetWidth();
+ }
+
+ if ( nWinStyle & WB_VCENTER )
+ {
+ nYOffset = ( rSize.Height() - aUnion.GetHeight() ) / 2;
+ }
+ else if ( nWinStyle & WB_BOTTOM )
+ {
+ nYOffset = rSize.Height() - aUnion.GetHeight();
+ }
+
+ // the top left corner should always be visible, so we don't allow negative offsets
+ if ( nXOffset < 0 ) nXOffset = 0;
+ if ( nYOffset < 0 ) nYOffset = 0;
+
+ aImagePos.X() += nXOffset;
+ aImagePos.Y() += nYOffset;
+ aTextPos.X() += nXOffset;
+ aTextPos.Y() += nYOffset;
+
+ // set rPos and rSize to the union
+ rSize = aUnion.GetSize();
+ rPos.X() += nXOffset;
+ rPos.Y() += nYOffset;
+
+ if ( bHasSymbol )
+ {
+ if ( mpButtonData->meSymbolAlign == SYMBOLALIGN_RIGHT )
+ {
+ Point aRightPos = Point( aTextPos.X() + aTextSize.Width() + aSymbolSize.Width()/2, aTextPos.Y() );
+ *pSymbolRect = Rectangle( aRightPos, aSymbolSize );
+ }
+ else
+ {
+ *pSymbolRect = Rectangle( aTextPos, aSymbolSize );
+ aTextPos.X() += ( 3 * nSymbolHeight / 2 );
+ }
+ if ( mpButtonData->mbSmallSymbol )
+ {
+ nYOffset = (aUnion.GetHeight() - aSymbolSize.Height())/2;
+ pSymbolRect->setY( aTextPos.Y() + nYOffset );
+ }
+ }
+
+ USHORT nStyle = 0;
+
+ if ( ! ( nDrawFlags & WINDOW_DRAW_NODISABLE ) &&
+ ! IsEnabled() )
+ nStyle |= IMAGE_DRAW_DISABLE;
+
+ if ( pBitmapEx && ( pDev->GetOutDevType() == OUTDEV_PRINTER ) )
+ {
+ // Fuer die BitmapEx ueberlegt sich KA noch, wie man die disablete
+ // Darstellung hinbekommt...
+ pBitmapEx->Draw( pDev, aImagePos, aImageSize /*, nStyle*/ );
+ }
+ else
+ {
+ if ( IsZoom() )
+ pDev->DrawImage( aImagePos, aImageSize, *pImage, nStyle );
+ else
+ pDev->DrawImage( aImagePos, *pImage, nStyle );
+ }
+
+ if ( bDrawText )
+ {
+ ImplSetFocusRect( Rectangle( aTextPos, aTextSize ) );
+ pDev->DrawText( Rectangle( aTextPos, aTextSize ), aText, nTextStyle, pVector, pDisplayText );
+ }
+ else
+ {
+ ImplSetFocusRect( Rectangle( aImagePos, aImageSize ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+void Button::ImplSetFocusRect( const Rectangle &rFocusRect )
+{
+ Rectangle aFocusRect = rFocusRect;
+ Rectangle aOutputRect = Rectangle( Point(), GetOutputSizePixel() );
+
+ if ( ! aFocusRect.IsEmpty() )
+ {
+ aFocusRect.Left()--;
+ aFocusRect.Top()--;
+ aFocusRect.Right()++;
+ aFocusRect.Bottom()++;
+ }
+
+ if ( aFocusRect.Left() < aOutputRect.Left() ) aFocusRect.Left() = aOutputRect.Left();
+ if ( aFocusRect.Top() < aOutputRect.Top() ) aFocusRect.Top() = aOutputRect.Top();
+ if ( aFocusRect.Right() > aOutputRect.Right() ) aFocusRect.Right() = aOutputRect.Right();
+ if ( aFocusRect.Bottom() > aOutputRect.Bottom() ) aFocusRect.Bottom() = aOutputRect.Bottom();
+
+ mpButtonData->maFocusRect = aFocusRect;
+}
+
+// -----------------------------------------------------------------------
+const Rectangle& Button::ImplGetFocusRect() const
+{
+ return mpButtonData->maFocusRect;
+}
+
+// -----------------------------------------------------------------------
+USHORT& Button::ImplGetButtonState()
+{
+ return mpButtonData->mnButtonState;
+}
+
+// -----------------------------------------------------------------------
+USHORT Button::ImplGetButtonState() const
+{
+ return mpButtonData->mnButtonState;
+}
+
+// -----------------------------------------------------------------------
+void Button::ImplSetSymbolAlign( SymbolAlign eAlign )
+{
+ if ( mpButtonData->meSymbolAlign != eAlign )
+ {
+ mpButtonData->meSymbolAlign = eAlign;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+SymbolAlign Button::ImplGetSymbolAlign() const
+{
+ return mpButtonData->meSymbolAlign;
+}
+// -----------------------------------------------------------------------
+void Button::ImplSetSmallSymbol( BOOL bSmall )
+{
+ mpButtonData->mbSmallSymbol = bSmall;
+}
+
+// -----------------------------------------------------------------------
+void Button::EnableImageDisplay( BOOL bEnable )
+{
+ if( bEnable )
+ mpButtonData->mnButtonState &= ~BUTTON_DRAW_NOIMAGE;
+ else
+ mpButtonData->mnButtonState |= BUTTON_DRAW_NOIMAGE;
+}
+
+// -----------------------------------------------------------------------
+BOOL Button::IsImageDisplayEnabled()
+{
+ return (mpButtonData->mnButtonState & BUTTON_DRAW_NOIMAGE) == 0;
+}
+
+// -----------------------------------------------------------------------
+void Button::EnableTextDisplay( BOOL bEnable )
+{
+ if( bEnable )
+ mpButtonData->mnButtonState &= ~BUTTON_DRAW_NOTEXT;
+ else
+ mpButtonData->mnButtonState |= BUTTON_DRAW_NOTEXT;
+}
+
+// -----------------------------------------------------------------------
+BOOL Button::IsTextDisplayEnabled()
+{
+ return (mpButtonData->mnButtonState & BUTTON_DRAW_NOTEXT) == 0;
+}
+
+// -----------------------------------------------------------------------
+void Button::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ // The flag SETTINGS_IN_UPDATE_SETTINGS is set when the settings changed due to a
+ // Application::SettingsChanged event. In this scenario we want to keep the style settings
+ // of our radio buttons and our check boxes.
+ if ( ( rDCEvt.GetType() == DATACHANGED_SETTINGS ) &&
+ ( rDCEvt.GetFlags() & SETTINGS_IN_UPDATE_SETTINGS ) )
+
+ {
+ const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
+ if ( pOldSettings )
+ {
+ BOOL bResetStyleSettings = FALSE;
+ AllSettings aAllSettings = GetSettings();
+ StyleSettings aStyleSetting = aAllSettings.GetStyleSettings();
+
+ USHORT nCheckBoxStyle = aStyleSetting.GetCheckBoxStyle();
+ if ( nCheckBoxStyle != pOldSettings->GetStyleSettings().GetCheckBoxStyle() )
+ {
+ aStyleSetting.SetCheckBoxStyle( pOldSettings->GetStyleSettings().GetCheckBoxStyle() );
+ bResetStyleSettings = TRUE;
+ }
+
+ USHORT nRadioButtonStyle = aStyleSetting.GetRadioButtonStyle();
+ if ( nRadioButtonStyle != pOldSettings->GetStyleSettings().GetRadioButtonStyle() )
+ {
+ aStyleSetting.SetRadioButtonStyle( pOldSettings->GetStyleSettings().GetRadioButtonStyle() );
+ bResetStyleSettings = TRUE;
+ }
+
+ if ( bResetStyleSettings )
+ {
+ aAllSettings.SetStyleSettings( pOldSettings->GetStyleSettings() );
+ SetSettings( aAllSettings );
+ }
+ }
+ }
+}
+
+void Button::SetSmallSymbol (bool small)
+{
+ ImplSetSmallSymbol (small);
+}
+
+bool Button::IsSmallSymbol () const
+{
+ return mpButtonData->mbSmallSymbol;
+}
+
+// =======================================================================
+
+void PushButton::ImplInitPushButtonData()
+{
+ mpWindowImpl->mbPushButton = TRUE;
+
+ meSymbol = SYMBOL_NOSYMBOL;
+ meState = STATE_NOCHECK;
+ meSaveValue = STATE_NOCHECK;
+ mnDDStyle = 0;
+ mbPressed = FALSE;
+ mbInUserDraw = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( pParent->GetWindow( WINDOW_LASTCHILD ), nStyle );
+ Button::ImplInit( pParent, nStyle, NULL );
+
+ if ( nStyle & WB_NOLIGHTBORDER )
+ ImplGetButtonState() |= BUTTON_DRAW_NOLIGHTBORDER;
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits PushButton::ImplInitStyle( const Window* pPrevWindow, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+
+ // if no alignment is given, default to "vertically centered". This is because since
+ // #i26046#, we respect the vertical alignment flags (previously we didn't completely),
+ // but we of course want to look as before when no vertical alignment is specified
+ if ( ( nStyle & ( WB_TOP | WB_VCENTER | WB_BOTTOM ) ) == 0 )
+ nStyle |= WB_VCENTER;
+
+ if ( !(nStyle & WB_NOGROUP) &&
+ (!pPrevWindow ||
+ ((pPrevWindow->GetType() != WINDOW_PUSHBUTTON) &&
+ (pPrevWindow->GetType() != WINDOW_OKBUTTON) &&
+ (pPrevWindow->GetType() != WINDOW_CANCELBUTTON) &&
+ (pPrevWindow->GetType() != WINDOW_HELPBUTTON)) ) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------
+
+const Font& PushButton::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetPushButtonFont();
+}
+
+// -----------------------------------------------------------------
+const Color& PushButton::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetButtonTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Button::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ SetBackground();
+ // #i38498#: do not check for GetParent()->IsChildTransparentModeEnabled()
+ // otherwise the formcontrol button will be overdrawn due to PARENTCLIPMODE_NOCLIP
+ // for radio and checkbox this is ok as they shoud appear transparent in documents
+ if ( IsNativeControlSupported( CTRL_PUSHBUTTON, PART_ENTIRE_CONTROL ) )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ mpWindowImpl->mbUseNativeFocus = (GetStyle() & WB_FLATBUTTON)
+ ? false
+ : ImplGetSVData()->maNWFData.mbNoFocusRects;
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::ImplDrawPushButtonFrame( Window* pDev,
+ Rectangle& rRect, USHORT nStyle )
+{
+ if ( !(pDev->GetStyle() & (WB_RECTSTYLE | WB_SMALLSTYLE)) )
+ {
+ StyleSettings aStyleSettings = pDev->GetSettings().GetStyleSettings();
+ if ( pDev->IsControlBackground() )
+ aStyleSettings.Set3DColors( pDev->GetControlBackground() );
+
+ USHORT nPushButtonSysStyle = aStyleSettings.GetPushButtonStyle() & STYLE_PUSHBUTTON_STYLE;
+ if ( nPushButtonSysStyle == STYLE_PUSHBUTTON_MAC )
+ {
+ pDev->SetLineColor();
+ pDev->SetFillColor( aStyleSettings.GetFaceColor() );
+ pDev->DrawRect( rRect );
+
+ if ( (aStyleSettings.GetOptions() & STYLE_OPTION_MONO) ||
+ (pDev->GetOutDevType() == OUTDEV_PRINTER) )
+ nStyle |= BUTTON_DRAW_MONO;
+
+ if ( nStyle & BUTTON_DRAW_DEFAULT )
+ {
+ if ( nStyle & BUTTON_DRAW_MONO )
+ pDev->SetLineColor( Color( COL_BLACK ) );
+ else
+ pDev->SetLineColor( aStyleSettings.GetDarkShadowColor() );
+
+ pDev->DrawLine( Point( rRect.Left()+3, rRect.Top() ),
+ Point( rRect.Right()-3, rRect.Top() ) );
+ pDev->DrawLine( Point( rRect.Left()+3, rRect.Bottom() ),
+ Point( rRect.Right()-3, rRect.Bottom() ) );
+ pDev->DrawLine( Point( rRect.Left(), rRect.Top()+3 ),
+ Point( rRect.Left(), rRect.Bottom()-3 ) );
+ pDev->DrawLine( Point( rRect.Right(), rRect.Top()+3 ),
+ Point( rRect.Right(), rRect.Bottom()-3 ) );
+ pDev->DrawPixel( Point( rRect.Left()+2, rRect.Top()+1 ) );
+ pDev->DrawPixel( Point( rRect.Left()+1, rRect.Top()+2 ) );
+ pDev->DrawPixel( Point( rRect.Right()-2, rRect.Top()+1 ) );
+ pDev->DrawPixel( Point( rRect.Right()-1, rRect.Top()+2 ) );
+ pDev->DrawPixel( Point( rRect.Left()+2, rRect.Bottom()-1 ) );
+ pDev->DrawPixel( Point( rRect.Left()+1, rRect.Bottom()-2 ) );
+ pDev->DrawPixel( Point( rRect.Right()-2, rRect.Bottom()-1 ) );
+ pDev->DrawPixel( Point( rRect.Right()-1, rRect.Bottom()-2 ) );
+
+ if ( nStyle & BUTTON_DRAW_MONO )
+ pDev->SetLineColor( Color( COL_BLACK ) );
+ else
+ pDev->SetLineColor( aStyleSettings.GetShadowColor() );
+ pDev->DrawLine( Point( rRect.Left()+3, rRect.Bottom()-1 ),
+ Point( rRect.Right()-3, rRect.Bottom()-1 ) );
+ pDev->DrawLine( Point( rRect.Right()-1, rRect.Top()+3 ),
+ Point( rRect.Right()-1, rRect.Bottom()-3 ) );
+ pDev->DrawPixel( Point( rRect.Right()-3, rRect.Bottom()-2 ) );
+ pDev->DrawPixel( Point( rRect.Right()-2, rRect.Bottom()-2 ) );
+ pDev->DrawPixel( Point( rRect.Right()-2, rRect.Bottom()-3 ) );
+ }
+
+ rRect.Left() += 2;
+ rRect.Top() += 2;
+ rRect.Right() -= 2;
+ rRect.Bottom() -= 2;
+
+ if ( nStyle & BUTTON_DRAW_MONO )
+ pDev->SetLineColor( Color( COL_BLACK ) );
+ else
+ pDev->SetLineColor( aStyleSettings.GetDarkShadowColor() );
+
+ pDev->DrawLine( Point( rRect.Left()+2, rRect.Top() ),
+ Point( rRect.Right()-2, rRect.Top() ) );
+ pDev->DrawLine( Point( rRect.Left()+2, rRect.Bottom() ),
+ Point( rRect.Right()-2, rRect.Bottom() ) );
+ pDev->DrawLine( Point( rRect.Left(), rRect.Top()+2 ),
+ Point( rRect.Left(), rRect.Bottom()-2 ) );
+ pDev->DrawLine( Point( rRect.Right(), rRect.Top()+2 ),
+ Point( rRect.Right(), rRect.Bottom()-2 ) );
+ pDev->DrawPixel( Point( rRect.Left()+1, rRect.Top()+1 ) );
+ pDev->DrawPixel( Point( rRect.Right()-1, rRect.Top()+1 ) );
+ pDev->DrawPixel( Point( rRect.Left()+1, rRect.Bottom()-1 ) );
+ pDev->DrawPixel( Point( rRect.Right()-1, rRect.Bottom()-1 ) );
+
+ pDev->SetLineColor();
+ if ( nStyle & BUTTON_DRAW_CHECKED )
+ pDev->SetFillColor( aStyleSettings.GetCheckedColor() );
+ else
+ pDev->SetFillColor( aStyleSettings.GetFaceColor() );
+ pDev->DrawRect( Rectangle( rRect.Left()+2, rRect.Top()+2, rRect.Right()-2, rRect.Bottom()-2 ) );
+
+ if ( !(nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED)) )
+ {
+ if ( nStyle & BUTTON_DRAW_MONO )
+ pDev->SetLineColor( Color( COL_BLACK ) );
+ else
+ pDev->SetLineColor( aStyleSettings.GetShadowColor() );
+ pDev->DrawLine( Point( rRect.Left()+2, rRect.Bottom()-1 ),
+ Point( rRect.Right()-2, rRect.Bottom()-1 ) );
+ pDev->DrawLine( Point( rRect.Right()-1, rRect.Top()+2 ),
+ Point( rRect.Right()-1, rRect.Bottom()-2 ) );
+ pDev->DrawPixel( Point( rRect.Right()-2, rRect.Bottom()-2 ) );
+ pDev->SetLineColor( aStyleSettings.GetLightColor() );
+ }
+ else
+ pDev->SetLineColor( aStyleSettings.GetShadowColor() );
+
+ if ( !(nStyle & BUTTON_DRAW_MONO) )
+ {
+ pDev->DrawLine( Point( rRect.Left()+2, rRect.Top()+1 ),
+ Point( rRect.Right()-2, rRect.Top()+1 ) );
+ pDev->DrawLine( Point( rRect.Left()+1, rRect.Top()+2 ),
+ Point( rRect.Left()+1, rRect.Bottom()-2 ) );
+ pDev->DrawPixel( Point( rRect.Top()+2, rRect.Right()+2 ) );
+ }
+
+ rRect.Left() += 2;
+ rRect.Top() += 2;
+ rRect.Right() -= 2;
+ rRect.Bottom() -= 2;
+
+ if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) )
+ {
+ rRect.Left()++;
+ rRect.Top()++;
+ rRect.Right()++;
+ rRect.Bottom()++;
+ }
+
+ return;
+ }
+ }
+
+ DecorationView aDecoView( pDev );
+ if ( pDev->IsControlBackground() )
+ {
+ AllSettings aSettings = pDev->GetSettings();
+ AllSettings aOldSettings = aSettings;
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ aStyleSettings.Set3DColors( pDev->GetControlBackground() );
+ aSettings.SetStyleSettings( aStyleSettings );
+ pDev->OutputDevice::SetSettings( aSettings );
+ rRect = aDecoView.DrawButton( rRect, nStyle );
+ pDev->OutputDevice::SetSettings( aOldSettings );
+ }
+ else
+ rRect = aDecoView.DrawButton( rRect, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PushButton::ImplHitTestPushButton( Window* pDev,
+ const Point& rPos )
+{
+ Point aTempPoint;
+ Rectangle aTestRect( aTempPoint, pDev->GetOutputSizePixel() );
+
+ if ( !(pDev->GetStyle() & (WB_RECTSTYLE | WB_SMALLSTYLE)) )
+ {
+ const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
+
+ USHORT nPushButtonSysStyle = rStyleSettings.GetPushButtonStyle() & STYLE_PUSHBUTTON_STYLE;
+ if ( nPushButtonSysStyle == STYLE_PUSHBUTTON_MAC )
+ {
+ aTestRect.Left() += 2;
+ aTestRect.Top() += 2;
+ aTestRect.Right() -= 2;
+ aTestRect.Bottom() -= 2;
+ }
+ }
+
+ return aTestRect.IsInside( rPos );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT PushButton::ImplGetTextStyle( ULONG nDrawFlags ) const
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ USHORT nTextStyle = TEXT_DRAW_MNEMONIC | TEXT_DRAW_MULTILINE | TEXT_DRAW_ENDELLIPSIS;
+
+ if ( ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO ) ||
+ ( nDrawFlags & WINDOW_DRAW_MONO ) )
+ nTextStyle |= TEXT_DRAW_MONO;
+
+ if ( GetStyle() & WB_WORDBREAK )
+ nTextStyle |= TEXT_DRAW_WORDBREAK;
+ if ( GetStyle() & WB_NOLABEL )
+ nTextStyle &= ~TEXT_DRAW_MNEMONIC;
+
+ if ( GetStyle() & WB_LEFT )
+ nTextStyle |= TEXT_DRAW_LEFT;
+ else if ( GetStyle() & WB_RIGHT )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else
+ nTextStyle |= TEXT_DRAW_CENTER;
+
+ if ( GetStyle() & WB_TOP )
+ nTextStyle |= TEXT_DRAW_TOP;
+ else if ( GetStyle() & WB_BOTTOM )
+ nTextStyle |= TEXT_DRAW_BOTTOM;
+ else
+ nTextStyle |= TEXT_DRAW_VCENTER;
+
+ if ( ! ( (nDrawFlags & WINDOW_DRAW_NODISABLE) || IsEnabled() ) )
+ nTextStyle |= TEXT_DRAW_DISABLE;
+
+ return nTextStyle;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDrawBtnDropDownArrow( OutputDevice* pDev,
+ long nX, long nY,
+ Color& rColor, BOOL bBlack )
+{
+ Color aOldLineColor = pDev->GetLineColor();
+ Color aOldFillColor = pDev->GetFillColor();
+
+ pDev->SetLineColor();
+ if ( bBlack )
+ pDev->SetFillColor( Color( COL_BLACK ) );
+ else
+ pDev->SetFillColor( rColor );
+ pDev->DrawRect( Rectangle( nX+0, nY+0, nX+6, nY+0 ) );
+ pDev->DrawRect( Rectangle( nX+1, nY+1, nX+5, nY+1 ) );
+ pDev->DrawRect( Rectangle( nX+2, nY+2, nX+4, nY+2 ) );
+ pDev->DrawRect( Rectangle( nX+3, nY+3, nX+3, nY+3 ) );
+ if ( bBlack )
+ {
+ pDev->SetFillColor( rColor );
+ pDev->DrawRect( Rectangle( nX+2, nY+1, nX+4, nY+1 ) );
+ pDev->DrawRect( Rectangle( nX+3, nY+2, nX+3, nY+2 ) );
+ }
+ pDev->SetLineColor( aOldLineColor );
+ pDev->SetFillColor( aOldFillColor );
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::ImplDrawPushButtonContent( OutputDevice* pDev, ULONG nDrawFlags,
+ const Rectangle& rRect,
+ bool bLayout )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Rectangle aInRect = rRect;
+ Color aColor;
+ XubString aText = PushButton::GetText(); // PushButton:: wegen MoreButton
+ USHORT nTextStyle = ImplGetTextStyle( nDrawFlags );
+ USHORT nStyle;
+
+ if( aInRect.nRight < aInRect.nLeft || aInRect.nBottom < aInRect.nTop )
+ aInRect.SetEmpty();
+
+ pDev->Push( PUSH_CLIPREGION );
+ pDev->IntersectClipRegion( aInRect );
+
+ if ( nDrawFlags & WINDOW_DRAW_MONO )
+ aColor = Color( COL_BLACK );
+ else if ( IsControlForeground() )
+ aColor = GetControlForeground();
+ else if( nDrawFlags & WINDOW_DRAW_ROLLOVER )
+ aColor = rStyleSettings.GetButtonRolloverTextColor();
+ else
+ aColor = rStyleSettings.GetButtonTextColor();
+
+ pDev->SetTextColor( aColor );
+
+ if ( IsEnabled() || (nDrawFlags & WINDOW_DRAW_NODISABLE) )
+ nStyle = 0;
+ else
+ nStyle = SYMBOL_DRAW_DISABLE;
+
+ Size aSize = rRect.GetSize();
+ Point aPos = rRect.TopLeft();
+
+ ULONG nImageSep = 1 + (pDev->GetTextHeight()-10)/2;
+ if( nImageSep < 1 )
+ nImageSep = 1;
+ if ( mnDDStyle == PUSHBUTTON_DROPDOWN_MENUBUTTON )
+ {
+ if ( aText.Len() && ! (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) )
+ {
+ // calc Symbol- and Textrect
+ long nSymbolSize = pDev->GetTextHeight() / 2 + 1;
+ aInRect.Right() -= 5;
+ aInRect.Left() = aInRect.Right() - nSymbolSize;
+ aSize.Width() -= ( 5 + nSymbolSize );
+
+ ImplDrawAlignedImage( pDev, aPos, aSize, bLayout, nImageSep,
+ nDrawFlags, nTextStyle, NULL, (GetStyle() & WB_FLATBUTTON) != 0 );
+ }
+ else
+ ImplCalcSymbolRect( aInRect );
+
+ if( ! bLayout )
+ {
+ DecorationView aDecoView( pDev );
+ long nDistance = (aInRect.GetHeight() > 10) ? 2 : 1;
+ long nX = aInRect.Left() - 2*nDistance;;
+ Point aStartPt( nX, aInRect.Top()+nDistance );
+ Point aEndPt( nX, aInRect.Bottom()-nDistance );
+ aDecoView.DrawSeparator( aStartPt, aEndPt );
+ aDecoView.DrawSymbol( aInRect, SYMBOL_SPIN_DOWN, aColor, nStyle );
+ aInRect.Left() -= 2*nDistance;
+ ImplSetSymbolRect( aInRect );
+ }
+ }
+ else
+ {
+ Rectangle aSymbolRect;
+ // FIXME: (GetStyle() & WB_FLATBUTTON) != 0 is preliminary
+ // in the next major this should be replaced by "true"
+ ImplDrawAlignedImage( pDev, aPos, aSize, bLayout, nImageSep, nDrawFlags,
+ nTextStyle, IsSymbol() ? &aSymbolRect : NULL, (GetStyle() & WB_FLATBUTTON) != 0 );
+
+ if ( IsSymbol() && ! bLayout )
+ {
+ DecorationView aDecoView( pDev );
+ aDecoView.DrawSymbol( aSymbolRect, meSymbol, aColor, nStyle );
+ ImplSetSymbolRect( aSymbolRect );
+ }
+
+ if ( mnDDStyle == PUSHBUTTON_DROPDOWN_TOOLBOX && !bLayout )
+ {
+ BOOL bBlack = FALSE;
+ Color aArrowColor( COL_BLACK );
+
+ if ( !(nDrawFlags & WINDOW_DRAW_MONO) )
+ {
+ if ( !IsEnabled() )
+ aArrowColor = rStyleSettings.GetShadowColor();
+ else
+ {
+ aArrowColor = Color( COL_LIGHTGREEN );
+ bBlack = TRUE;
+ }
+ }
+
+ ImplDrawBtnDropDownArrow( pDev, aInRect.Right()-6, aInRect.Top()+1,
+ aArrowColor, bBlack );
+ }
+ }
+
+ UserDrawEvent aUDEvt( this, aInRect, 0 );
+ UserDraw( aUDEvt );
+
+ pDev->Pop(); // restore clipregion
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::UserDraw( const UserDrawEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::ImplDrawPushButton( bool bLayout )
+{
+ if( !bLayout )
+ HideFocus();
+
+ USHORT nButtonStyle = ImplGetButtonState();
+ Point aPoint;
+ Size aOutSz( GetOutputSizePixel() );
+ Rectangle aRect( aPoint, aOutSz );
+ Rectangle aInRect = aRect;
+ Rectangle aTextRect;
+ BOOL bNativeOK = FALSE;
+
+ // adjust style if button should be rendered 'pressed'
+ if ( mbPressed )
+ nButtonStyle |= BUTTON_DRAW_PRESSED;
+
+ // TODO: move this to Window class or make it a member !!!
+ ControlType aCtrlType = 0;
+ switch( GetParent()->GetType() )
+ {
+ case WINDOW_LISTBOX:
+ case WINDOW_MULTILISTBOX:
+ case WINDOW_TREELISTBOX:
+ aCtrlType = CTRL_LISTBOX;
+ break;
+
+ case WINDOW_COMBOBOX:
+ case WINDOW_PATTERNBOX:
+ case WINDOW_NUMERICBOX:
+ case WINDOW_METRICBOX:
+ case WINDOW_CURRENCYBOX:
+ case WINDOW_DATEBOX:
+ case WINDOW_TIMEBOX:
+ case WINDOW_LONGCURRENCYBOX:
+ aCtrlType = CTRL_COMBOBOX;
+ break;
+ default:
+ break;
+ }
+
+ BOOL bDropDown = ( IsSymbol() && (GetSymbol()==SYMBOL_SPIN_DOWN) && !GetText().Len() );
+
+ if( bDropDown && (aCtrlType == CTRL_COMBOBOX || aCtrlType == CTRL_LISTBOX ) )
+ {
+ if( GetParent()->IsNativeControlSupported( aCtrlType, PART_ENTIRE_CONTROL) )
+ {
+ // skip painting if the button was already drawn by the theme
+ if( aCtrlType == CTRL_COMBOBOX )
+ {
+ Edit* pEdit = static_cast<Edit*>(GetParent());
+ if( pEdit->ImplUseNativeBorder( pEdit->GetStyle() ) )
+ bNativeOK = TRUE;
+ }
+ else if( GetParent()->IsNativeControlSupported( aCtrlType, HAS_BACKGROUND_TEXTURE) )
+ {
+ bNativeOK = TRUE;
+ }
+ if( !bNativeOK && GetParent()->IsNativeControlSupported( aCtrlType, PART_BUTTON_DOWN ) )
+ {
+ // let the theme draw it, note we then need support
+ // for CTRL_LISTBOX/PART_BUTTON_DOWN and CTRL_COMBOBOX/PART_BUTTON_DOWN
+
+ ImplControlValue aControlValue;
+ ControlState nState = 0;
+
+ if ( mbPressed ) nState |= CTRL_STATE_PRESSED;
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED ) nState |= CTRL_STATE_PRESSED;
+ if ( HasFocus() ) nState |= CTRL_STATE_FOCUSED;
+ if ( ImplGetButtonState() & BUTTON_DRAW_DEFAULT ) nState |= CTRL_STATE_DEFAULT;
+ if ( Window::IsEnabled() ) nState |= CTRL_STATE_ENABLED;
+
+ if ( IsMouseOver() && aInRect.IsInside( GetPointerPosPixel() ) )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ bNativeOK = DrawNativeControl( aCtrlType, PART_BUTTON_DOWN, aInRect, nState,
+ aControlValue, rtl::OUString() );
+ }
+ }
+ }
+
+ if( bNativeOK )
+ return;
+
+ bool bRollOver = (IsMouseOver() && aInRect.IsInside( GetPointerPosPixel() ));
+ if ( (bNativeOK=IsNativeControlSupported(CTRL_PUSHBUTTON, PART_ENTIRE_CONTROL)) == TRUE )
+ {
+ PushButtonValue aControlValue;
+ Rectangle aCtrlRegion( aInRect );
+ ControlState nState = 0;
+
+ if ( mbPressed || IsChecked() ) nState |= CTRL_STATE_PRESSED;
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED ) nState |= CTRL_STATE_PRESSED;
+ if ( HasFocus() ) nState |= CTRL_STATE_FOCUSED;
+ if ( ImplGetButtonState() & BUTTON_DRAW_DEFAULT ) nState |= CTRL_STATE_DEFAULT;
+ if ( Window::IsEnabled() ) nState |= CTRL_STATE_ENABLED;
+
+ if ( bRollOver )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ if( GetStyle() & WB_BEVELBUTTON )
+ aControlValue.mbBevelButton = true;
+
+ // draw frame into invisible window to have aInRect modified correctly
+ // but do not shift the inner rect for pressed buttons (ie remove BUTTON_DRAW_PRESSED)
+ // this assumes the theme has enough visual cues to signalize the button was pressed
+ //Window aWin( this );
+ //ImplDrawPushButtonFrame( &aWin, aInRect, nButtonStyle & ~BUTTON_DRAW_PRESSED );
+
+ // looks better this way as symbols were displaced slightly using the above approach
+ aInRect.Top()+=4;
+ aInRect.Bottom()-=4;
+ aInRect.Left()+=4;
+ aInRect.Right()-=4;
+
+ // prepare single line hint (needed on mac to decide between normal push button and
+ // rectangular bevel button look)
+ Size aFontSize( Application::GetSettings().GetStyleSettings().GetPushButtonFont().GetSize() );
+ aFontSize = LogicToPixel( aFontSize, MapMode( MAP_POINT ) );
+ Size aInRectSize( LogicToPixel( Size( aInRect.GetWidth(), aInRect.GetHeight() ) ) );
+ aControlValue.mbSingleLine = (aInRectSize.Height() < 2 * aFontSize.Height() );
+
+ if( ((nState & CTRL_STATE_ROLLOVER)) || ! (GetStyle() & WB_FLATBUTTON) )
+ {
+ bNativeOK = DrawNativeControl( CTRL_PUSHBUTTON, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ aControlValue, rtl::OUString()/*PushButton::GetText()*/ );
+ }
+ else
+ {
+ bNativeOK = true;
+ }
+
+ // draw content using the same aInRect as non-native VCL would do
+ ImplDrawPushButtonContent( this,
+ (nState&CTRL_STATE_ROLLOVER) ? WINDOW_DRAW_ROLLOVER : 0,
+ aInRect, bLayout );
+
+ if ( HasFocus() )
+ ShowFocus( ImplGetFocusRect() );
+ }
+
+ if ( bNativeOK == FALSE )
+ {
+ // draw PushButtonFrame, aInRect has content size afterwards
+ if( (GetStyle() & WB_FLATBUTTON) )
+ {
+ Rectangle aTempRect( aInRect );
+ if( ! bLayout && bRollOver )
+ ImplDrawPushButtonFrame( this, aTempRect, nButtonStyle );
+ aInRect.Left() += 2;
+ aInRect.Top() += 2;
+ aInRect.Right() -= 2;
+ aInRect.Bottom() -= 2;
+ }
+ else
+ {
+ if( ! bLayout )
+ ImplDrawPushButtonFrame( this, aInRect, nButtonStyle );
+ }
+
+ // draw content
+ ImplDrawPushButtonContent( this, 0, aInRect, bLayout );
+
+ if( ! bLayout && HasFocus() )
+ {
+ ShowFocus( ImplGetFocusRect() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::ImplSetDefButton( BOOL bSet )
+{
+ Size aSize( GetSizePixel() );
+ Point aPos( GetPosPixel() );
+ int dLeft(0), dRight(0), dTop(0), dBottom(0);
+ BOOL bSetPos = FALSE;
+
+ if ( (IsNativeControlSupported(CTRL_PUSHBUTTON, PART_ENTIRE_CONTROL)) == TRUE )
+ {
+ Rectangle aBound, aCont;
+ Rectangle aCtrlRect( 0, 0, 80, 20 ); // use a constant size to avoid accumulating
+ // will not work if the theme has dynamic adornment sizes
+ ImplControlValue aControlValue;
+ Rectangle aCtrlRegion( aCtrlRect );
+ ControlState nState = CTRL_STATE_DEFAULT|CTRL_STATE_ENABLED;
+
+ // get native size of a 'default' button
+ // and adjust the VCL button if more space for adornment is required
+ if( GetNativeControlRegion( CTRL_PUSHBUTTON, PART_ENTIRE_CONTROL, aCtrlRegion,
+ nState, aControlValue, rtl::OUString(),
+ aBound, aCont ) )
+ {
+ dLeft = aCont.Left() - aBound.Left();
+ dTop = aCont.Top() - aBound.Top();
+ dRight = aBound.Right() - aCont.Right();
+ dBottom = aBound.Bottom() - aCont.Bottom();
+ bSetPos = dLeft || dTop || dRight || dBottom;
+ }
+ }
+
+ if ( bSet )
+ {
+ if( !(ImplGetButtonState() & BUTTON_DRAW_DEFAULT) && bSetPos )
+ {
+ // adjust pos/size when toggling from non-default to default
+ aPos.Move(-dLeft, -dTop);
+ aSize.Width() += dLeft + dRight;
+ aSize.Height() += dTop + dBottom;
+ }
+ ImplGetButtonState() |= BUTTON_DRAW_DEFAULT;
+ }
+ else
+ {
+ if( (ImplGetButtonState() & BUTTON_DRAW_DEFAULT) && bSetPos )
+ {
+ // adjust pos/size when toggling from default to non-default
+ aPos.Move(dLeft, dTop);
+ aSize.Width() -= dLeft + dRight;
+ aSize.Height() -= dTop + dBottom;
+ }
+ ImplGetButtonState() &= ~BUTTON_DRAW_DEFAULT;
+ }
+ if( bSetPos )
+ SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height(), WINDOW_POSSIZE_ALL );
+
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PushButton::ImplIsDefButton() const
+{
+ return (ImplGetButtonState() & BUTTON_DRAW_DEFAULT) != 0;
+}
+
+// -----------------------------------------------------------------------
+
+PushButton::PushButton( WindowType nType ) :
+ Button( nType )
+{
+ ImplInitPushButtonData();
+}
+
+// -----------------------------------------------------------------------
+
+PushButton::PushButton( Window* pParent, WinBits nStyle ) :
+ Button( WINDOW_PUSHBUTTON )
+{
+ ImplInitPushButtonData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+PushButton::PushButton( Window* pParent, const ResId& rResId ) :
+ Button( WINDOW_PUSHBUTTON )
+{
+ ImplInitPushButtonData();
+ rResId.SetRT( RSC_PUSHBUTTON );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+PushButton::~PushButton()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() &&
+ ImplHitTestPushButton( this, rMEvt.GetPosPixel() ) )
+ {
+ USHORT nTrackFlags = 0;
+
+ if ( ( GetStyle() & WB_REPEAT ) &&
+ ! ( GetStyle() & WB_TOGGLE ) )
+ nTrackFlags |= STARTTRACK_BUTTONREPEAT;
+
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplDrawPushButton();
+ StartTracking( nTrackFlags );
+
+ if ( nTrackFlags & STARTTRACK_BUTTONREPEAT )
+ Click();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::Tracking( const TrackingEvent& rTEvt )
+{
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
+ GrabFocus();
+
+ if ( GetStyle() & WB_TOGGLE )
+ {
+ // Don't toggle, when aborted
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ if ( IsChecked() )
+ {
+ Check( FALSE );
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ }
+ else
+ Check( TRUE );
+ }
+ }
+ else
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+
+ ImplDrawPushButton();
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ if ( ! ( ( GetStyle() & WB_REPEAT ) &&
+ ! ( GetStyle() & WB_TOGGLE ) ) )
+ Click();
+ }
+ }
+ }
+ else
+ {
+ if ( ImplHitTestPushButton( this, rTEvt.GetMouseEvent().GetPosPixel() ) )
+ {
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ if ( rTEvt.IsTrackingRepeat() && (GetStyle() & WB_REPEAT) &&
+ ! ( GetStyle() & WB_TOGGLE ) )
+ Click();
+ }
+ else
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplDrawPushButton();
+ }
+ }
+ else
+ {
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplDrawPushButton();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if ( !aKeyCode.GetModifier() &&
+ ((aKeyCode.GetCode() == KEY_RETURN) || (aKeyCode.GetCode() == KEY_SPACE)) )
+ {
+ if ( !(ImplGetButtonState() & BUTTON_DRAW_PRESSED) )
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplDrawPushButton();
+ }
+
+ if ( ( GetStyle() & WB_REPEAT ) &&
+ ! ( GetStyle() & WB_TOGGLE ) )
+ Click();
+ }
+ else if ( (ImplGetButtonState() & BUTTON_DRAW_PRESSED) && (aKeyCode.GetCode() == KEY_ESCAPE) )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplDrawPushButton();
+ }
+ else
+ Button::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::KeyUp( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if ( (ImplGetButtonState() & BUTTON_DRAW_PRESSED) &&
+ ((aKeyCode.GetCode() == KEY_RETURN) || (aKeyCode.GetCode() == KEY_SPACE)) )
+ {
+ if ( GetStyle() & WB_TOGGLE )
+ {
+ if ( IsChecked() )
+ {
+ Check( FALSE );
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ }
+ else
+ Check( TRUE );
+
+ Toggle();
+ }
+ else
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+
+ ImplDrawPushButton();
+
+ if ( !( ( GetStyle() & WB_REPEAT ) &&
+ ! ( GetStyle() & WB_TOGGLE ) ) )
+ Click();
+ }
+ else
+ Button::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<PushButton*>(this)->ImplDrawPushButton( true );
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::Paint( const Rectangle& )
+{
+ ImplDrawPushButton();
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Rectangle aRect( aPos, aSize );
+ Rectangle aTextRect;
+ Font aFont = GetDrawPixelFont( pDev );
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ if ( nFlags & WINDOW_DRAW_MONO )
+ {
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ }
+ else
+ {
+ pDev->SetTextColor( GetTextColor() );
+
+ // DecoView uses the FaceColor...
+ AllSettings aSettings = pDev->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ if ( IsControlBackground() )
+ aStyleSettings.SetFaceColor( GetControlBackground() );
+ else
+ aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
+ aSettings.SetStyleSettings( aStyleSettings );
+ pDev->SetSettings( aSettings );
+ }
+ pDev->SetTextFillColor();
+
+ DecorationView aDecoView( pDev );
+ USHORT nButtonStyle = 0;
+ if ( nFlags & WINDOW_DRAW_MONO )
+ nButtonStyle |= BUTTON_DRAW_MONO;
+ if ( IsChecked() )
+ nButtonStyle |= BUTTON_DRAW_CHECKED;
+ aRect = aDecoView.DrawButton( aRect, nButtonStyle );
+
+ ImplDrawPushButtonContent( pDev, nFlags, aRect, false );
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::GetFocus()
+{
+ ShowFocus( ImplGetFocusRect() );
+ SetInputContext( InputContext( GetFont() ) );
+ Button::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::LoseFocus()
+{
+ EndSelection();
+ HideFocus();
+ Button::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::StateChanged( StateChangedType nType )
+{
+ Button::StateChanged( nType );
+
+ if ( (nType == STATE_CHANGE_ENABLE) ||
+ (nType == STATE_CHANGE_TEXT) ||
+ (nType == STATE_CHANGE_IMAGE) ||
+ (nType == STATE_CHANGE_DATA) ||
+ (nType == STATE_CHANGE_STATE) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetWindow( WINDOW_PREV ), GetStyle() ) );
+
+ bool bIsDefButton = ( GetStyle() & WB_DEFBUTTON ) != 0;
+ bool bWasDefButton = ( GetPrevStyle() & WB_DEFBUTTON ) != 0;
+ if ( bIsDefButton != bWasDefButton )
+ ImplSetDefButton( bIsDefButton );
+
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ if ( (GetPrevStyle() & PUSHBUTTON_VIEW_STYLE) !=
+ (GetStyle() & PUSHBUTTON_VIEW_STYLE) )
+ Invalidate();
+ }
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Button::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long PushButton::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
+ {
+ // trigger redraw as mouse over state has changed
+
+ // TODO: move this to Window class or make it a member !!!
+ ControlType aCtrlType = 0;
+ switch( GetParent()->GetType() )
+ {
+ case WINDOW_LISTBOX:
+ case WINDOW_MULTILISTBOX:
+ case WINDOW_TREELISTBOX:
+ aCtrlType = CTRL_LISTBOX;
+ break;
+
+ case WINDOW_COMBOBOX:
+ case WINDOW_PATTERNBOX:
+ case WINDOW_NUMERICBOX:
+ case WINDOW_METRICBOX:
+ case WINDOW_CURRENCYBOX:
+ case WINDOW_DATEBOX:
+ case WINDOW_TIMEBOX:
+ case WINDOW_LONGCURRENCYBOX:
+ aCtrlType = CTRL_COMBOBOX;
+ break;
+ default:
+ break;
+ }
+
+ BOOL bDropDown = ( IsSymbol() && (GetSymbol()==SYMBOL_SPIN_DOWN) && !GetText().Len() );
+
+ if( bDropDown && GetParent()->IsNativeControlSupported( aCtrlType, PART_ENTIRE_CONTROL) &&
+ !GetParent()->IsNativeControlSupported( aCtrlType, PART_BUTTON_DOWN) )
+ {
+ Window *pBorder = GetParent()->GetWindow( WINDOW_BORDER );
+ if(aCtrlType == CTRL_COMBOBOX)
+ {
+ // only paint the button part to avoid flickering of the combobox text
+ Point aPt;
+ Rectangle aClipRect( aPt, GetOutputSizePixel() );
+ aClipRect.SetPos(pBorder->ScreenToOutputPixel(OutputToScreenPixel(aClipRect.TopLeft())));
+ pBorder->Invalidate( aClipRect );
+ }
+ else
+ {
+ pBorder->Invalidate( INVALIDATE_NOERASE );
+ pBorder->Update();
+ }
+ }
+ else if( (GetStyle() & WB_FLATBUTTON) ||
+ IsNativeControlSupported(CTRL_PUSHBUTTON, PART_ENTIRE_CONTROL) )
+ {
+ Invalidate();
+ }
+ }
+ }
+
+ return nDone ? nDone : Button::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::Toggle()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_PUSHBUTTON_TOGGLE, maToggleHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::SetSymbol( SymbolType eSymbol )
+{
+ if ( meSymbol != eSymbol )
+ {
+ meSymbol = eSymbol;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+void PushButton::SetSymbolAlign( SymbolAlign eAlign )
+{
+ ImplSetSymbolAlign( eAlign );
+}
+
+// -----------------------------------------------------------------------
+SymbolAlign PushButton::GetSymbolAlign() const
+{
+ return ImplGetSymbolAlign();
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::SetDropDown( USHORT nStyle )
+{
+ if ( mnDDStyle != nStyle )
+ {
+ mnDDStyle = nStyle;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::SetState( TriState eState )
+{
+ if ( meState != eState )
+ {
+ meState = eState;
+ if ( meState == STATE_NOCHECK )
+ ImplGetButtonState() &= ~(BUTTON_DRAW_CHECKED | BUTTON_DRAW_DONTKNOW);
+ else if ( meState == STATE_CHECK )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_DONTKNOW;
+ ImplGetButtonState() |= BUTTON_DRAW_CHECKED;
+ }
+ else // STATE_DONTKNOW
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_CHECKED;
+ ImplGetButtonState() |= BUTTON_DRAW_DONTKNOW;
+ }
+
+ StateChanged( STATE_CHANGE_STATE );
+ Toggle();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::SetPressed( BOOL bPressed )
+{
+ if ( mbPressed != bPressed )
+ {
+ mbPressed = bPressed;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PushButton::EndSelection()
+{
+ EndTracking( ENDTRACK_CANCEL );
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ if ( !mbPressed )
+ ImplDrawPushButton();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size PushButton::CalcMinimumSize( long nMaxWidth ) const
+{
+ Size aSize;
+
+ if ( IsSymbol() )
+ {
+ if ( IsSmallSymbol ())
+ aSize = Size( 16, 12 );
+ else
+ aSize = Size( 26, 24 );
+ if( mnDDStyle == PUSHBUTTON_DROPDOWN_MENUBUTTON )
+ aSize.Width() += 4;
+ }
+ else if ( IsImage() && ! (ImplGetButtonState() & BUTTON_DRAW_NOIMAGE) )
+ aSize = GetModeImage().GetSizePixel();
+ if ( PushButton::GetText().Len() && ! (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) )
+ {
+ ULONG nDrawFlags = 0;
+ Size textSize = GetTextRect( Rectangle( Point(), Size( nMaxWidth ? nMaxWidth : 0x7fffffff, 0x7fffffff ) ),
+ PushButton::GetText(), ImplGetTextStyle( nDrawFlags ) ).GetSize();
+ aSize.Width() += int( textSize.Width () * 1.15 );
+ aSize.Height() = std::max( aSize.Height(), long( textSize.Height() * 1.15 ) );
+ }
+
+ // cf. ImplDrawPushButton ...
+ if( (GetStyle() & WB_SMALLSTYLE) == 0 )
+ {
+ aSize.Width() += 8;
+ aSize.Height() += 8;
+ }
+
+ return CalcWindowSize( aSize );
+}
+
+Size PushButton::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM: {
+ return CalcMinimumSize();
+ }
+ default:
+ return Button::GetOptimalSize( eType );
+ }
+}
+
+// =======================================================================
+
+void OKButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ PushButton::ImplInit( pParent, nStyle );
+
+ SetText( Button::GetStandardText( BUTTON_OK ) );
+ SetHelpText( Button::GetStandardHelpText( BUTTON_OK ) );
+}
+
+// -----------------------------------------------------------------------
+
+OKButton::OKButton( Window* pParent, WinBits nStyle ) :
+ PushButton( WINDOW_OKBUTTON )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+OKButton::OKButton( Window* pParent, const ResId& rResId ) :
+ PushButton( WINDOW_OKBUTTON )
+{
+ rResId.SetRT( RSC_OKBUTTON );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void OKButton::Click()
+{
+ // Ist kein Link gesetzt, dann schliesse Parent
+ if ( !GetClickHdl() )
+ {
+ Window* pParent = GetParent();
+ if ( pParent->IsSystemWindow() )
+ {
+ if ( pParent->IsDialog() )
+ {
+ if ( ((Dialog*)pParent)->IsInExecute() )
+ ((Dialog*)pParent)->EndDialog( TRUE );
+ // gegen rekursive Aufrufe schuetzen
+ else if ( !((Dialog*)pParent)->IsInClose() )
+ {
+ if ( pParent->GetStyle() & WB_CLOSEABLE )
+ ((Dialog*)pParent)->Close();
+ }
+ }
+ else
+ {
+ if ( pParent->GetStyle() & WB_CLOSEABLE )
+ ((SystemWindow*)pParent)->Close();
+ }
+ }
+ }
+ else
+ {
+ PushButton::Click();
+ }
+}
+
+// =======================================================================
+
+void CancelButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ PushButton::ImplInit( pParent, nStyle );
+
+ SetText( Button::GetStandardText( BUTTON_CANCEL ) );
+ SetHelpText( Button::GetStandardHelpText( BUTTON_CANCEL ) );
+}
+
+// -----------------------------------------------------------------------
+
+CancelButton::CancelButton( Window* pParent, WinBits nStyle ) :
+ PushButton( WINDOW_CANCELBUTTON )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+CancelButton::CancelButton( Window* pParent, const ResId& rResId ) :
+ PushButton( WINDOW_CANCELBUTTON )
+{
+ rResId.SetRT( RSC_CANCELBUTTON );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void CancelButton::Click()
+{
+ // Ist kein Link gesetzt, dann schliesse Parent
+ if ( !GetClickHdl() )
+ {
+ Window* pParent = GetParent();
+ if ( pParent->IsSystemWindow() )
+ {
+ if ( pParent->IsDialog() )
+ {
+ if ( ((Dialog*)pParent)->IsInExecute() )
+ ((Dialog*)pParent)->EndDialog( FALSE );
+ // gegen rekursive Aufrufe schuetzen
+ else if ( !((Dialog*)pParent)->IsInClose() )
+ {
+ if ( pParent->GetStyle() & WB_CLOSEABLE )
+ ((Dialog*)pParent)->Close();
+ }
+ }
+ else
+ {
+ if ( pParent->GetStyle() & WB_CLOSEABLE )
+ ((SystemWindow*)pParent)->Close();
+ }
+ }
+ }
+ else
+ {
+ PushButton::Click();
+ }
+}
+
+// =======================================================================
+
+void HelpButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ PushButton::ImplInit( pParent, nStyle | WB_NOPOINTERFOCUS );
+
+ SetText( Button::GetStandardText( BUTTON_HELP ) );
+ SetHelpText( Button::GetStandardHelpText( BUTTON_HELP ) );
+}
+
+// -----------------------------------------------------------------------
+
+HelpButton::HelpButton( Window* pParent, WinBits nStyle ) :
+ PushButton( WINDOW_HELPBUTTON )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+HelpButton::HelpButton( Window* pParent, const ResId& rResId ) :
+ PushButton( WINDOW_HELPBUTTON )
+{
+ rResId.SetRT( RSC_HELPBUTTON );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void HelpButton::Click()
+{
+ // Ist kein Link gesetzt, loese Hilfe aus
+ if ( !GetClickHdl() )
+ {
+ Window* pFocusWin = Application::GetFocusWindow();
+ if ( !pFocusWin )
+ pFocusWin = this;
+
+ HelpEvent aEvt( pFocusWin->GetPointerPosPixel(), HELPMODE_CONTEXT );
+ pFocusWin->RequestHelp( aEvt );
+ }
+ PushButton::Click();
+}
+
+// =======================================================================
+
+void RadioButton::ImplInitRadioButtonData()
+{
+ mbChecked = FALSE;
+ mbSaveValue = FALSE;
+ mbRadioCheck = TRUE;
+ mbStateChanged = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( pParent->GetWindow( WINDOW_LASTCHILD ), nStyle );
+ Button::ImplInit( pParent, nStyle, NULL );
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits RadioButton::ImplInitStyle( const Window* pPrevWindow, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOGROUP) &&
+ (!pPrevWindow || (pPrevWindow->GetType() != WINDOW_RADIOBUTTON)) )
+ nStyle |= WB_GROUP;
+ if ( !(nStyle & WB_NOTABSTOP) )
+ {
+ if ( IsChecked() )
+ nStyle |= WB_TABSTOP;
+ else
+ nStyle &= ~WB_TABSTOP;
+ }
+ return nStyle;
+}
+
+// -----------------------------------------------------------------
+
+const Font& RadioButton::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetRadioCheckFont();
+}
+
+// -----------------------------------------------------------------
+const Color& RadioButton::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetRadioCheckTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Button::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ Window* pParent = GetParent();
+ if ( !IsControlBackground() &&
+ (pParent->IsChildTransparentModeEnabled() || IsNativeControlSupported( CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL ) ) )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ if( IsNativeControlSupported( CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL ) )
+ mpWindowImpl->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+ }
+}
+
+//---------------------------------------------------------------------
+//--- 12.03.2003 18:46:14 ---------------------------------------------
+
+void RadioButton::DrawRadioButtonState( )
+{
+ ImplDrawRadioButtonState( );
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplInvalidateOrDrawRadioButtonState()
+{
+ if( ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase )
+ {
+ if ( IsNativeControlSupported(CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL) )
+ {
+ Invalidate();
+ Update();
+ return;
+ }
+ }
+ ImplDrawRadioButtonState();
+}
+
+void RadioButton::ImplDrawRadioButtonState()
+{
+ USHORT nButtonStyle = 0;
+ BOOL bNativeOK = FALSE;
+
+ // no native drawing for image radio buttons
+ if ( !maImage && (bNativeOK=IsNativeControlSupported(CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL)) == TRUE )
+ {
+ ImplControlValue aControlValue( mbChecked ? BUTTONVALUE_ON : BUTTONVALUE_OFF );
+ Rectangle aCtrlRect( maStateRect.TopLeft(), maStateRect.GetSize() );
+ ControlState nState = 0;
+
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED ) nState |= CTRL_STATE_PRESSED;
+ if ( HasFocus() ) nState |= CTRL_STATE_FOCUSED;
+ if ( ImplGetButtonState() & BUTTON_DRAW_DEFAULT ) nState |= CTRL_STATE_DEFAULT;
+ if ( IsEnabled() ) nState |= CTRL_STATE_ENABLED;
+
+ if ( IsMouseOver() && maMouseRect.IsInside( GetPointerPosPixel() ) )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ bNativeOK = DrawNativeControl( CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL, aCtrlRect, nState,
+ aControlValue,rtl::OUString() );
+
+ }
+
+if ( bNativeOK == FALSE )
+{
+ // kein Image-RadioButton
+ if ( !maImage )
+ {
+ USHORT nStyle = ImplGetButtonState();
+ if ( !IsEnabled() )
+ nStyle |= BUTTON_DRAW_DISABLED;
+ if ( mbChecked )
+ nStyle |= BUTTON_DRAW_CHECKED;
+ Image aImage = GetRadioImage( GetSettings(), nStyle );
+ if ( IsZoom() )
+ DrawImage( maStateRect.TopLeft(), maStateRect.GetSize(), aImage );
+ else
+ DrawImage( maStateRect.TopLeft(), aImage );
+ }
+ else
+ {
+ HideFocus();
+
+ DecorationView aDecoView( this );
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Rectangle aImageRect = maStateRect;
+ Size aImageSize = maImage.GetSizePixel();
+ BOOL bEnabled = IsEnabled();
+
+ aImageSize.Width() = CalcZoom( aImageSize.Width() );
+ aImageSize.Height() = CalcZoom( aImageSize.Height() );
+
+ // Border und Selektionsstatus ausgeben
+ nButtonStyle = FRAME_DRAW_DOUBLEIN;
+ aImageRect = aDecoView.DrawFrame( aImageRect, nButtonStyle );
+ if ( (ImplGetButtonState() & BUTTON_DRAW_PRESSED) || !bEnabled )
+ SetFillColor( rStyleSettings.GetFaceColor() );
+ else
+ SetFillColor( rStyleSettings.GetFieldColor() );
+ SetLineColor();
+ DrawRect( aImageRect );
+
+ // Image ausgeben
+ nButtonStyle = 0;
+ if ( !bEnabled )
+ nButtonStyle |= IMAGE_DRAW_DISABLE;
+
+ // check for HC mode
+ Image *pImage = &maImage;
+ if( !!maImageHC )
+ {
+ if( rStyleSettings.GetHighContrastMode() )
+ pImage = &maImageHC;
+ }
+
+ Point aImagePos( aImageRect.TopLeft() );
+ aImagePos.X() += (aImageRect.GetWidth()-aImageSize.Width())/2;
+ aImagePos.Y() += (aImageRect.GetHeight()-aImageSize.Height())/2;
+ if ( IsZoom() )
+ DrawImage( aImagePos, aImageSize, *pImage, nButtonStyle );
+ else
+ DrawImage( aImagePos, *pImage, nButtonStyle );
+
+ aImageRect.Left()++;
+ aImageRect.Top()++;
+ aImageRect.Right()--;
+ aImageRect.Bottom()--;
+
+ ImplSetFocusRect( aImageRect );
+
+ if ( mbChecked )
+ {
+ SetLineColor( rStyleSettings.GetHighlightColor() );
+ SetFillColor();
+ if ( (aImageSize.Width() >= 20) || (aImageSize.Height() >= 20) )
+ {
+ aImageRect.Left()++;
+ aImageRect.Top()++;
+ aImageRect.Right()--;
+ aImageRect.Bottom()--;
+ }
+ DrawRect( aImageRect );
+ aImageRect.Left()++;
+ aImageRect.Top()++;
+ aImageRect.Right()--;
+ aImageRect.Bottom()--;
+ DrawRect( aImageRect );
+ }
+
+ if ( HasFocus() )
+ ShowFocus( ImplGetFocusRect() );
+ }
+}
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize,
+ const Size& rImageSize, Rectangle& rStateRect,
+ Rectangle& rMouseRect, bool bLayout )
+{
+ WinBits nWinStyle = GetStyle();
+ XubString aText( GetText() );
+ Rectangle aRect( rPos, rSize );
+ MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+
+ pDev->Push( PUSH_CLIPREGION );
+ pDev->IntersectClipRegion( Rectangle( rPos, rSize ) );
+
+ // kein Image-RadioButton
+ if ( !maImage )
+ {
+ if ( ( aText.Len() && ! (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) ) ||
+ ( HasImage() && ! (ImplGetButtonState() & BUTTON_DRAW_NOIMAGE) ) )
+ {
+ USHORT nTextStyle = Button::ImplGetTextStyle( aText, nWinStyle, nDrawFlags );
+
+ const long nImageSep = GetDrawPixel( pDev, ImplGetImageToTextDistance() );
+ Size aSize( rSize );
+ Point aPos( rPos );
+ aPos.X() += rImageSize.Width() + nImageSep;
+ aSize.Width() -= rImageSize.Width() + nImageSep;
+
+ // if the text rect height is smaller than the height of the image
+ // then for single lines the default should be centered text
+ if( (nWinStyle & (WB_TOP|WB_VCENTER|WB_BOTTOM)) == 0 &&
+ (rImageSize.Height() > rSize.Height() || ! (nWinStyle & WB_WORDBREAK) ) )
+ {
+ nTextStyle &= ~(TEXT_DRAW_TOP|TEXT_DRAW_BOTTOM);
+ nTextStyle |= TEXT_DRAW_VCENTER;
+ aSize.Height() = rImageSize.Height();
+ }
+
+ ImplDrawAlignedImage( pDev, aPos, aSize, bLayout, 1,
+ nDrawFlags, nTextStyle, NULL );
+
+ rMouseRect = Rectangle( aPos, aSize );
+ rMouseRect.Left() = rPos.X();
+
+ rStateRect.Left() = rPos.X();
+ rStateRect.Top() = rMouseRect.Top();
+
+ if ( aSize.Height() > rImageSize.Height() )
+ rStateRect.Top() += ( aSize.Height() - rImageSize.Height() ) / 2;
+ else
+ {
+ rStateRect.Top() -= ( rImageSize.Height() - aSize.Height() ) / 2;
+ if( rStateRect.Top() < 0 )
+ rStateRect.Top() = 0;
+ }
+
+ rStateRect.Right() = rStateRect.Left() + rImageSize.Width()-1;
+ rStateRect.Bottom() = rStateRect.Top() + rImageSize.Height()-1;
+
+ if ( rStateRect.Bottom() > rMouseRect.Bottom() )
+ rMouseRect.Bottom() = rStateRect.Bottom();
+ }
+ else
+ {
+ if ( nWinStyle & WB_CENTER )
+ rStateRect.Left() = rPos.X()+((rSize.Width()-rImageSize.Width())/2);
+ else if ( nWinStyle & WB_RIGHT )
+ rStateRect.Left() = rPos.X()+rSize.Width()-rImageSize.Width(); //-1;
+ else
+ rStateRect.Left() = rPos.X(); //+1;
+ if ( nWinStyle & WB_VCENTER )
+ rStateRect.Top() = rPos.Y()+((rSize.Height()-rImageSize.Height())/2);
+ else if ( nWinStyle & WB_BOTTOM )
+ rStateRect.Top() = rPos.Y()+rSize.Height()-rImageSize.Height(); //-1;
+ else
+ rStateRect.Top() = rPos.Y(); //+1;
+ rStateRect.Right() = rStateRect.Left()+rImageSize.Width()-1;
+ rStateRect.Bottom() = rStateRect.Top()+rImageSize.Height()-1;
+ rMouseRect = rStateRect;
+
+ ImplSetFocusRect( rStateRect );
+
+/* und oben -1, da CalcSize() auch Focus-Rechteck nicht mit einrechnet,
+da im Writer ansonsten die Images noch weiter oben haengen
+ rFocusRect = rStateRect;
+ rFocusRect.Left()--;
+ rFocusRect.Top()--;
+ rFocusRect.Right()++;
+ rFocusRect.Bottom()++;
+*/
+ }
+ }
+ else
+ {
+ BOOL bTopImage = (nWinStyle & WB_TOP) != 0;
+ Size aImageSize = maImage.GetSizePixel();
+ Rectangle aImageRect( rPos, rSize );
+ long nTextHeight = pDev->GetTextHeight();
+ long nTextWidth = pDev->GetCtrlTextWidth( aText );
+
+ // Positionen und Groessen berechnen
+ if ( aText.Len() && ! (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) )
+ {
+ Size aTmpSize( (aImageSize.Width()+8), (aImageSize.Height()+8) );
+ if ( bTopImage )
+ {
+ aImageRect.Left() = (rSize.Width()-aTmpSize.Width())/2;
+ aImageRect.Top() = (rSize.Height()-(aTmpSize.Height()+nTextHeight+6))/2;
+ }
+ else
+ aImageRect.Top() = (rSize.Height()-aTmpSize.Height())/2;
+
+ aImageRect.Right() = aImageRect.Left()+aTmpSize.Width();
+ aImageRect.Bottom() = aImageRect.Top()+aTmpSize.Height();
+
+ // Text ausgeben
+ Point aTxtPos = rPos;
+ if ( bTopImage )
+ {
+ aTxtPos.X() += (rSize.Width()-nTextWidth)/2;
+ aTxtPos.Y() += aImageRect.Bottom()+6;
+ }
+ else
+ {
+ aTxtPos.X() += aImageRect.Right()+8;
+ aTxtPos.Y() += (rSize.Height()-nTextHeight)/2;
+ }
+ pDev->DrawCtrlText( aTxtPos, aText, 0, STRING_LEN, TEXT_DRAW_MNEMONIC, pVector, pDisplayText );
+ }
+
+ rMouseRect = aImageRect;
+ rStateRect = aImageRect;
+ }
+
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplDrawRadioButton( bool bLayout )
+{
+ if( !bLayout )
+ HideFocus();
+
+ Size aImageSize;
+ if ( !maImage )
+ aImageSize = ImplGetRadioImageSize();
+ else
+ aImageSize = maImage.GetSizePixel();
+ aImageSize.Width() = CalcZoom( aImageSize.Width() );
+ aImageSize.Height() = CalcZoom( aImageSize.Height() );
+
+ // Draw control text
+ ImplDraw( this, 0, Point(), GetOutputSizePixel(),
+ aImageSize, maStateRect, maMouseRect, bLayout );
+
+ if( !bLayout || (IsNativeControlSupported(CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL)==TRUE) )
+ {
+ if ( !maImage && HasFocus() )
+ ShowFocus( ImplGetFocusRect() );
+
+ ImplDrawRadioButtonState();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::GetRadioButtonGroup( std::vector< RadioButton* >& io_rGroup, bool bIncludeThis ) const
+{
+ // empty the list
+ io_rGroup.clear();
+
+ // go back to first in group;
+ Window* pFirst = const_cast<RadioButton*>(this);
+ while( ( pFirst->GetStyle() & WB_GROUP ) == 0 )
+ {
+ Window* pWindow = pFirst->GetWindow( WINDOW_PREV );
+ if( pWindow )
+ pFirst = pWindow;
+ else
+ break;
+ }
+ // insert radiobuttons up to next group
+ do
+ {
+ if( pFirst->GetType() == WINDOW_RADIOBUTTON )
+ {
+ if( pFirst != this || bIncludeThis )
+ io_rGroup.push_back( static_cast<RadioButton*>(pFirst) );
+ }
+ pFirst = pFirst->GetWindow( WINDOW_NEXT );
+ } while( pFirst && ( ( pFirst->GetStyle() & WB_GROUP ) == 0 ) );
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplUncheckAllOther()
+{
+ mpWindowImpl->mnStyle |= WB_TABSTOP;
+
+ // Gruppe mit RadioButtons durchgehen und die gecheckten Buttons
+ Window* pWindow;
+ WinBits nStyle;
+ if ( !(GetStyle() & WB_GROUP) )
+ {
+ pWindow = GetWindow( WINDOW_PREV );
+ while ( pWindow )
+ {
+ nStyle = pWindow->GetStyle();
+
+ if ( pWindow->GetType() == WINDOW_RADIOBUTTON )
+ {
+ if ( ((RadioButton*)pWindow)->IsChecked() )
+ {
+ ImplDelData aDelData;
+ pWindow->ImplAddDel( &aDelData );
+ ((RadioButton*)pWindow)->SetState( FALSE );
+ if ( aDelData.IsDelete() )
+ return;
+ pWindow->ImplRemoveDel( &aDelData );
+ }
+ // Um falsch gesetzt WB_TABSTOPS immer zu entfernen, nicht
+ // innerhalb der if-Abfrage
+ pWindow->mpWindowImpl->mnStyle &= ~WB_TABSTOP;
+ }
+
+ if ( nStyle & WB_GROUP )
+ break;
+
+ pWindow = pWindow->GetWindow( WINDOW_PREV );
+ }
+ }
+
+ pWindow = GetWindow( WINDOW_NEXT );
+ while ( pWindow )
+ {
+ nStyle = pWindow->GetStyle();
+
+ if ( nStyle & WB_GROUP )
+ break;
+
+ if ( pWindow->GetType() == WINDOW_RADIOBUTTON )
+ {
+ if ( ((RadioButton*)pWindow)->IsChecked() )
+ {
+ ImplDelData aDelData;
+ pWindow->ImplAddDel( &aDelData );
+ ((RadioButton*)pWindow)->SetState( FALSE );
+ if ( aDelData.IsDelete() )
+ return;
+ pWindow->ImplRemoveDel( &aDelData );
+ }
+ // Um falsch gesetzt WB_TABSTOPS immer zu entfernen, nicht
+ // innerhalb der if-Abfrage
+ pWindow->mpWindowImpl->mnStyle &= ~WB_TABSTOP;
+ }
+
+ pWindow = pWindow->GetWindow( WINDOW_NEXT );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplCallClick( BOOL bGrabFocus, USHORT nFocusFlags )
+{
+ mbStateChanged = !mbChecked;
+ mbChecked = TRUE;
+ mpWindowImpl->mnStyle |= WB_TABSTOP;
+ ImplInvalidateOrDrawRadioButtonState();
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ if ( mbRadioCheck )
+ ImplUncheckAllOther();
+ if ( aDelData.IsDelete() )
+ return;
+ if ( bGrabFocus )
+ ImplGrabFocus( nFocusFlags );
+ if ( aDelData.IsDelete() )
+ return;
+ if ( mbStateChanged )
+ Toggle();
+ if ( aDelData.IsDelete() )
+ return;
+ Click();
+ if ( aDelData.IsDelete() )
+ return;
+ ImplRemoveDel( &aDelData );
+ mbStateChanged = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+RadioButton::RadioButton( Window* pParent, WinBits nStyle ) :
+ Button( WINDOW_RADIOBUTTON )
+{
+ ImplInitRadioButtonData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+RadioButton::RadioButton( Window* pParent, const ResId& rResId ) :
+ Button( WINDOW_RADIOBUTTON )
+{
+ ImplInitRadioButtonData();
+ rResId.SetRT( RSC_RADIOBUTTON );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplLoadRes( const ResId& rResId )
+{
+ Button::ImplLoadRes( rResId );
+
+ //anderer Wert als Default ?
+ USHORT nChecked = ReadShortRes();
+ if ( nChecked )
+ SetState( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+RadioButton::~RadioButton()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() && maMouseRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawRadioButtonState();
+ StartTracking();
+ return;
+ }
+
+ Button::MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::Tracking( const TrackingEvent& rTEvt )
+{
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
+ GrabFocus();
+
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ ImplCallClick();
+ else
+ ImplInvalidateOrDrawRadioButtonState();
+ }
+ }
+ else
+ {
+ if ( maMouseRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() ) )
+ {
+ if ( !(ImplGetButtonState() & BUTTON_DRAW_PRESSED) )
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawRadioButtonState();
+ }
+ }
+ else
+ {
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawRadioButtonState();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if ( !aKeyCode.GetModifier() && (aKeyCode.GetCode() == KEY_SPACE) )
+ {
+ if ( !(ImplGetButtonState() & BUTTON_DRAW_PRESSED) )
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawRadioButtonState();
+ }
+ }
+ else if ( (ImplGetButtonState() & BUTTON_DRAW_PRESSED) && (aKeyCode.GetCode() == KEY_ESCAPE) )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawRadioButtonState();
+ }
+ else
+ Button::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::KeyUp( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if ( (ImplGetButtonState() & BUTTON_DRAW_PRESSED) && (aKeyCode.GetCode() == KEY_SPACE) )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplCallClick();
+ }
+ else
+ Button::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<RadioButton*>(this)->ImplDrawRadioButton( true );
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::Paint( const Rectangle& )
+{
+ ImplDrawRadioButton();
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ if ( !maImage )
+ {
+ MapMode aResMapMode( MAP_100TH_MM );
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Size aImageSize = pDev->LogicToPixel( Size( 300, 300 ), aResMapMode );
+ Size aBrd1Size = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode );
+ Size aBrd2Size = pDev->LogicToPixel( Size( 60, 60 ), aResMapMode );
+ Font aFont = GetDrawPixelFont( pDev );
+ Rectangle aStateRect;
+ Rectangle aMouseRect;
+ Rectangle aFocusRect;
+
+ aImageSize.Width() = CalcZoom( aImageSize.Width() );
+ aImageSize.Height() = CalcZoom( aImageSize.Height() );
+ aBrd1Size.Width() = CalcZoom( aBrd1Size.Width() );
+ aBrd1Size.Height() = CalcZoom( aBrd1Size.Height() );
+ aBrd2Size.Width() = CalcZoom( aBrd2Size.Width() );
+ aBrd2Size.Height() = CalcZoom( aBrd2Size.Height() );
+
+ if ( !aBrd1Size.Width() )
+ aBrd1Size.Width() = 1;
+ if ( !aBrd1Size.Height() )
+ aBrd1Size.Height() = 1;
+ if ( !aBrd2Size.Width() )
+ aBrd2Size.Width() = 1;
+ if ( !aBrd2Size.Height() )
+ aBrd2Size.Height() = 1;
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ if ( nFlags & WINDOW_DRAW_MONO )
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ else
+ pDev->SetTextColor( GetTextColor() );
+ pDev->SetTextFillColor();
+
+ ImplDraw( pDev, nFlags, aPos, aSize,
+ aImageSize, aStateRect, aMouseRect );
+
+ Point aCenterPos = aStateRect.Center();
+ long nRadX = aImageSize.Width()/2;
+ long nRadY = aImageSize.Height()/2;
+
+ pDev->SetLineColor();
+ pDev->SetFillColor( Color( COL_BLACK ) );
+ pDev->DrawPolygon( Polygon( aCenterPos, nRadX, nRadY ) );
+ nRadX -= aBrd1Size.Width();
+ nRadY -= aBrd1Size.Height();
+ pDev->SetFillColor( Color( COL_WHITE ) );
+ pDev->DrawPolygon( Polygon( aCenterPos, nRadX, nRadY ) );
+ if ( mbChecked )
+ {
+ nRadX -= aBrd1Size.Width();
+ nRadY -= aBrd1Size.Height();
+ if ( !nRadX )
+ nRadX = 1;
+ if ( !nRadY )
+ nRadY = 1;
+ pDev->SetFillColor( Color( COL_BLACK ) );
+ pDev->DrawPolygon( Polygon( aCenterPos, nRadX, nRadY ) );
+ }
+
+ pDev->Pop();
+ }
+ else
+ {
+ DBG_ERROR( "RadioButton::Draw() - not implemented for RadioButton with Image" );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::GetFocus()
+{
+ ShowFocus( ImplGetFocusRect() );
+ SetInputContext( InputContext( GetFont() ) );
+ Button::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::LoseFocus()
+{
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawRadioButtonState();
+ }
+
+ HideFocus();
+ Button::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::StateChanged( StateChangedType nType )
+{
+ Button::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_STATE )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate( maStateRect );
+ }
+ else if ( (nType == STATE_CHANGE_ENABLE) ||
+ (nType == STATE_CHANGE_TEXT) ||
+ (nType == STATE_CHANGE_IMAGE) ||
+ (nType == STATE_CHANGE_DATA) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetWindow( WINDOW_PREV ), GetStyle() ) );
+
+ if ( (GetPrevStyle() & RADIOBUTTON_VIEW_STYLE) !=
+ (GetStyle() & RADIOBUTTON_VIEW_STYLE) )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Button::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long RadioButton::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL) )
+ {
+ if( ( maMouseRect.IsInside( GetPointerPosPixel()) &&
+ !maMouseRect.IsInside( GetLastPointerPosPixel()) ) ||
+ ( maMouseRect.IsInside( GetLastPointerPosPixel()) &&
+ !maMouseRect.IsInside( GetPointerPosPixel()) ) ||
+ pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
+ {
+ Invalidate( maStateRect );
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Button::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::Toggle()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_RADIOBUTTON_TOGGLE, maToggleHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL RadioButton::SetModeRadioImage( const Image& rImage, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+{
+ if ( rImage != maImage )
+ {
+ maImage = rImage;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ if( maImageHC != rImage )
+ {
+ maImageHC = rImage;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+const Image& RadioButton::GetModeRadioImage( BmpColorMode eMode ) const
+{
+ if( eMode == BMP_COLOR_HIGHCONTRAST )
+ return maImageHC;
+ else
+ return maImage;
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::SetState( BOOL bCheck )
+{
+ // TabStop-Flag richtig mitfuehren
+ if ( bCheck )
+ mpWindowImpl->mnStyle |= WB_TABSTOP;
+ else
+ mpWindowImpl->mnStyle &= ~WB_TABSTOP;
+
+ if ( mbChecked != bCheck )
+ {
+ mbChecked = bCheck;
+ StateChanged( STATE_CHANGE_STATE );
+ Toggle();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::Check( BOOL bCheck )
+{
+ // TabStop-Flag richtig mitfuehren
+ if ( bCheck )
+ mpWindowImpl->mnStyle |= WB_TABSTOP;
+ else
+ mpWindowImpl->mnStyle &= ~WB_TABSTOP;
+
+ if ( mbChecked != bCheck )
+ {
+ mbChecked = bCheck;
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ StateChanged( STATE_CHANGE_STATE );
+ if ( aDelData.IsDelete() )
+ return;
+ if ( bCheck && mbRadioCheck )
+ ImplUncheckAllOther();
+ if ( aDelData.IsDelete() )
+ return;
+ Toggle();
+ ImplRemoveDel( &aDelData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long RadioButton::ImplGetImageToTextDistance() const
+{
+ // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
+ // which might have been aligned with the text of the check box
+ return CalcZoom( 4 );
+}
+
+// -----------------------------------------------------------------------
+
+Size RadioButton::ImplGetRadioImageSize() const
+{
+ Size aSize;
+ // why are IsNativeControlSupported and GetNativeControlRegion not const ?
+ RadioButton* pThis = const_cast<RadioButton*>(this);
+ bool bDefaultSize = true;
+ if( pThis->IsNativeControlSupported( CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aControlValue;
+ // #i45896# workaround gcc3.3 temporary problem
+ Rectangle aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
+ ControlState nState = CTRL_STATE_DEFAULT|CTRL_STATE_ENABLED;
+ Rectangle aBoundingRgn, aContentRgn;
+
+ // get native size of a radio button
+ if( pThis->GetNativeControlRegion( CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL, aCtrlRegion,
+ nState, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ aSize = aContentRgn.GetSize();
+ bDefaultSize = false;
+ }
+ }
+ if( bDefaultSize )
+ aSize = GetRadioImage( GetSettings(), 0 ).GetSizePixel();
+ return aSize;
+}
+
+static void LoadThemedImageList (const StyleSettings &rStyleSettings,
+ ImageList *pList, const ResId &rResId,
+ USHORT nImages)
+{
+ Color aColorAry1[6];
+ Color aColorAry2[6];
+ aColorAry1[0] = Color( 0xC0, 0xC0, 0xC0 );
+ aColorAry1[1] = Color( 0xFF, 0xFF, 0x00 );
+ aColorAry1[2] = Color( 0xFF, 0xFF, 0xFF );
+ aColorAry1[3] = Color( 0x80, 0x80, 0x80 );
+ aColorAry1[4] = Color( 0x00, 0x00, 0x00 );
+ aColorAry1[5] = Color( 0x00, 0xFF, 0x00 );
+ aColorAry2[0] = rStyleSettings.GetFaceColor();
+ aColorAry2[1] = rStyleSettings.GetWindowColor();
+ aColorAry2[2] = rStyleSettings.GetLightColor();
+ aColorAry2[3] = rStyleSettings.GetShadowColor();
+ aColorAry2[4] = rStyleSettings.GetDarkShadowColor();
+ aColorAry2[5] = rStyleSettings.GetWindowTextColor();
+
+ Color aMaskColor(0x00, 0x00, 0xFF );
+ DBG_ASSERT( sizeof(aColorAry1) == sizeof(aColorAry2), "aColorAry1 must match aColorAry2" );
+ // FIXME: do we want the mask for the checkbox ?
+ pList->InsertFromHorizontalBitmap (rResId, nImages, &aMaskColor,
+ aColorAry1, aColorAry2, sizeof(aColorAry1) / sizeof(Color));
+}
+
+Image RadioButton::GetRadioImage( const AllSettings& rSettings, USHORT nFlags )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ const StyleSettings& rStyleSettings = rSettings.GetStyleSettings();
+ USHORT nStyle = rStyleSettings.GetRadioButtonStyle() & STYLE_RADIOBUTTON_STYLE;
+
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO )
+ nStyle = STYLE_RADIOBUTTON_MONO;
+
+ if ( !pSVData->maCtrlData.mpRadioImgList ||
+ (pSVData->maCtrlData.mnRadioStyle != nStyle) ||
+ (pSVData->maCtrlData.mnLastRadioFColor != rStyleSettings.GetFaceColor().GetColor()) ||
+ (pSVData->maCtrlData.mnLastRadioWColor != rStyleSettings.GetWindowColor().GetColor()) ||
+ (pSVData->maCtrlData.mnLastRadioLColor != rStyleSettings.GetLightColor().GetColor()) )
+ {
+ if ( pSVData->maCtrlData.mpRadioImgList )
+ delete pSVData->maCtrlData.mpRadioImgList;
+
+ pSVData->maCtrlData.mnLastRadioFColor = rStyleSettings.GetFaceColor().GetColor();
+ pSVData->maCtrlData.mnLastRadioWColor = rStyleSettings.GetWindowColor().GetColor();
+ pSVData->maCtrlData.mnLastRadioLColor = rStyleSettings.GetLightColor().GetColor();
+
+ Color pColorAry1[6];
+ Color pColorAry2[6];
+ pColorAry1[0] = Color( 0xC0, 0xC0, 0xC0 );
+ pColorAry1[1] = Color( 0xFF, 0xFF, 0x00 );
+ pColorAry1[2] = Color( 0xFF, 0xFF, 0xFF );
+ pColorAry1[3] = Color( 0x80, 0x80, 0x80 );
+ pColorAry1[4] = Color( 0x00, 0x00, 0x00 );
+ pColorAry1[5] = Color( 0x00, 0xFF, 0x00 );
+ pColorAry2[0] = rStyleSettings.GetFaceColor();
+ pColorAry2[1] = rStyleSettings.GetWindowColor();
+ pColorAry2[2] = rStyleSettings.GetLightColor();
+ pColorAry2[3] = rStyleSettings.GetShadowColor();
+ pColorAry2[4] = rStyleSettings.GetDarkShadowColor();
+ pColorAry2[5] = rStyleSettings.GetWindowTextColor();
+
+ ResMgr* pResMgr = ImplGetResMgr();
+ pSVData->maCtrlData.mpRadioImgList = new ImageList();
+ if( pResMgr )
+ LoadThemedImageList( rStyleSettings,
+ pSVData->maCtrlData.mpRadioImgList,
+ ResId( SV_RESID_BITMAP_RADIO+nStyle, *pResMgr ), 6 );
+ pSVData->maCtrlData.mnRadioStyle = nStyle;
+ }
+
+ USHORT nId;
+ if ( nFlags & BUTTON_DRAW_DISABLED )
+ {
+ if ( nFlags & BUTTON_DRAW_CHECKED )
+ nId = 6;
+ else
+ nId = 5;
+ }
+ else if ( nFlags & BUTTON_DRAW_PRESSED )
+ {
+ if ( nFlags & BUTTON_DRAW_CHECKED )
+ nId = 4;
+ else
+ nId = 3;
+ }
+ else
+ {
+ if ( nFlags & BUTTON_DRAW_CHECKED )
+ nId = 2;
+ else
+ nId = 1;
+ }
+ return pSVData->maCtrlData.mpRadioImgList->GetImage( nId );
+}
+
+// -----------------------------------------------------------------------
+
+void RadioButton::ImplSetMinimumNWFSize()
+{
+ Push( PUSH_MAPMODE );
+ SetMapMode( MAP_PIXEL );
+
+ ImplControlValue aControlValue;
+ Size aCurSize( GetSizePixel() );
+ Rectangle aCtrlRegion( Point( 0, 0 ), aCurSize );
+ Rectangle aBoundingRgn, aContentRgn;
+
+ // get native size of a radiobutton
+ if( GetNativeControlRegion( CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_DEFAULT|CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Size aSize = aContentRgn.GetSize();
+
+ if( aSize.Height() > aCurSize.Height() )
+ {
+ aCurSize.Height() = aSize.Height();
+ SetSizePixel( aCurSize );
+ }
+ }
+
+ Pop();
+}
+
+// -----------------------------------------------------------------------
+
+Size RadioButton::CalcMinimumSize( long nMaxWidth ) const
+{
+ Size aSize;
+ if ( !maImage )
+ aSize = ImplGetRadioImageSize();
+ else
+ aSize = maImage.GetSizePixel();
+
+ nMaxWidth -= aSize.Width();
+
+ XubString aText = GetText();
+ if ( aText.Len() && ! (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) )
+ {
+ // subtract what will be added later
+ nMaxWidth-=2;
+ nMaxWidth -= ImplGetImageToTextDistance();
+
+ Size aTextSize = GetTextRect( Rectangle( Point(), Size( nMaxWidth > 0 ? nMaxWidth : 0x7fffffff, 0x7fffffff ) ),
+ aText, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
+ aSize.Width()+=2; // for focus rect
+ aSize.Width() += ImplGetImageToTextDistance();
+ aSize.Width() += aTextSize.Width();
+ if ( aSize.Height() < aTextSize.Height() )
+ aSize.Height() = aTextSize.Height();
+ }
+ else if ( !maImage )
+ {
+/* da ansonsten im Writer die Control zu weit oben haengen
+ aSize.Width() += 2;
+ aSize.Height() += 2;
+*/
+ }
+
+ return CalcWindowSize( aSize );
+}
+
+// -----------------------------------------------------------------------
+
+Size RadioButton::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Button::GetOptimalSize( eType );
+ }
+}
+
+// =======================================================================
+
+void CheckBox::ImplInitCheckBoxData()
+{
+ meState = STATE_NOCHECK;
+ meSaveValue = STATE_NOCHECK;
+ mbTriState = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( pParent->GetWindow( WINDOW_LASTCHILD ), nStyle );
+ Button::ImplInit( pParent, nStyle, NULL );
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits CheckBox::ImplInitStyle( const Window* pPrevWindow, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+ if ( !(nStyle & WB_NOGROUP) &&
+ (!pPrevWindow || (pPrevWindow->GetType() != WINDOW_CHECKBOX)) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------
+
+const Font& CheckBox::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetRadioCheckFont();
+}
+
+// -----------------------------------------------------------------
+const Color& CheckBox::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetRadioCheckTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Button::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ Window* pParent = GetParent();
+ if ( !IsControlBackground() &&
+ (pParent->IsChildTransparentModeEnabled() || IsNativeControlSupported( CTRL_CHECKBOX, PART_ENTIRE_CONTROL ) ) )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ if( IsNativeControlSupported( CTRL_CHECKBOX, PART_ENTIRE_CONTROL ) )
+ ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplLoadRes( const ResId& rResId )
+{
+ Button::ImplLoadRes( rResId );
+
+ if ( rResId.GetRT() != RSC_TRISTATEBOX )
+ {
+ USHORT nChecked = ReadShortRes();
+ //anderer Wert als Default ?
+ if( nChecked )
+ Check( TRUE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplInvalidateOrDrawCheckBoxState()
+{
+ if( ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase )
+ {
+ if ( IsNativeControlSupported(CTRL_CHECKBOX, PART_ENTIRE_CONTROL) )
+ {
+ Invalidate();
+ Update();
+ return;
+ }
+ }
+ ImplDrawCheckBoxState();
+}
+
+void CheckBox::ImplDrawCheckBoxState()
+{
+ bool bNativeOK = TRUE;
+
+ if ( (bNativeOK=IsNativeControlSupported(CTRL_CHECKBOX, PART_ENTIRE_CONTROL)) == TRUE )
+ {
+ ImplControlValue aControlValue( meState == STATE_CHECK ? BUTTONVALUE_ON : BUTTONVALUE_OFF );
+ Rectangle aCtrlRegion( maStateRect );
+ ControlState nState = 0;
+
+ if ( HasFocus() ) nState |= CTRL_STATE_FOCUSED;
+ if ( ImplGetButtonState() & BUTTON_DRAW_DEFAULT ) nState |= CTRL_STATE_DEFAULT;
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED ) nState |= CTRL_STATE_PRESSED;
+ if ( IsEnabled() ) nState |= CTRL_STATE_ENABLED;
+
+ if ( meState == STATE_CHECK )
+ aControlValue.setTristateVal( BUTTONVALUE_ON );
+ else if ( meState == STATE_DONTKNOW )
+ aControlValue.setTristateVal( BUTTONVALUE_MIXED );
+
+ if ( IsMouseOver() && maMouseRect.IsInside( GetPointerPosPixel() ) )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ bNativeOK = DrawNativeControl( CTRL_CHECKBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() );
+ }
+
+ if ( bNativeOK == FALSE )
+ {
+ USHORT nStyle = ImplGetButtonState();
+ if ( !IsEnabled() )
+ nStyle |= BUTTON_DRAW_DISABLED;
+ if ( meState == STATE_DONTKNOW )
+ nStyle |= BUTTON_DRAW_DONTKNOW;
+ else if ( meState == STATE_CHECK )
+ nStyle |= BUTTON_DRAW_CHECKED;
+ Image aImage = GetCheckImage( GetSettings(), nStyle );
+ if ( IsZoom() )
+ DrawImage( maStateRect.TopLeft(), maStateRect.GetSize(), aImage );
+ else
+ DrawImage( maStateRect.TopLeft(), aImage );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize,
+ const Size& rImageSize, Rectangle& rStateRect,
+ Rectangle& rMouseRect, bool bLayout )
+{
+ WinBits nWinStyle = GetStyle();
+ XubString aText( GetText() );
+
+ pDev->Push( PUSH_CLIPREGION | PUSH_LINECOLOR );
+ pDev->IntersectClipRegion( Rectangle( rPos, rSize ) );
+
+ long nLineY = rPos.Y() + (rSize.Height()-1)/2;
+ if ( ( aText.Len() && ! (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) ) ||
+ ( HasImage() && ! (ImplGetButtonState() & BUTTON_DRAW_NOIMAGE) ) )
+ {
+ USHORT nTextStyle = Button::ImplGetTextStyle( aText, nWinStyle, nDrawFlags );
+
+ const long nImageSep = GetDrawPixel( pDev, ImplGetImageToTextDistance() );
+ Size aSize( rSize );
+ Point aPos( rPos );
+ aPos.X() += rImageSize.Width() + nImageSep;
+ aSize.Width() -= rImageSize.Width() + nImageSep;
+
+ // if the text rect height is smaller than the height of the image
+ // then for single lines the default should be centered text
+ if( (nWinStyle & (WB_TOP|WB_VCENTER|WB_BOTTOM)) == 0 &&
+ (rImageSize.Height() > rSize.Height() || ! (nWinStyle & WB_WORDBREAK) ) )
+ {
+ nTextStyle &= ~(TEXT_DRAW_TOP|TEXT_DRAW_BOTTOM);
+ nTextStyle |= TEXT_DRAW_VCENTER;
+ aSize.Height() = rImageSize.Height();
+ }
+
+ ImplDrawAlignedImage( pDev, aPos, aSize, bLayout, 1,
+ nDrawFlags, nTextStyle, NULL );
+ nLineY = aPos.Y() + aSize.Height()/2;
+
+ rMouseRect = Rectangle( aPos, aSize );
+ rMouseRect.Left() = rPos.X();
+ rStateRect.Left() = rPos.X();
+ rStateRect.Top() = rMouseRect.Top();
+
+ if ( aSize.Height() > rImageSize.Height() )
+ rStateRect.Top() += ( aSize.Height() - rImageSize.Height() ) / 2;
+ else
+ {
+ rStateRect.Top() -= ( rImageSize.Height() - aSize.Height() ) / 2;
+ if( rStateRect.Top() < 0 )
+ rStateRect.Top() = 0;
+ }
+
+ rStateRect.Right() = rStateRect.Left()+rImageSize.Width()-1;
+ rStateRect.Bottom() = rStateRect.Top()+rImageSize.Height()-1;
+ if ( rStateRect.Bottom() > rMouseRect.Bottom() )
+ rMouseRect.Bottom() = rStateRect.Bottom();
+ }
+ else
+ {
+ if ( nWinStyle & WB_CENTER )
+ rStateRect.Left() = rPos.X()+((rSize.Width()-rImageSize.Width())/2);
+ else if ( nWinStyle & WB_RIGHT )
+ rStateRect.Left() = rPos.X()+rSize.Width()-rImageSize.Width();
+ else
+ rStateRect.Left() = rPos.X();
+ if ( nWinStyle & WB_VCENTER )
+ rStateRect.Top() = rPos.Y()+((rSize.Height()-rImageSize.Height())/2);
+ else if ( nWinStyle & WB_BOTTOM )
+ rStateRect.Top() = rPos.Y()+rSize.Height()-rImageSize.Height();
+ else
+ rStateRect.Top() = rPos.Y();
+ rStateRect.Right() = rStateRect.Left()+rImageSize.Width()-1;
+ rStateRect.Bottom() = rStateRect.Top()+rImageSize.Height()-1;
+ // provide space for focusrect
+ // note: this assumes that the control's size was adjusted
+ // accordingly in Get/LoseFocus, so the onscreen position won't change
+ if( HasFocus() )
+ rStateRect.Move( 1, 1 );
+ rMouseRect = rStateRect;
+
+ ImplSetFocusRect( rStateRect );
+ }
+
+ const int nLineSpace = 4;
+ if( (GetStyle() & WB_CBLINESTYLE) != 0 &&
+ rMouseRect.Right()-1-nLineSpace < rPos.X()+rSize.Width() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO )
+ SetLineColor( Color( COL_BLACK ) );
+ else
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ long nLineX = rMouseRect.Right()+nLineSpace;
+ DrawLine( Point( nLineX, nLineY ), Point( rPos.X() + rSize.Width()-1, nLineY ) );
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ {
+ SetLineColor( rStyleSettings.GetLightColor() );
+ DrawLine( Point( nLineX, nLineY+1 ), Point( rPos.X() + rSize.Width()-1, nLineY+1 ) );
+ }
+ }
+
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplDrawCheckBox( bool bLayout )
+{
+ Size aImageSize = ImplGetCheckImageSize();
+ aImageSize.Width() = CalcZoom( aImageSize.Width() );
+ aImageSize.Height() = CalcZoom( aImageSize.Height() );
+
+ if( !bLayout )
+ HideFocus();
+
+ ImplDraw( this, 0, Point(), GetOutputSizePixel(), aImageSize,
+ maStateRect, maMouseRect, bLayout );
+
+ if( !bLayout )
+ {
+ ImplDrawCheckBoxState();
+ if ( HasFocus() )
+ ShowFocus( ImplGetFocusRect() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplCheck()
+{
+ TriState eNewState;
+ if ( meState == STATE_NOCHECK )
+ eNewState = STATE_CHECK;
+ else if ( !mbTriState )
+ eNewState = STATE_NOCHECK;
+ else if ( meState == STATE_CHECK )
+ eNewState = STATE_DONTKNOW;
+ else
+ eNewState = STATE_NOCHECK;
+ meState = eNewState;
+
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ if( (GetStyle() & WB_EARLYTOGGLE) )
+ Toggle();
+ ImplInvalidateOrDrawCheckBoxState();
+ if( ! (GetStyle() & WB_EARLYTOGGLE) )
+ Toggle();
+ if ( aDelData.IsDelete() )
+ return;
+ ImplRemoveDel( &aDelData );
+ Click();
+}
+
+// -----------------------------------------------------------------------
+
+CheckBox::CheckBox( Window* pParent, WinBits nStyle ) :
+ Button( WINDOW_CHECKBOX )
+{
+ ImplInitCheckBoxData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+CheckBox::CheckBox( Window* pParent, const ResId& rResId ) :
+ Button( WINDOW_CHECKBOX )
+{
+ ImplInitCheckBoxData();
+ rResId.SetRT( RSC_CHECKBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() && maMouseRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawCheckBoxState();
+ StartTracking();
+ return;
+ }
+
+ Button::MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::Tracking( const TrackingEvent& rTEvt )
+{
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
+ GrabFocus();
+
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ ImplCheck();
+ else
+ ImplInvalidateOrDrawCheckBoxState();
+ }
+ }
+ else
+ {
+ if ( maMouseRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() ) )
+ {
+ if ( !(ImplGetButtonState() & BUTTON_DRAW_PRESSED) )
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawCheckBoxState();
+ }
+ }
+ else
+ {
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawCheckBoxState();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if ( !aKeyCode.GetModifier() && (aKeyCode.GetCode() == KEY_SPACE) )
+ {
+ if ( !(ImplGetButtonState() & BUTTON_DRAW_PRESSED) )
+ {
+ ImplGetButtonState() |= BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawCheckBoxState();
+ }
+ }
+ else if ( (ImplGetButtonState() & BUTTON_DRAW_PRESSED) && (aKeyCode.GetCode() == KEY_ESCAPE) )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawCheckBoxState();
+ }
+ else
+ Button::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::KeyUp( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if ( (ImplGetButtonState() & BUTTON_DRAW_PRESSED) && (aKeyCode.GetCode() == KEY_SPACE) )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplCheck();
+ }
+ else
+ Button::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<CheckBox*>(this)->ImplDrawCheckBox( true );
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::Paint( const Rectangle& )
+{
+ ImplDrawCheckBox();
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ MapMode aResMapMode( MAP_100TH_MM );
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Size aImageSize = pDev->LogicToPixel( Size( 300, 300 ), aResMapMode );
+ Size aBrd1Size = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode );
+ Size aBrd2Size = pDev->LogicToPixel( Size( 30, 30 ), aResMapMode );
+ long nCheckWidth = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode ).Width();
+ Font aFont = GetDrawPixelFont( pDev );
+ Rectangle aStateRect;
+ Rectangle aMouseRect;
+
+ aImageSize.Width() = CalcZoom( aImageSize.Width() );
+ aImageSize.Height() = CalcZoom( aImageSize.Height() );
+ aBrd1Size.Width() = CalcZoom( aBrd1Size.Width() );
+ aBrd1Size.Height() = CalcZoom( aBrd1Size.Height() );
+ aBrd2Size.Width() = CalcZoom( aBrd2Size.Width() );
+ aBrd2Size.Height() = CalcZoom( aBrd2Size.Height() );
+
+ if ( !aBrd1Size.Width() )
+ aBrd1Size.Width() = 1;
+ if ( !aBrd1Size.Height() )
+ aBrd1Size.Height() = 1;
+ if ( !aBrd2Size.Width() )
+ aBrd2Size.Width() = 1;
+ if ( !aBrd2Size.Height() )
+ aBrd2Size.Height() = 1;
+ if ( !nCheckWidth )
+ nCheckWidth = 1;
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ if ( nFlags & WINDOW_DRAW_MONO )
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ else
+ pDev->SetTextColor( GetTextColor() );
+ pDev->SetTextFillColor();
+
+ ImplDraw( pDev, nFlags, aPos, aSize,
+ aImageSize, aStateRect, aMouseRect, false );
+
+ pDev->SetLineColor();
+ pDev->SetFillColor( Color( COL_BLACK ) );
+ pDev->DrawRect( aStateRect );
+ aStateRect.Left() += aBrd1Size.Width();
+ aStateRect.Top() += aBrd1Size.Height();
+ aStateRect.Right() -= aBrd1Size.Width();
+ aStateRect.Bottom() -= aBrd1Size.Height();
+ if ( meState == STATE_DONTKNOW )
+ pDev->SetFillColor( Color( COL_LIGHTGRAY ) );
+ else
+ pDev->SetFillColor( Color( COL_WHITE ) );
+ pDev->DrawRect( aStateRect );
+
+ if ( meState == STATE_CHECK )
+ {
+ aStateRect.Left() += aBrd2Size.Width();
+ aStateRect.Top() += aBrd2Size.Height();
+ aStateRect.Right() -= aBrd2Size.Width();
+ aStateRect.Bottom() -= aBrd2Size.Height();
+ Point aPos11( aStateRect.TopLeft() );
+ Point aPos12( aStateRect.BottomRight() );
+ Point aPos21( aStateRect.TopRight() );
+ Point aPos22( aStateRect.BottomLeft() );
+ Point aTempPos11( aPos11 );
+ Point aTempPos12( aPos12 );
+ Point aTempPos21( aPos21 );
+ Point aTempPos22( aPos22 );
+ pDev->SetLineColor( Color( COL_BLACK ) );
+ long nDX = 0;
+ for ( long i = 0; i < nCheckWidth; i++ )
+ {
+ if ( !(i % 2) )
+ {
+ aTempPos11.X() = aPos11.X()+nDX;
+ aTempPos12.X() = aPos12.X()+nDX;
+ aTempPos21.X() = aPos21.X()+nDX;
+ aTempPos22.X() = aPos22.X()+nDX;
+ }
+ else
+ {
+ nDX++;
+ aTempPos11.X() = aPos11.X()-nDX;
+ aTempPos12.X() = aPos12.X()-nDX;
+ aTempPos21.X() = aPos21.X()-nDX;
+ aTempPos22.X() = aPos22.X()-nDX;
+ }
+ pDev->DrawLine( aTempPos11, aTempPos12 );
+ pDev->DrawLine( aTempPos21, aTempPos22 );
+ }
+ }
+
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::GetFocus()
+{
+ if ( !GetText().Len() || (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) )
+ {
+ // increase button size to have space for focus rect
+ // checkboxes without text will draw focusrect around the check
+ // See CheckBox::ImplDraw()
+ Point aPos( GetPosPixel() );
+ Size aSize( GetSizePixel() );
+ aPos.Move(-1,-1);
+ aSize.Height() += 2;
+ aSize.Width() += 2;
+ SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height(), WINDOW_POSSIZE_ALL );
+ ImplDrawCheckBox();
+ }
+ else
+ ShowFocus( ImplGetFocusRect() );
+
+ SetInputContext( InputContext( GetFont() ) );
+ Button::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::LoseFocus()
+{
+ if ( ImplGetButtonState() & BUTTON_DRAW_PRESSED )
+ {
+ ImplGetButtonState() &= ~BUTTON_DRAW_PRESSED;
+ ImplInvalidateOrDrawCheckBoxState();
+ }
+
+ HideFocus();
+ Button::LoseFocus();
+
+ if ( !GetText().Len() || (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) )
+ {
+ // decrease button size again (see GetFocus())
+ // checkboxes without text will draw focusrect around the check
+ Point aPos( GetPosPixel() );
+ Size aSize( GetSizePixel() );
+ aPos.Move(1,1);
+ aSize.Height() -= 2;
+ aSize.Width() -= 2;
+ SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height(), WINDOW_POSSIZE_ALL );
+ ImplDrawCheckBox();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::StateChanged( StateChangedType nType )
+{
+ Button::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_STATE )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate( maStateRect );
+ }
+ else if ( (nType == STATE_CHANGE_ENABLE) ||
+ (nType == STATE_CHANGE_TEXT) ||
+ (nType == STATE_CHANGE_IMAGE) ||
+ (nType == STATE_CHANGE_DATA) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetWindow( WINDOW_PREV ), GetStyle() ) );
+
+ if ( (GetPrevStyle() & CHECKBOX_VIEW_STYLE) !=
+ (GetStyle() & CHECKBOX_VIEW_STYLE) )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Button::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long CheckBox::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_CHECKBOX, PART_ENTIRE_CONTROL) )
+ {
+ if( ( maMouseRect.IsInside( GetPointerPosPixel()) &&
+ !maMouseRect.IsInside( GetLastPointerPosPixel()) ) ||
+ ( maMouseRect.IsInside( GetLastPointerPosPixel()) &&
+ !maMouseRect.IsInside( GetPointerPosPixel()) ) ||
+ pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
+ {
+ Invalidate( maStateRect );
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Button::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::Toggle()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_CHECKBOX_TOGGLE, maToggleHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::SetState( TriState eState )
+{
+ if ( !mbTriState && (eState == STATE_DONTKNOW) )
+ eState = STATE_NOCHECK;
+
+ if ( meState != eState )
+ {
+ meState = eState;
+ StateChanged( STATE_CHANGE_STATE );
+ Toggle();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::EnableTriState( BOOL bTriState )
+{
+ if ( mbTriState != bTriState )
+ {
+ mbTriState = bTriState;
+
+ if ( !bTriState && (meState == STATE_DONTKNOW) )
+ SetState( STATE_NOCHECK );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long CheckBox::ImplGetImageToTextDistance() const
+{
+ // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
+ // which might have been aligned with the text of the check box
+ return CalcZoom( 4 );
+}
+
+// -----------------------------------------------------------------------
+
+Size CheckBox::ImplGetCheckImageSize() const
+{
+ Size aSize;
+ // why are IsNativeControlSupported and GetNativeControlRegion not const ?
+ CheckBox* pThis = const_cast<CheckBox*>(this);
+ bool bDefaultSize = true;
+ if( pThis->IsNativeControlSupported( CTRL_CHECKBOX, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aControlValue;
+ // #i45896# workaround gcc3.3 temporary problem
+ Rectangle aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
+ ControlState nState = CTRL_STATE_DEFAULT|CTRL_STATE_ENABLED;
+ Rectangle aBoundingRgn, aContentRgn;
+
+ // get native size of a check box
+ if( pThis->GetNativeControlRegion( CTRL_CHECKBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
+ nState, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ aSize = aContentRgn.GetSize();
+ bDefaultSize = false;
+ }
+ }
+ if( bDefaultSize )
+ aSize = GetCheckImage( GetSettings(), 0 ).GetSizePixel();
+ return aSize;
+}
+
+Image CheckBox::GetCheckImage( const AllSettings& rSettings, USHORT nFlags )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ const StyleSettings& rStyleSettings = rSettings.GetStyleSettings();
+ USHORT nStyle = rStyleSettings.GetCheckBoxStyle() & STYLE_CHECKBOX_STYLE;
+
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO )
+ nStyle = STYLE_CHECKBOX_MONO;
+
+ if ( !pSVData->maCtrlData.mpCheckImgList ||
+ (pSVData->maCtrlData.mnCheckStyle != nStyle) ||
+ (pSVData->maCtrlData.mnLastCheckFColor != rStyleSettings.GetFaceColor().GetColor()) ||
+ (pSVData->maCtrlData.mnLastCheckWColor != rStyleSettings.GetWindowColor().GetColor()) ||
+ (pSVData->maCtrlData.mnLastCheckLColor != rStyleSettings.GetLightColor().GetColor()) )
+ {
+ if ( pSVData->maCtrlData.mpCheckImgList )
+ delete pSVData->maCtrlData.mpCheckImgList;
+
+ pSVData->maCtrlData.mnLastCheckFColor = rStyleSettings.GetFaceColor().GetColor();
+ pSVData->maCtrlData.mnLastCheckWColor = rStyleSettings.GetWindowColor().GetColor();
+ pSVData->maCtrlData.mnLastCheckLColor = rStyleSettings.GetLightColor().GetColor();
+
+ ResMgr* pResMgr = ImplGetResMgr();
+ pSVData->maCtrlData.mpCheckImgList = new ImageList();
+ if( pResMgr )
+ LoadThemedImageList( rStyleSettings,
+ pSVData->maCtrlData.mpCheckImgList,
+ ResId( SV_RESID_BITMAP_CHECK+nStyle, *pResMgr ), 9 );
+ pSVData->maCtrlData.mnCheckStyle = nStyle;
+ }
+
+ USHORT nId;
+ if ( nFlags & BUTTON_DRAW_DISABLED )
+ {
+ if ( nFlags & BUTTON_DRAW_DONTKNOW )
+ nId = 9;
+ else if ( nFlags & BUTTON_DRAW_CHECKED )
+ nId = 6;
+ else
+ nId = 5;
+ }
+ else if ( nFlags & BUTTON_DRAW_PRESSED )
+ {
+ if ( nFlags & BUTTON_DRAW_DONTKNOW )
+ nId = 8;
+ else if ( nFlags & BUTTON_DRAW_CHECKED )
+ nId = 4;
+ else
+ nId = 3;
+ }
+ else
+ {
+ if ( nFlags & BUTTON_DRAW_DONTKNOW )
+ nId = 7;
+ else if ( nFlags & BUTTON_DRAW_CHECKED )
+ nId = 2;
+ else
+ nId = 1;
+ }
+ return pSVData->maCtrlData.mpCheckImgList->GetImage( nId );
+}
+
+// -----------------------------------------------------------------------
+
+void CheckBox::ImplSetMinimumNWFSize()
+{
+ Push( PUSH_MAPMODE );
+ SetMapMode( MAP_PIXEL );
+
+ ImplControlValue aControlValue;
+ Size aCurSize( GetSizePixel() );
+ Rectangle aCtrlRegion( Point( 0, 0 ), aCurSize );
+ Rectangle aBoundingRgn, aContentRgn;
+
+ // get native size of a radiobutton
+ if( GetNativeControlRegion( CTRL_CHECKBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_DEFAULT|CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Size aSize = aContentRgn.GetSize();
+
+ if( aSize.Height() > aCurSize.Height() )
+ {
+ aCurSize.Height() = aSize.Height();
+ SetSizePixel( aCurSize );
+ }
+ }
+
+ Pop();
+}
+
+// -----------------------------------------------------------------------
+
+Size CheckBox::CalcMinimumSize( long nMaxWidth ) const
+{
+ Size aSize = ImplGetCheckImageSize();
+ nMaxWidth -= aSize.Width();
+
+ XubString aText = GetText();
+ if ( aText.Len() && ! (ImplGetButtonState() & BUTTON_DRAW_NOTEXT) )
+ {
+ // subtract what will be added later
+ nMaxWidth-=2;
+ nMaxWidth -= ImplGetImageToTextDistance();
+
+ Size aTextSize = GetTextRect( Rectangle( Point(), Size( nMaxWidth > 0 ? nMaxWidth : 0x7fffffff, 0x7fffffff ) ),
+ aText, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
+ aSize.Width()+=2; // for focus rect
+ aSize.Width() += ImplGetImageToTextDistance();
+ aSize.Width() += aTextSize.Width();
+ if ( aSize.Height() < aTextSize.Height() )
+ aSize.Height() = aTextSize.Height();
+ }
+ else
+ {
+ // is this still correct ? since the checkbox now
+ // shows a focus rect it should be 2 pixels wider and longer
+/* da ansonsten im Writer die Control zu weit oben haengen
+ aSize.Width() += 2;
+ aSize.Height() += 2;
+*/
+ }
+
+ return CalcWindowSize( aSize );
+}
+
+// -----------------------------------------------------------------------
+
+Size CheckBox::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Button::GetOptimalSize( eType );
+ }
+}
+
+// =======================================================================
+
+ImageButton::ImageButton( WindowType nType ) :
+ PushButton( nType )
+{
+ ImplInitStyle();
+}
+
+// -----------------------------------------------------------------------
+
+ImageButton::ImageButton( Window* pParent, WinBits nStyle ) :
+ PushButton( pParent, nStyle )
+{
+ ImplInitStyle();
+}
+
+// -----------------------------------------------------------------------
+
+ImageButton::ImageButton( Window* pParent, const ResId& rResId ) :
+ PushButton( pParent, rResId.SetRT( RSC_IMAGEBUTTON ) )
+{
+ ULONG nObjMask = ReadLongRes();
+
+ if ( RSC_IMAGEBUTTON_IMAGE & nObjMask )
+ {
+ SetModeImage( Image( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+
+ if ( RSC_IMAGEBUTTON_SYMBOL & nObjMask )
+ SetSymbol( (SymbolType)ReadLongRes() );
+
+ if ( RSC_IMAGEBUTTON_STATE & nObjMask )
+ SetState( (TriState)ReadLongRes() );
+
+ ImplInitStyle();
+}
+
+// -----------------------------------------------------------------------
+
+ImageButton::~ImageButton()
+{
+}
+
+// -----------------------------------------------------------------------
+void ImageButton::ImplInitStyle()
+{
+ WinBits nStyle = GetStyle();
+
+ if ( ! ( nStyle & ( WB_RIGHT | WB_LEFT ) ) )
+ nStyle |= WB_CENTER;
+
+ if ( ! ( nStyle & ( WB_TOP | WB_BOTTOM ) ) )
+ nStyle |= WB_VCENTER;
+
+ SetStyle( nStyle );
+}
+
+// =======================================================================
+
+ImageRadioButton::ImageRadioButton( Window* pParent, WinBits nStyle ) :
+ RadioButton( pParent, nStyle )
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImageRadioButton::ImageRadioButton( Window* pParent, const ResId& rResId ) :
+ RadioButton( pParent, rResId.SetRT( RSC_IMAGERADIOBUTTON ) )
+{
+ ULONG nObjMask = ReadLongRes();
+
+ if ( RSC_IMAGERADIOBUTTON_IMAGE & nObjMask )
+ {
+ SetModeRadioImage( Image( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImageRadioButton::~ImageRadioButton()
+{
+}
+
+// =======================================================================
+
+TriStateBox::TriStateBox( Window* pParent, WinBits nStyle ) :
+ CheckBox( pParent, nStyle )
+{
+ EnableTriState( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+TriStateBox::TriStateBox( Window* pParent, const ResId& rResId ) :
+ CheckBox( pParent, rResId.SetRT( RSC_TRISTATEBOX ) )
+{
+ EnableTriState( TRUE );
+
+ ULONG nTriState = ReadLongRes();
+ USHORT bDisableTriState = ReadShortRes();
+ //anderer Wert als Default ?
+ if ( (TriState)nTriState != STATE_NOCHECK )
+ SetState( (TriState)nTriState );
+ if ( bDisableTriState )
+ EnableTriState( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+TriStateBox::~TriStateBox()
+{
+}
+
+// =======================================================================
+
+DisclosureButton::DisclosureButton( Window* pParent, WinBits ) :
+ CheckBox( pParent, WB_NOBORDER )
+{
+}
+
+// -----------------------------------------------------------------------
+
+DisclosureButton::DisclosureButton( Window* pParent, const ResId& rResId ) :
+ CheckBox( pParent, rResId.SetRT( RSC_CHECKBOX ) )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void DisclosureButton::ImplDrawCheckBoxState()
+{
+ /* HACK: DisclosureButton is currently assuming, that the disclosure sign
+ will fit into the rectangle occupied by a normal checkbox on all themes.
+ If this does not hold true for some theme, ImplGetCheckImageSize
+ would have to be overloaded for DisclosureButton; also GetNativeControlRegion
+ for CTRL_LISTNODE would have to be implemented and taken into account
+ */
+
+ Rectangle aStateRect( GetStateRect() );
+
+ ImplControlValue aControlValue( GetState() == STATE_CHECK ? BUTTONVALUE_ON : BUTTONVALUE_OFF );
+ Rectangle aCtrlRegion( aStateRect );
+ ControlState nState = 0;
+
+ if ( HasFocus() ) nState |= CTRL_STATE_FOCUSED;
+ if ( ImplGetButtonState() & BUTTON_DRAW_DEFAULT ) nState |= CTRL_STATE_DEFAULT;
+ if ( Window::IsEnabled() ) nState |= CTRL_STATE_ENABLED;
+ if ( IsMouseOver() && GetMouseRect().IsInside( GetPointerPosPixel() ) )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ if( ! DrawNativeControl( CTRL_LISTNODE, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() ) )
+ {
+ ImplSVCtrlData& rCtrlData( ImplGetSVData()->maCtrlData );
+ if( ! rCtrlData.mpDisclosurePlus )
+ rCtrlData.mpDisclosurePlus = new Image( BitmapEx( VclResId( SV_DISCLOSURE_PLUS ) ) );
+ if( ! rCtrlData.mpDisclosurePlusHC )
+ rCtrlData.mpDisclosurePlusHC = new Image( BitmapEx( VclResId( SV_DISCLOSURE_PLUS_HC ) ) );
+ if( ! rCtrlData.mpDisclosureMinus )
+ rCtrlData.mpDisclosureMinus = new Image( BitmapEx( VclResId( SV_DISCLOSURE_MINUS ) ) );
+ if( ! rCtrlData.mpDisclosureMinusHC )
+ rCtrlData.mpDisclosureMinusHC = new Image( BitmapEx( VclResId( SV_DISCLOSURE_MINUS_HC ) ) );
+
+ Image* pImg = NULL;
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ pImg = IsChecked() ? rCtrlData.mpDisclosureMinusHC : rCtrlData.mpDisclosurePlusHC;
+ else
+ pImg = IsChecked() ? rCtrlData.mpDisclosureMinus : rCtrlData.mpDisclosurePlus;
+
+ DBG_ASSERT( pImg, "no disclosure image" );
+ if( ! pImg )
+ return;
+
+ USHORT nStyle = 0;
+ if( ! IsEnabled() )
+ nStyle |= IMAGE_DRAW_DISABLE;
+
+ Size aSize( aStateRect.GetSize() );
+ Size aImgSize( pImg->GetSizePixel() );
+ Point aOff( (aSize.Width() - aImgSize.Width())/2,
+ (aSize.Height() - aImgSize.Height())/2 );
+ aOff += aStateRect.TopLeft();
+ DrawImage( aOff, *pImg, nStyle );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DisclosureButton::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if( !aKeyCode.GetModifier() &&
+ ( ( aKeyCode.GetCode() == KEY_ADD ) ||
+ ( aKeyCode.GetCode() == KEY_SUBTRACT ) )
+ )
+ {
+ Check( aKeyCode.GetCode() == KEY_ADD );
+ }
+ else
+ Button::KeyInput( rKEvt );
+}
+
+
diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx
new file mode 100644
index 000000000000..8efa3404a44a
--- /dev/null
+++ b/vcl/source/control/combobox.cxx
@@ -0,0 +1,1583 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/table.hxx>
+#include <tools/debug.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/ilstbox.hxx>
+#include <vcl/lstbox.h>
+#include <vcl/button.hxx>
+#include <vcl/subedit.hxx>
+#include <vcl/event.hxx>
+#include <vcl/combobox.hxx>
+#include <vcl/controldata.hxx>
+
+
+
+// =======================================================================
+
+inline ULONG ImplCreateKey( USHORT nPos )
+{
+ // Key = Pos+1, wegen Pos 0
+ return nPos+1;
+}
+
+// -----------------------------------------------------------------------
+
+static void lcl_GetSelectedEntries( Table& rSelectedPos, const XubString& rText, xub_Unicode cTokenSep, const ImplEntryList* pEntryList )
+{
+ for( xub_StrLen n = rText.GetTokenCount( cTokenSep ); n; )
+ {
+ XubString aToken = rText.GetToken( --n, cTokenSep );
+ aToken.EraseLeadingAndTrailingChars( ' ' );
+ USHORT nPos = pEntryList->FindEntry( aToken );
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ rSelectedPos.Insert( ImplCreateKey( nPos ), (void*)sal_IntPtr(1L) );
+ }
+}
+
+// =======================================================================
+
+ComboBox::ComboBox( WindowType nType ) :
+ Edit( nType )
+{
+ ImplInitComboBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+ComboBox::ComboBox( Window* pParent, WinBits nStyle ) :
+ Edit( WINDOW_COMBOBOX )
+{
+ ImplInitComboBoxData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ComboBox::ComboBox( Window* pParent, const ResId& rResId ) :
+ Edit( WINDOW_COMBOBOX )
+{
+ ImplInitComboBoxData();
+ rResId.SetRT( RSC_COMBOBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+ComboBox::~ComboBox()
+{
+ SetSubEdit( NULL );
+ delete mpSubEdit;
+
+ delete mpImplLB;
+ mpImplLB = NULL;
+
+ delete mpFloatWin;
+ delete mpBtn;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::ImplInitComboBoxData()
+{
+ mpSubEdit = NULL;
+ mpBtn = NULL;
+ mpImplLB = NULL;
+ mpFloatWin = NULL;
+
+ mnDDHeight = 0;
+ mbDDAutoSize = TRUE;
+ mbSyntheticModify = FALSE;
+ mbMatchCase = FALSE;
+ mcMultiSep = ';';
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::ImplCalcEditHeight()
+{
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ GetBorder( nLeft, nTop, nRight, nBottom );
+ mnDDHeight = (USHORT)(mpSubEdit->GetTextHeight() + nTop + nBottom + 4);
+ if ( !IsDropDownBox() )
+ mnDDHeight += 4;
+
+ Rectangle aCtrlRegion( Point( 0, 0 ), Size( 10, 10 ) );
+ Rectangle aBoundRegion, aContentRegion;
+ ImplControlValue aControlValue;
+ ControlType aType = IsDropDownBox() ? CTRL_COMBOBOX : CTRL_EDITBOX;
+ if( GetNativeControlRegion( aType, PART_ENTIRE_CONTROL,
+ aCtrlRegion,
+ CTRL_STATE_ENABLED,
+ aControlValue, rtl::OUString(),
+ aBoundRegion, aContentRegion ) )
+ {
+ const long nNCHeight = aBoundRegion.GetHeight();
+ if( mnDDHeight < nNCHeight )
+ mnDDHeight = sal::static_int_cast<USHORT>( nNCHeight );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::ImplInit( Window* pParent, WinBits nStyle )
+{
+ ImplInitStyle( nStyle );
+
+ BOOL bNoBorder = ( nStyle & WB_NOBORDER ) ? TRUE : FALSE;
+ if ( !(nStyle & WB_DROPDOWN) )
+ {
+ nStyle &= ~WB_BORDER;
+ nStyle |= WB_NOBORDER;
+ }
+ else
+ {
+ if ( !bNoBorder )
+ nStyle |= WB_BORDER;
+ }
+
+ Edit::ImplInit( pParent, nStyle );
+ SetBackground();
+
+ // DropDown ?
+ WinBits nEditStyle = nStyle & ( WB_LEFT | WB_RIGHT | WB_CENTER );
+ WinBits nListStyle = nStyle;
+ if( nStyle & WB_DROPDOWN )
+ {
+ mpFloatWin = new ImplListBoxFloatingWindow( this );
+ mpFloatWin->SetAutoWidth( TRUE );
+ mpFloatWin->SetPopupModeEndHdl( LINK( this, ComboBox, ImplPopupModeEndHdl ) );
+
+ mpBtn = new ImplBtn( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
+ ImplInitDropDownButton( mpBtn );
+ mpBtn->SetMBDownHdl( LINK( this, ComboBox, ImplClickBtnHdl ) );
+ mpBtn->Show();
+
+ nEditStyle |= WB_NOBORDER;
+ nListStyle &= ~WB_BORDER;
+ nListStyle |= WB_NOBORDER;
+ }
+ else
+ {
+ if ( !bNoBorder )
+ {
+ nEditStyle |= WB_BORDER;
+ nListStyle &= ~WB_NOBORDER;
+ nListStyle |= WB_BORDER;
+ }
+ }
+
+ mpSubEdit = new Edit( this, nEditStyle );
+ mpSubEdit->EnableRTL( FALSE );
+ SetSubEdit( mpSubEdit );
+ mpSubEdit->SetPosPixel( Point() );
+ EnableAutocomplete( TRUE );
+ mpSubEdit->Show();
+
+ Window* pLBParent = this;
+ if ( mpFloatWin )
+ pLBParent = mpFloatWin;
+ mpImplLB = new ImplListBox( pLBParent, nListStyle|WB_SIMPLEMODE );
+ mpImplLB->SetPosPixel( Point() );
+ mpImplLB->SetSelectHdl( LINK( this, ComboBox, ImplSelectHdl ) );
+ mpImplLB->SetCancelHdl( LINK( this, ComboBox, ImplCancelHdl ) );
+ mpImplLB->SetDoubleClickHdl( LINK( this, ComboBox, ImplDoubleClickHdl ) );
+ mpImplLB->SetUserDrawHdl( LINK( this, ComboBox, ImplUserDrawHdl ) );
+ mpImplLB->SetSelectionChangedHdl( LINK( this, ComboBox, ImplSelectionChangedHdl ) );
+ mpImplLB->Show();
+
+ if ( mpFloatWin )
+ mpFloatWin->SetImplListBox( mpImplLB );
+ else
+ mpImplLB->GetMainWindow()->AllowGrabFocus( TRUE );
+
+ ImplCalcEditHeight();
+
+ SetCompoundControl( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits ComboBox::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::ImplLoadRes( const ResId& rResId )
+{
+ Edit::ImplLoadRes( rResId );
+
+ ULONG nNumber = ReadLongRes();
+
+ if( nNumber )
+ {
+ for( USHORT i = 0; i < nNumber; i++ )
+ {
+ InsertEntry( ReadStringRes(), LISTBOX_APPEND );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::EnableAutocomplete( BOOL bEnable, BOOL bMatchCase )
+{
+ mbMatchCase = bMatchCase;
+
+ if ( bEnable )
+ mpSubEdit->SetAutocompleteHdl( LINK( this, ComboBox, ImplAutocompleteHdl ) );
+ else
+ mpSubEdit->SetAutocompleteHdl( Link() );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ComboBox::IsAutocompleteEnabled() const
+{
+ return mpSubEdit->GetAutocompleteHdl().IsSet();
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplClickBtnHdl, void*, EMPTYARG )
+{
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
+ mpSubEdit->GrabFocus();
+ if ( !mpImplLB->GetEntryList()->GetMRUCount() )
+ ImplUpdateFloatSelection();
+ else
+ mpImplLB->SelectEntry( 0 , TRUE );
+ mpBtn->SetPressed( TRUE );
+ SetSelection( Selection( 0, SELECTION_MAX ) );
+ mpFloatWin->StartFloat( TRUE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
+
+ ImplClearLayoutData();
+ if( mpImplLB )
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplPopupModeEndHdl, void*, EMPTYARG )
+{
+ if( mpFloatWin->IsPopupModeCanceled() )
+ {
+ if ( !mpImplLB->GetEntryList()->IsEntryPosSelected( mpFloatWin->GetPopupModeStartSaveSelection() ) )
+ {
+ mpImplLB->SelectEntry( mpFloatWin->GetPopupModeStartSaveSelection(), TRUE );
+ BOOL bTravelSelect = mpImplLB->IsTravelSelect();
+ mpImplLB->SetTravelSelect( TRUE );
+ Select();
+ mpImplLB->SetTravelSelect( bTravelSelect );
+ }
+ }
+
+ ImplClearLayoutData();
+ if( mpImplLB )
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+
+ mpBtn->SetPressed( FALSE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_CLOSE );
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplAutocompleteHdl, Edit*, pEdit )
+{
+ Selection aSel = pEdit->GetSelection();
+ AutocompleteAction eAction = pEdit->GetAutocompleteAction();
+
+ /* If there is no current selection do not auto complete on
+ Tab/Shift-Tab since then we would not cycle to the next field.
+ */
+ if ( aSel.Len() ||
+ ((eAction != AUTOCOMPLETE_TABFORWARD) && (eAction != AUTOCOMPLETE_TABBACKWARD)) )
+ {
+ XubString aFullText = pEdit->GetText();
+ XubString aStartText = aFullText.Copy( 0, (xub_StrLen)aSel.Max() );
+ USHORT nStart = mpImplLB->GetCurrentPos();
+
+ if ( nStart == LISTBOX_ENTRY_NOTFOUND )
+ nStart = 0;
+
+ BOOL bForward = TRUE;
+ if ( eAction == AUTOCOMPLETE_TABFORWARD )
+ nStart++;
+ else if ( eAction == AUTOCOMPLETE_TABBACKWARD )
+ {
+ bForward = FALSE;
+ nStart = nStart ? nStart - 1 : mpImplLB->GetEntryList()->GetEntryCount()-1;
+ }
+
+ USHORT nPos = LISTBOX_ENTRY_NOTFOUND;
+ if( ! mbMatchCase )
+ {
+ // Try match case insensitive from current position
+ nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, nStart, bForward, TRUE );
+ if ( nPos == LISTBOX_ENTRY_NOTFOUND )
+ // Try match case insensitive, but from start
+ nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, bForward ? 0 : (mpImplLB->GetEntryList()->GetEntryCount()-1), bForward, TRUE );
+ }
+
+ if ( nPos == LISTBOX_ENTRY_NOTFOUND )
+ // Try match full from current position
+ nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, nStart, bForward, FALSE );
+ if ( nPos == LISTBOX_ENTRY_NOTFOUND )
+ // Match full, but from start
+ nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, bForward ? 0 : (mpImplLB->GetEntryList()->GetEntryCount()-1), bForward, FALSE );
+
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ XubString aText = mpImplLB->GetEntryList()->GetEntryText( nPos );
+ Selection aSelection( aText.Len(), aStartText.Len() );
+ pEdit->SetText( aText, aSelection );
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplSelectHdl, void*, EMPTYARG )
+{
+ BOOL bPopup = IsInDropDown();
+ BOOL bCallSelect = FALSE;
+ if ( mpImplLB->IsSelectionChanged() || bPopup )
+ {
+ XubString aText;
+ if ( IsMultiSelectionEnabled() )
+ {
+ aText = mpSubEdit->GetText();
+
+ // Alle Eintraege entfernen, zu denen es einen Entry gibt, der aber nicht selektiert ist.
+ xub_StrLen nIndex = 0;
+ while ( nIndex != STRING_NOTFOUND )
+ {
+ xub_StrLen nPrevIndex = nIndex;
+ XubString aToken = aText.GetToken( 0, mcMultiSep, nIndex );
+ xub_StrLen nTokenLen = aToken.Len();
+ aToken.EraseLeadingAndTrailingChars( ' ' );
+ USHORT nP = mpImplLB->GetEntryList()->FindEntry( aToken );
+ if ( (nP != LISTBOX_ENTRY_NOTFOUND) && (!mpImplLB->GetEntryList()->IsEntryPosSelected( nP )) )
+ {
+ aText.Erase( nPrevIndex, nTokenLen );
+ nIndex = sal::static_int_cast<xub_StrLen>(nIndex - nTokenLen);
+ if ( (nPrevIndex < aText.Len()) && (aText.GetChar( nPrevIndex ) == mcMultiSep) )
+ {
+ aText.Erase( nPrevIndex, 1 );
+ nIndex--;
+ }
+ }
+ aText.EraseLeadingAndTrailingChars( ' ' );
+ }
+
+ // Fehlende Eintraege anhaengen...
+ Table aSelInText;
+ lcl_GetSelectedEntries( aSelInText, aText, mcMultiSep, mpImplLB->GetEntryList() );
+ USHORT nSelectedEntries = mpImplLB->GetEntryList()->GetSelectEntryCount();
+ for ( USHORT n = 0; n < nSelectedEntries; n++ )
+ {
+ USHORT nP = mpImplLB->GetEntryList()->GetSelectEntryPos( n );
+ if ( !aSelInText.IsKeyValid( ImplCreateKey( nP ) ) )
+ {
+ if ( aText.Len() && (aText.GetChar( aText.Len()-1 ) != mcMultiSep) )
+ aText += mcMultiSep;
+ if ( aText.Len() )
+ aText += ' '; // etwas auflockern
+ aText += mpImplLB->GetEntryList()->GetEntryText( nP );
+ aText += mcMultiSep;
+ }
+ }
+ if ( aText.Len() && (aText.GetChar( aText.Len()-1 ) == mcMultiSep) )
+ aText.Erase( aText.Len()-1, 1 );
+ }
+ else
+ {
+ aText = mpImplLB->GetEntryList()->GetSelectEntry( 0 );
+ }
+
+ mpSubEdit->SetText( aText );
+
+ Selection aNewSelection( 0, aText.Len() );
+ if ( IsMultiSelectionEnabled() )
+ aNewSelection.Min() = aText.Len();
+ mpSubEdit->SetSelection( aNewSelection );
+
+ bCallSelect = TRUE;
+ }
+
+ // #84652# Call GrabFocus and EndPopupMode before calling Select/Modify, but after changing the text
+
+ if ( bPopup && !mpImplLB->IsTravelSelect() &&
+ ( !IsMultiSelectionEnabled() || !mpImplLB->GetSelectModifier() ) )
+ {
+ mpFloatWin->EndPopupMode();
+ GrabFocus();
+ }
+
+ if ( bCallSelect )
+ {
+ mpSubEdit->SetModifyFlag();
+ mbSyntheticModify = TRUE;
+ Modify();
+ mbSyntheticModify = FALSE;
+ Select();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplCancelHdl, void*, EMPTYARG )
+{
+ if( IsInDropDown() )
+ mpFloatWin->EndPopupMode();
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplSelectionChangedHdl, void*, n )
+{
+ if ( !mpImplLB->IsTrackingSelect() )
+ {
+ USHORT nChanged = (USHORT)(ULONG)n;
+ if ( !mpSubEdit->IsReadOnly() && mpImplLB->GetEntryList()->IsEntryPosSelected( nChanged ) )
+ mpSubEdit->SetText( mpImplLB->GetEntryList()->GetEntryText( nChanged ) );
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplDoubleClickHdl, void*, EMPTYARG )
+{
+ DoubleClick();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::ToggleDropDown()
+{
+ if( IsDropDownBox() )
+ {
+ if( mpFloatWin->IsInPopupMode() )
+ mpFloatWin->EndPopupMode();
+ else
+ {
+ mpSubEdit->GrabFocus();
+ if ( !mpImplLB->GetEntryList()->GetMRUCount() )
+ ImplUpdateFloatSelection();
+ else
+ mpImplLB->SelectEntry( 0 , TRUE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
+ mpBtn->SetPressed( TRUE );
+ SetSelection( Selection( 0, SELECTION_MAX ) );
+ mpFloatWin->StartFloat( TRUE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::Select()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_COMBOBOX_SELECT, maSelectHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::DoubleClick()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_COMBOBOX_DOUBLECLICK, maDoubleClickHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::EnableAutoSize( BOOL bAuto )
+{
+ mbDDAutoSize = bAuto;
+ if ( mpFloatWin )
+ {
+ if ( bAuto && !mpFloatWin->GetDropDownLineCount() )
+ mpFloatWin->SetDropDownLineCount( 5 );
+ else if ( !bAuto )
+ mpFloatWin->SetDropDownLineCount( 0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::EnableDDAutoWidth( BOOL b )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetAutoWidth( b );
+}
+
+ // -----------------------------------------------------------------------
+
+BOOL ComboBox::IsDDAutoWidthEnabled() const
+{
+ return mpFloatWin ? mpFloatWin->IsAutoWidth() : FALSE;
+}
+
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetDropDownLineCount( USHORT nLines )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetDropDownLineCount( nLines );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetDropDownLineCount() const
+{
+ USHORT nLines = 0;
+ if ( mpFloatWin )
+ nLines = mpFloatWin->GetDropDownLineCount();
+ return nLines;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight,
+ USHORT nFlags )
+{
+ if( IsDropDownBox() && ( nFlags & WINDOW_POSSIZE_SIZE ) )
+ {
+ Size aPrefSz = mpFloatWin->GetPrefSize();
+ if ( ( nFlags & WINDOW_POSSIZE_HEIGHT ) && ( nHeight >= 2*mnDDHeight ) )
+ aPrefSz.Height() = nHeight-mnDDHeight;
+ if ( nFlags & WINDOW_POSSIZE_WIDTH )
+ aPrefSz.Width() = nWidth;
+ mpFloatWin->SetPrefSize( aPrefSz );
+
+ if ( IsAutoSizeEnabled() && ! (nFlags & WINDOW_POSSIZE_DROPDOWN) )
+ nHeight = mnDDHeight;
+ }
+
+ Edit::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::Resize()
+{
+ Control::Resize();
+
+ Size aOutSz = GetOutputSizePixel();
+ if( IsDropDownBox() )
+ {
+ long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
+ long nTop = 0;
+ long nBottom = aOutSz.Height();
+
+ Window *pBorder = GetWindow( WINDOW_BORDER );
+ ImplControlValue aControlValue;
+ Point aPoint;
+ Rectangle aContent, aBound;
+
+ // use the full extent of the control
+ Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
+
+ if ( GetNativeControlRegion(CTRL_COMBOBOX, PART_BUTTON_DOWN,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ // convert back from border space to local coordinates
+ aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
+ aContent.Move(-aPoint.X(), -aPoint.Y());
+
+ mpBtn->SetPosSizePixel( aContent.Left(), nTop, aContent.getWidth(), (nBottom-nTop) );
+
+ // adjust the size of the edit field
+ if ( GetNativeControlRegion(CTRL_COMBOBOX, PART_SUB_EDIT,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ // convert back from border space to local coordinates
+ aContent.Move(-aPoint.X(), -aPoint.Y());
+
+ // use the themes drop down size
+ mpSubEdit->SetPosSizePixel( aContent.TopLeft(), aContent.GetSize() );
+ }
+ else
+ {
+ // use the themes drop down size for the button
+ aOutSz.Width() -= aContent.getWidth();
+ mpSubEdit->SetSizePixel( aOutSz );
+ }
+ }
+ else
+ {
+ nSBWidth = CalcZoom( nSBWidth );
+ mpSubEdit->SetPosSizePixel( Point( 0, 0 ), Size( aOutSz.Width() - nSBWidth, aOutSz.Height() ) );
+ mpBtn->SetPosSizePixel( aOutSz.Width() - nSBWidth, nTop, nSBWidth, (nBottom-nTop) );
+ }
+ }
+ else
+ {
+ mpSubEdit->SetSizePixel( Size( aOutSz.Width(), mnDDHeight ) );
+ mpImplLB->SetPosSizePixel( 0, mnDDHeight, aOutSz.Width(), aOutSz.Height() - mnDDHeight );
+ if ( GetText().Len() )
+ ImplUpdateFloatSelection();
+ }
+
+ // FloatingWindow-Groesse auch im unsichtbare Zustand auf Stand halten,
+ // weil KEY_PGUP/DOWN ausgewertet wird...
+ if ( mpFloatWin )
+ mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize() );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ AppendLayoutData( *mpSubEdit );
+ mpSubEdit->SetLayoutDataParent( this );
+ Control* pMainWindow = mpImplLB->GetMainWindow();
+ if( mpFloatWin )
+ {
+ // dropdown mode
+ if( mpFloatWin->IsReallyVisible() )
+ {
+ AppendLayoutData( *pMainWindow );
+ pMainWindow->SetLayoutDataParent( this );
+ }
+ }
+ else
+ {
+ AppendLayoutData( *pMainWindow );
+ pMainWindow->SetLayoutDataParent( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::StateChanged( StateChangedType nType )
+{
+ Edit::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_READONLY )
+ {
+ mpImplLB->SetReadOnly( IsReadOnly() );
+ if ( mpBtn )
+ mpBtn->Enable( IsEnabled() && !IsReadOnly() );
+ }
+ else if ( nType == STATE_CHANGE_ENABLE )
+ {
+ mpSubEdit->Enable( IsEnabled() );
+ mpImplLB->Enable( IsEnabled() && !IsReadOnly() );
+ if ( mpBtn )
+ mpBtn->Enable( IsEnabled() && !IsReadOnly() );
+ Invalidate();
+ }
+ else if( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ mpImplLB->SetUpdateMode( IsUpdateMode() );
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ mpImplLB->SetZoom( GetZoom() );
+ mpSubEdit->SetZoom( GetZoom() );
+ ImplCalcEditHeight();
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ mpImplLB->SetControlFont( GetControlFont() );
+ mpSubEdit->SetControlFont( GetControlFont() );
+ ImplCalcEditHeight();
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ mpImplLB->SetControlForeground( GetControlForeground() );
+ mpSubEdit->SetControlForeground( GetControlForeground() );
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ mpImplLB->SetControlBackground( GetControlBackground() );
+ mpSubEdit->SetControlBackground( GetControlBackground() );
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ mpImplLB->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT ) ? TRUE : FALSE );
+ }
+ else if( nType == STATE_CHANGE_MIRRORING )
+ {
+ if( mpBtn )
+ {
+ mpBtn->EnableRTL( IsRTLEnabled() );
+ ImplInitDropDownButton( mpBtn );
+ }
+ mpSubEdit->StateChanged( STATE_CHANGE_MIRRORING );
+ mpImplLB->EnableRTL( IsRTLEnabled() );
+ Resize();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ if ( mpBtn )
+ {
+ mpBtn->SetSettings( GetSettings() );
+ ImplInitDropDownButton( mpBtn );
+ }
+ Resize();
+ mpImplLB->Resize(); // Wird nicht durch ComboBox::Resize() gerufen, wenn sich die ImplLB nicht aendert.
+ SetBackground(); // due to a hack in Window::UpdateSettings the background must be reset
+ // otherwise it will overpaint NWF drawn comboboxes
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long ComboBox::PreNotify( NotifyEvent& rNEvt )
+{
+
+ return Edit::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long ComboBox::Notify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ if( ( rNEvt.GetType() == EVENT_KEYINPUT ) && ( rNEvt.GetWindow() == mpSubEdit )
+ && !IsReadOnly() )
+ {
+ KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
+ USHORT nKeyCode = aKeyEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN:
+ {
+ ImplUpdateFloatSelection();
+ if( ( nKeyCode == KEY_DOWN ) && mpFloatWin && !mpFloatWin->IsInPopupMode() && aKeyEvt.GetKeyCode().IsMod2() )
+ {
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
+ mpBtn->SetPressed( TRUE );
+ if ( mpImplLB->GetEntryList()->GetMRUCount() )
+ mpImplLB->SelectEntry( 0 , TRUE );
+ SetSelection( Selection( 0, SELECTION_MAX ) );
+ mpFloatWin->StartFloat( FALSE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
+ nDone = 1;
+ }
+ else if( ( nKeyCode == KEY_UP ) && mpFloatWin && mpFloatWin->IsInPopupMode() && aKeyEvt.GetKeyCode().IsMod2() )
+ {
+ mpFloatWin->EndPopupMode();
+ nDone = 1;
+ }
+ else
+ {
+ nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
+ }
+ }
+ break;
+
+ case KEY_RETURN:
+ {
+ if( ( rNEvt.GetWindow() == mpSubEdit ) && IsInDropDown() )
+ {
+ mpImplLB->ProcessKeyInput( aKeyEvt );
+ nDone = 1;
+ }
+ }
+ break;
+ }
+ }
+ else if ( (rNEvt.GetType() == EVENT_LOSEFOCUS) && mpFloatWin )
+ {
+ if( mpFloatWin->HasChildPathFocus() )
+ mpSubEdit->GrabFocus();
+ else if ( mpFloatWin->IsInPopupMode() && !HasChildPathFocus( TRUE ) )
+ mpFloatWin->EndPopupMode();
+ }
+ else if( (rNEvt.GetType() == EVENT_COMMAND) &&
+ (rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL) &&
+ (rNEvt.GetWindow() == mpSubEdit) )
+ {
+ USHORT nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
+ if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
+ || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
+ && HasChildPathFocus()
+ )
+ )
+ {
+ nDone = mpImplLB->HandleWheelAsCursorTravel( *rNEvt.GetCommandEvent() );
+ }
+ else
+ {
+ nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
+ }
+ }
+ else if( ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) && ( rNEvt.GetWindow() == mpImplLB->GetMainWindow() ) )
+ {
+ mpSubEdit->GrabFocus();
+ }
+
+ return nDone ? nDone : Edit::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetText( const XubString& rStr )
+{
+ ImplCallEventListeners( VCLEVENT_COMBOBOX_SETTEXT );
+
+ Edit::SetText( rStr );
+ ImplUpdateFloatSelection();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetText( const XubString& rStr, const Selection& rNewSelection )
+{
+ ImplCallEventListeners( VCLEVENT_COMBOBOX_SETTEXT );
+
+ Edit::SetText( rStr, rNewSelection );
+ ImplUpdateFloatSelection();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::Modify()
+{
+ if ( !mbSyntheticModify )
+ ImplUpdateFloatSelection();
+
+ Edit::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::ImplUpdateFloatSelection()
+{
+ // Text in der ListBox in den sichtbaren Bereich bringen
+ mpImplLB->SetCallSelectionChangedHdl( FALSE );
+ if ( !IsMultiSelectionEnabled() )
+ {
+ XubString aSearchStr( mpSubEdit->GetText() );
+ USHORT nSelect = LISTBOX_ENTRY_NOTFOUND;
+ BOOL bSelect = TRUE;
+
+ if ( mpImplLB->GetCurrentPos() != LISTBOX_ENTRY_NOTFOUND )
+ {
+ XubString aCurrent = mpImplLB->GetEntryList()->GetEntryText( mpImplLB->GetCurrentPos() );
+ if ( aCurrent == aSearchStr )
+ nSelect = mpImplLB->GetCurrentPos();
+ }
+
+ if ( nSelect == LISTBOX_ENTRY_NOTFOUND )
+ nSelect = mpImplLB->GetEntryList()->FindEntry( aSearchStr );
+ if ( nSelect == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpImplLB->GetEntryList()->FindMatchingEntry( aSearchStr );
+ bSelect = FALSE;
+ }
+
+ if( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ {
+ if ( !mpImplLB->IsVisible( nSelect ) )
+ mpImplLB->ShowProminentEntry( nSelect );
+ mpImplLB->SelectEntry( nSelect, bSelect );
+ }
+ else
+ {
+ nSelect = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
+ if( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ mpImplLB->SelectEntry( nSelect, FALSE );
+ mpImplLB->ResetCurrentPos();
+ }
+ }
+ else
+ {
+ Table aSelInText;
+ lcl_GetSelectedEntries( aSelInText, mpSubEdit->GetText(), mcMultiSep, mpImplLB->GetEntryList() );
+ for ( USHORT n = 0; n < mpImplLB->GetEntryList()->GetEntryCount(); n++ )
+ mpImplLB->SelectEntry( n, aSelInText.IsKeyValid( ImplCreateKey( n ) ) );
+ }
+ mpImplLB->SetCallSelectionChangedHdl( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::InsertEntry( const XubString& rStr, USHORT nPos )
+{
+ USHORT nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr );
+ nRealPos = sal::static_int_cast<USHORT>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
+ CallEventListeners( VCLEVENT_COMBOBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
+ return nRealPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::InsertEntry( const XubString& rStr, const Image& rImage, USHORT nPos )
+{
+ USHORT nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr, rImage );
+ nRealPos = sal::static_int_cast<USHORT>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
+ CallEventListeners( VCLEVENT_COMBOBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
+ return nRealPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::RemoveEntry( const XubString& rStr )
+{
+ RemoveEntry( GetEntryPos( rStr ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::RemoveEntry( USHORT nPos )
+{
+ mpImplLB->RemoveEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+ CallEventListeners( VCLEVENT_COMBOBOX_ITEMREMOVED, (void*) sal_IntPtr(nPos) );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::Clear()
+{
+ mpImplLB->Clear();
+ CallEventListeners( VCLEVENT_COMBOBOX_ITEMREMOVED, (void*) sal_IntPtr(-1) );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetEntryPos( const XubString& rStr ) const
+{
+ USHORT nPos = mpImplLB->GetEntryList()->FindEntry( rStr );
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ nPos = sal::static_int_cast<USHORT>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetEntryPos( const void* pData ) const
+{
+ USHORT nPos = mpImplLB->GetEntryList()->FindEntry( pData );
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ nPos = sal::static_int_cast<USHORT>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+XubString ComboBox::GetEntry( USHORT nPos ) const
+{
+ return mpImplLB->GetEntryList()->GetEntryText( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetEntryCount() const
+{
+ return mpImplLB->GetEntryList()->GetEntryCount() - mpImplLB->GetEntryList()->GetMRUCount();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ComboBox::IsTravelSelect() const
+{
+ return mpImplLB->IsTravelSelect();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ComboBox::IsInDropDown() const
+{
+ return mpFloatWin && mpFloatWin->IsInPopupMode();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::EnableMultiSelection( BOOL bMulti )
+{
+ mpImplLB->EnableMultiSelection( bMulti, FALSE );
+ mpImplLB->SetMultiSelectionSimpleMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ComboBox::IsMultiSelectionEnabled() const
+{
+ return mpImplLB->IsMultiSelectionEnabled();
+}
+
+// -----------------------------------------------------------------------
+
+long ComboBox::CalcWindowSizePixel( USHORT nLines ) const
+{
+ return mpImplLB->GetEntryHeight() * nLines;
+}
+
+// -----------------------------------------------------------------------
+
+Size ComboBox::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Edit::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size ComboBox::CalcMinimumSize() const
+{
+ Size aSz;
+ if ( !IsDropDownBox() )
+ {
+ aSz = mpImplLB->CalcSize( mpImplLB->GetEntryList()->GetEntryCount() );
+ aSz.Height() += mnDDHeight;
+ }
+ else
+ {
+ aSz.Height() = mpImplLB->CalcSize( 1 ).Height();
+ aSz.Width() = mpImplLB->GetMaxEntryWidth();
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ }
+
+ aSz = CalcWindowSize( aSz );
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Size ComboBox::CalcAdjustedSize( const Size& rPrefSize ) const
+{
+ Size aSz = rPrefSize;
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom );
+ aSz.Height() -= nTop+nBottom;
+ if ( !IsDropDownBox() )
+ {
+ long nEntryHeight = CalcSize( 1, 1 ).Height();
+ long nLines = aSz.Height() / nEntryHeight;
+ if ( nLines < 1 )
+ nLines = 1;
+ aSz.Height() = nLines * nEntryHeight;
+ aSz.Height() += mnDDHeight;
+ }
+ else
+ {
+ aSz.Height() = mnDDHeight;
+ }
+ aSz.Height() += nTop+nBottom;
+
+ aSz = CalcWindowSize( aSz );
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Size ComboBox::CalcSize( USHORT nColumns, USHORT nLines ) const
+{
+ // ggf. werden ScrollBars eingeblendet
+ Size aMinSz = CalcMinimumSize();
+ Size aSz;
+
+ // Hoehe
+ if ( nLines )
+ {
+ if ( !IsDropDownBox() )
+ aSz.Height() = mpImplLB->CalcSize( nLines ).Height() + mnDDHeight;
+ else
+ aSz.Height() = mnDDHeight;
+ }
+ else
+ aSz.Height() = aMinSz.Height();
+
+ // Breite
+ if ( nColumns )
+ aSz.Width() = nColumns * GetTextWidth( UniString( 'X' ) );
+ else
+ aSz.Width() = aMinSz.Width();
+
+ if ( IsDropDownBox() )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+
+ if ( !IsDropDownBox() )
+ {
+ if ( aSz.Width() < aMinSz.Width() )
+ aSz.Height() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ if ( aSz.Height() < aMinSz.Height() )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ }
+
+ aSz = CalcWindowSize( aSz );
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::GetMaxVisColumnsAndLines( USHORT& rnCols, USHORT& rnLines ) const
+{
+ long nCharWidth = GetTextWidth( UniString( 'x' ) );
+ if ( !IsDropDownBox() )
+ {
+ Size aOutSz = mpImplLB->GetMainWindow()->GetOutputSizePixel();
+ rnCols = (USHORT)(aOutSz.Width()/nCharWidth);
+ rnLines = (USHORT)(aOutSz.Height()/mpImplLB->GetEntryHeight());
+ }
+ else
+ {
+ Size aOutSz = mpSubEdit->GetOutputSizePixel();
+ rnCols = (USHORT)(aOutSz.Width()/nCharWidth);
+ rnLines = 1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ mpImplLB->GetMainWindow()->ImplInitSettings( TRUE, TRUE, TRUE );
+
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Font aFont = mpImplLB->GetMainWindow()->GetDrawPixelFont( pDev );
+ OutDevType eOutDevType = pDev->GetOutDevType();
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ pDev->SetTextFillColor();
+
+ // Border/Background
+ pDev->SetLineColor();
+ pDev->SetFillColor();
+ BOOL bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
+ BOOL bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
+ if ( bBorder || bBackground )
+ {
+ Rectangle aRect( aPos, aSize );
+ // aRect.Top() += nEditHeight;
+ if ( bBorder )
+ {
+ ImplDrawFrame( pDev, aRect );
+ }
+ if ( bBackground )
+ {
+ pDev->SetFillColor( GetControlBackground() );
+ pDev->DrawRect( aRect );
+ }
+ }
+
+ // Inhalt
+ if ( !IsDropDownBox() )
+ {
+ long nOnePixel = GetDrawPixel( pDev, 1 );
+ long nTextHeight = pDev->GetTextHeight();
+ long nEditHeight = nTextHeight + 6*nOnePixel;
+ USHORT nTextStyle = TEXT_DRAW_VCENTER;
+
+ // First, draw the edit part
+ mpSubEdit->Draw( pDev, aPos, Size( aSize.Width(), nEditHeight ), nFlags );
+
+ // Second, draw the listbox
+ if ( GetStyle() & WB_CENTER )
+ nTextStyle |= TEXT_DRAW_CENTER;
+ else if ( GetStyle() & WB_RIGHT )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else
+ nTextStyle |= TEXT_DRAW_LEFT;
+
+ if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
+ {
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ }
+ else
+ {
+ if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ pDev->SetTextColor( rStyleSettings.GetDisableColor() );
+ }
+ else
+ {
+ pDev->SetTextColor( GetTextColor() );
+ }
+ }
+
+ Rectangle aClip( aPos, aSize );
+ pDev->IntersectClipRegion( aClip );
+ USHORT nLines = (USHORT) ( (aSize.Height()-nEditHeight) / nTextHeight );
+ if ( !nLines )
+ nLines = 1;
+ USHORT nTEntry = IsReallyVisible() ? mpImplLB->GetTopEntry() : 0;
+
+ Rectangle aTextRect( aPos, aSize );
+
+ aTextRect.Left() += 3*nOnePixel;
+ aTextRect.Right() -= 3*nOnePixel;
+ aTextRect.Top() += nEditHeight + nOnePixel;
+ aTextRect.Bottom() = aTextRect.Top() + nTextHeight;
+
+ // the drawing starts here
+ for ( USHORT n = 0; n < nLines; n++ )
+ {
+ pDev->DrawText( aTextRect, mpImplLB->GetEntryList()->GetEntryText( n+nTEntry ), nTextStyle );
+ aTextRect.Top() += nTextHeight;
+ aTextRect.Bottom() += nTextHeight;
+ }
+ }
+
+ pDev->Pop();
+
+ // Call Edit::Draw after restoring the MapMode...
+ if ( IsDropDownBox() )
+ {
+ mpSubEdit->Draw( pDev, rPos, rSize, nFlags );
+ // DD-Button ?
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ComboBox, ImplUserDrawHdl, UserDrawEvent*, pEvent )
+{
+ UserDraw( *pEvent );
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::UserDraw( const UserDrawEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetUserItemSize( const Size& rSz )
+{
+ mpImplLB->GetMainWindow()->SetUserItemSize( rSz );
+}
+
+// -----------------------------------------------------------------------
+
+const Size& ComboBox::GetUserItemSize() const
+{
+ return mpImplLB->GetMainWindow()->GetUserItemSize();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::EnableUserDraw( BOOL bUserDraw )
+{
+ mpImplLB->GetMainWindow()->EnableUserDraw( bUserDraw );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ComboBox::IsUserDrawEnabled() const
+{
+ return mpImplLB->GetMainWindow()->IsUserDrawEnabled();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::DrawEntry( const UserDrawEvent& rEvt, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos )
+{
+ DBG_ASSERT( rEvt.GetDevice() == mpImplLB->GetMainWindow(), "DrawEntry?!" );
+ mpImplLB->GetMainWindow()->DrawEntry( rEvt.GetItemId(), bDrawImage, bDrawText, bDrawTextAtImagePos );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetSeparatorPos( USHORT n )
+{
+ mpImplLB->SetSeparatorPos( n );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetSeparatorPos()
+{
+ mpImplLB->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetSeparatorPos() const
+{
+ return mpImplLB->GetSeparatorPos();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
+{
+ mpImplLB->SetMRUEntries( rEntries, cSep );
+}
+
+// -----------------------------------------------------------------------
+
+XubString ComboBox::GetMRUEntries( xub_Unicode cSep ) const
+{
+ return mpImplLB->GetMRUEntries( cSep );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetMaxMRUCount( USHORT n )
+{
+ mpImplLB->SetMaxMRUCount( n );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetMaxMRUCount() const
+{
+ return mpImplLB->GetMaxMRUCount();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetDisplayLineCount() const
+{
+ return mpImplLB->GetDisplayLineCount();
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetEntryData( USHORT nPos, void* pNewData )
+{
+ mpImplLB->SetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount(), pNewData );
+}
+
+// -----------------------------------------------------------------------
+
+void* ComboBox::GetEntryData( USHORT nPos ) const
+{
+ return mpImplLB->GetEntryList()->GetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetTopEntry( USHORT nPos )
+{
+ mpImplLB->SetTopEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::ShowProminentEntry( USHORT nPos )
+{
+ mpImplLB->ShowProminentEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ComboBox::GetTopEntry() const
+{
+ USHORT nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND;
+ if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
+ nPos = 0;
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ComboBox::SetProminentEntryType( ProminentEntry eType )
+{
+ mpImplLB->SetProminentEntryType( eType );
+}
+
+// -----------------------------------------------------------------------
+
+ProminentEntry ComboBox::GetProminentEntryType() const
+{
+ return mpImplLB->GetProminentEntryType();
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ComboBox::GetDropDownPosSizePixel() const
+{
+ return mpFloatWin ? mpFloatWin->GetWindowExtentsRelative( const_cast<ComboBox*>(this) ) : Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ComboBox::GetListPosSizePixel() const
+{
+ return mpFloatWin ? Rectangle() : mpImplLB->GetMainWindow()->GetWindowExtentsRelative( const_cast<ComboBox*>(this) );
+}
+
+// -----------------------------------------------------------------------
+
+const Wallpaper& ComboBox::GetDisplayBackground() const
+{
+ if( ! mpSubEdit->IsBackground() )
+ return Control::GetDisplayBackground();
+
+ const Wallpaper& rBack = mpSubEdit->GetBackground();
+ if( ! rBack.IsBitmap() &&
+ ! rBack.IsGradient() &&
+ rBack.GetColor().GetColor() == COL_TRANSPARENT
+ )
+ return Control::GetDisplayBackground();
+ return rBack;
+}
+// -----------------------------------------------------------------------------
+USHORT ComboBox::GetSelectEntryCount() const
+{
+ return mpImplLB->GetEntryList()->GetSelectEntryCount();
+}
+// -----------------------------------------------------------------------------
+USHORT ComboBox::GetSelectEntryPos( USHORT nIndex ) const
+{
+ USHORT nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( nIndex );
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
+ nPos = mpImplLB->GetEntryList()->FindEntry( mpImplLB->GetEntryList()->GetEntryText( nPos ) );
+ nPos = sal::static_int_cast<USHORT>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
+ }
+ return nPos;
+}
+// -----------------------------------------------------------------------------
+BOOL ComboBox::IsEntryPosSelected( USHORT nPos ) const
+{
+ return mpImplLB->GetEntryList()->IsEntryPosSelected( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+// -----------------------------------------------------------------------------
+void ComboBox::SelectEntryPos( USHORT nPos, BOOL bSelect)
+{
+ if ( nPos < mpImplLB->GetEntryList()->GetEntryCount() )
+ mpImplLB->SelectEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), bSelect );
+}
+// -----------------------------------------------------------------------------
+void ComboBox::SetNoSelection()
+{
+ mpImplLB->SetNoSelection();
+ mpSubEdit->SetText( String() );
+}
+// -----------------------------------------------------------------------------
+Rectangle ComboBox::GetBoundingRectangle( USHORT nItem ) const
+{
+ Rectangle aRect = mpImplLB->GetMainWindow()->GetBoundingRectangle( nItem );
+ Rectangle aOffset = mpImplLB->GetMainWindow()->GetWindowExtentsRelative( (Window*)this );
+ aRect.Move( aOffset.TopLeft().X(), aOffset.TopLeft().Y() );
+ return aRect;
+}
+// -----------------------------------------------------------------------------
+
+void ComboBox::SetBorderStyle( USHORT nBorderStyle )
+{
+ Window::SetBorderStyle( nBorderStyle );
+ if ( !IsDropDownBox() )
+ {
+ mpSubEdit->SetBorderStyle( nBorderStyle );
+ mpImplLB->SetBorderStyle( nBorderStyle );
+ }
+}
+// -----------------------------------------------------------------------------
+
+long ComboBox::GetIndexForPoint( const Point& rPoint, USHORT& rPos ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+
+ // check whether rPoint fits at all
+ long nIndex = Control::GetIndexForPoint( rPoint );
+ if( nIndex != -1 )
+ {
+ // point must be either in main list window
+ // or in impl window (dropdown case)
+ ImplListBoxWindow* pMain = mpImplLB->GetMainWindow();
+
+ // convert coordinates to ImplListBoxWindow pixel coordinate space
+ Point aConvPoint = LogicToPixel( rPoint );
+ aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
+ aConvPoint = pMain->AbsoluteScreenToOutputPixel( aConvPoint );
+ aConvPoint = pMain->PixelToLogic( aConvPoint );
+
+ // try to find entry
+ USHORT nEntry = pMain->GetEntryPosForPoint( aConvPoint );
+ if( nEntry == LISTBOX_ENTRY_NOTFOUND )
+ nIndex = -1;
+ else
+ rPos = nEntry;
+ }
+
+ // get line relative index
+ if( nIndex != -1 )
+ nIndex = ToRelativeLineIndex( nIndex );
+
+ return nIndex;
+}
diff --git a/vcl/source/control/ctrl.cxx b/vcl/source/control/ctrl.cxx
new file mode 100644
index 000000000000..918675cc0783
--- /dev/null
+++ b/vcl/source/control/ctrl.cxx
@@ -0,0 +1,587 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ctrl.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/controldata.hxx>
+#include <vcl/salnativewidgets.hxx>
+#include <vcl/textlayout.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace vcl;
+
+// =======================================================================
+
+void Control::ImplInitControlData()
+{
+ mbHasFocus = FALSE;
+ mpControlData = new ImplControlData;
+}
+
+// -----------------------------------------------------------------------
+
+Control::Control( WindowType nType ) :
+ Window( nType )
+{
+ ImplInitControlData();
+}
+
+// -----------------------------------------------------------------------
+
+Control::Control( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_CONTROL )
+{
+ ImplInitControlData();
+ Window::ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Control::Control( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_CONTROL )
+{
+ ImplInitControlData();
+ rResId.SetRT( RSC_CONTROL );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle, NULL );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+Control::~Control()
+{
+ delete mpControlData, mpControlData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Control::GetFocus()
+{
+ Window::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void Control::LoseFocus()
+{
+ Window::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void Control::Resize()
+{
+ ImplClearLayoutData();
+ Window::Resize();
+}
+
+// -----------------------------------------------------------------------
+
+void Control::FillLayoutData() const
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Control::CreateLayoutData() const
+{
+ DBG_ASSERT( !mpControlData->mpLayoutData, "Control::CreateLayoutData: should be called with non-existent layout data only!" );
+ mpControlData->mpLayoutData = new ::vcl::ControlLayoutData();
+}
+
+// -----------------------------------------------------------------------
+
+bool Control::HasLayoutData() const
+{
+ return mpControlData->mpLayoutData != NULL;
+}
+
+// -----------------------------------------------------------------------
+
+::vcl::ControlLayoutData* Control::GetLayoutData() const
+{
+ return mpControlData->mpLayoutData;
+}
+
+// -----------------------------------------------------------------------
+
+void Control::SetText( const String& rStr )
+{
+ ImplClearLayoutData();
+ Window::SetText( rStr );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ControlLayoutData::GetCharacterBounds( long nIndex ) const
+{
+ return (nIndex >= 0 && nIndex < (long) m_aUnicodeBoundRects.size()) ? m_aUnicodeBoundRects[ nIndex ] : Rectangle();
+}
+
+
+// -----------------------------------------------------------------------
+
+Rectangle Control::GetCharacterBounds( long nIndex ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetCharacterBounds( nIndex ) : Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+long ControlLayoutData::GetIndexForPoint( const Point& rPoint ) const
+{
+ long nIndex = -1;
+ for( long i = m_aUnicodeBoundRects.size()-1; i >= 0; i-- )
+ {
+ if( m_aUnicodeBoundRects[ i ].IsInside( rPoint ) )
+ {
+ nIndex = i;
+ break;
+ }
+ }
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+long Control::GetIndexForPoint( const Point& rPoint ) const
+{
+ if( ! HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetIndexForPoint( rPoint ) : -1;
+}
+
+// -----------------------------------------------------------------------
+
+long ControlLayoutData::GetLineCount() const
+{
+ long nLines = m_aLineIndices.size();
+ if( nLines == 0 && m_aDisplayText.Len() )
+ nLines = 1;
+ return nLines;
+}
+
+// -----------------------------------------------------------------------
+
+long Control::GetLineCount() const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineCount() : 0;
+}
+
+// -----------------------------------------------------------------------
+
+Pair ControlLayoutData::GetLineStartEnd( long nLine ) const
+{
+ Pair aPair( -1, -1 );
+
+ int nDisplayLines = m_aLineIndices.size();
+ if( nLine >= 0 && nLine < nDisplayLines )
+ {
+ aPair.A() = m_aLineIndices[nLine];
+ if( nLine+1 < nDisplayLines )
+ aPair.B() = m_aLineIndices[nLine+1]-1;
+ else
+ aPair.B() = m_aDisplayText.Len()-1;
+ }
+ else if( nLine == 0 && nDisplayLines == 0 && m_aDisplayText.Len() )
+ {
+ // special case for single line controls so the implementations
+ // in that case do not have to fill in the line indices
+ aPair.A() = 0;
+ aPair.B() = m_aDisplayText.Len()-1;
+ }
+ return aPair;
+}
+
+// -----------------------------------------------------------------------
+
+Pair Control::GetLineStartEnd( long nLine ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
+}
+
+// -----------------------------------------------------------------------
+
+long ControlLayoutData::ToRelativeLineIndex( long nIndex ) const
+{
+ // is the index sensible at all ?
+ if( nIndex >= 0 && nIndex < m_aDisplayText.Len() )
+ {
+ int nDisplayLines = m_aLineIndices.size();
+ // if only 1 line exists, then absolute and relative index are
+ // identical -> do nothing
+ if( nDisplayLines > 1 )
+ {
+ int nLine;
+ for( nLine = nDisplayLines-1; nLine >= 0; nLine-- )
+ {
+ if( m_aLineIndices[nLine] <= nIndex )
+ {
+ nIndex -= m_aLineIndices[nLine];
+ break;
+ }
+ }
+ if( nLine < 0 )
+ {
+ DBG_ASSERT( nLine >= 0, "ToRelativeLineIndex failed" );
+ nIndex = -1;
+ }
+ }
+ }
+ else
+ nIndex = -1;
+
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+long Control::ToRelativeLineIndex( long nIndex ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->ToRelativeLineIndex( nIndex ) : -1;
+}
+
+// -----------------------------------------------------------------------
+
+String Control::GetDisplayText() const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->m_aDisplayText : GetText();
+}
+
+// -----------------------------------------------------------------------
+
+long Control::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ {
+ if ( !mbHasFocus )
+ {
+ mbHasFocus = TRUE;
+ if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_GETFOCUS, maGetFocusHdl, this ) )
+ // been destroyed within the handler
+ return TRUE;
+ }
+ }
+ else
+ {
+ if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ Window* pFocusWin = Application::GetFocusWindow();
+ if ( !pFocusWin || !ImplIsWindowOrChild( pFocusWin ) )
+ {
+ mbHasFocus = FALSE;
+ if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_LOSEFOCUS, maLoseFocusHdl, this ) )
+ // been destroyed within the handler
+ return TRUE;
+ }
+ }
+ }
+
+ return Window::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Control::StateChanged( StateChangedType nStateChange )
+{
+ if( nStateChange == STATE_CHANGE_INITSHOW ||
+ nStateChange == STATE_CHANGE_VISIBLE ||
+ nStateChange == STATE_CHANGE_FORMAT ||
+ nStateChange == STATE_CHANGE_ZOOM ||
+ nStateChange == STATE_CHANGE_BORDER ||
+ nStateChange == STATE_CHANGE_CONTROLFONT
+ )
+ {
+ ImplClearLayoutData();
+ }
+ Window::StateChanged( nStateChange );
+}
+
+// -----------------------------------------------------------------------
+
+void Control::AppendLayoutData( const Control& rSubControl ) const
+{
+ if( !rSubControl.HasLayoutData() )
+ rSubControl.FillLayoutData();
+ if( !rSubControl.HasLayoutData() || !rSubControl.mpControlData->mpLayoutData->m_aDisplayText.Len() )
+ return;
+
+ long nCurrentIndex = mpControlData->mpLayoutData->m_aDisplayText.Len();
+ mpControlData->mpLayoutData->m_aDisplayText.Append( rSubControl.mpControlData->mpLayoutData->m_aDisplayText );
+ int nLines = rSubControl.mpControlData->mpLayoutData->m_aLineIndices.size();
+ int n;
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( nCurrentIndex );
+ for( n = 1; n < nLines; n++ )
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( rSubControl.mpControlData->mpLayoutData->m_aLineIndices[n] + nCurrentIndex );
+ int nRectangles = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects.size();
+ Rectangle aRel = const_cast<Control&>(rSubControl).GetWindowExtentsRelative( const_cast<Control*>(this) );
+ for( n = 0; n < nRectangles; n++ )
+ {
+ Rectangle aRect = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects[n];
+ aRect.Move( aRel.Left(), aRel.Top() );
+ mpControlData->mpLayoutData->m_aUnicodeBoundRects.push_back( aRect );
+ }
+}
+
+// -----------------------------------------------------------------
+
+BOOL Control::ImplCallEventListenersAndHandler( ULONG nEvent, const Link& rHandler, void* pCaller )
+{
+ ImplDelData aCheckDelete;
+ ImplAddDel( &aCheckDelete );
+
+ ImplCallEventListeners( nEvent );
+ if ( !aCheckDelete.IsDelete() )
+ {
+ rHandler.Call( pCaller );
+
+ if ( !aCheckDelete.IsDelete() )
+ {
+ ImplRemoveDel( &aCheckDelete );
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+// -----------------------------------------------------------------
+
+void Control::SetLayoutDataParent( const Control* pParent ) const
+{
+ if( HasLayoutData() )
+ mpControlData->mpLayoutData->m_pParent = pParent;
+}
+
+// -----------------------------------------------------------------
+
+void Control::ImplClearLayoutData() const
+{
+ delete mpControlData->mpLayoutData, mpControlData->mpLayoutData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Control::ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect )
+{
+ // use a deco view to draw the frame
+ // However, since there happens a lot of magic there, we need to fake some (style) settings
+ // on the device
+ AllSettings aOriginalSettings( pDev->GetSettings() );
+
+ AllSettings aNewSettings( aOriginalSettings );
+ StyleSettings aStyle( aNewSettings.GetStyleSettings() );
+
+ // The *only known* clients of the Draw methods of the various VCL-controls are form controls:
+ // During print preview, and during printing, Draw is called. Thus, drawing always happens with a
+ // mono (colored) border
+ aStyle.SetOptions( aStyle.GetOptions() | STYLE_OPTION_MONO );
+ aStyle.SetMonoColor( GetSettings().GetStyleSettings().GetMonoColor() );
+
+ aNewSettings.SetStyleSettings( aStyle );
+ // #i67023# do not call data changed listeners for this fake
+ // since they may understandably invalidate on settings changed
+ pDev->OutputDevice::SetSettings( aNewSettings );
+
+ DecorationView aDecoView( pDev );
+ rRect = aDecoView.DrawFrame( rRect, FRAME_DRAW_WINDOWBORDER );
+
+ pDev->OutputDevice::SetSettings( aOriginalSettings );
+}
+
+// -----------------------------------------------------------------------
+
+void Control::DataChanged( const DataChangedEvent& rDCEvt)
+{
+ // we don't want to loose some style settings for controls created with the
+ // toolkit
+ if ( IsCreatedWithToolkit() &&
+ (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ AllSettings aSettings = GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ ULONG nOldOptions = rDCEvt.GetOldSettings()->GetStyleSettings().GetOptions();
+ ULONG nNewOptions = aStyleSettings.GetOptions();
+
+ if ( !(nNewOptions & STYLE_OPTION_MONO) && ( nOldOptions & STYLE_OPTION_MONO ) )
+ {
+ nNewOptions |= STYLE_OPTION_MONO;
+ aStyleSettings.SetOptions( nNewOptions );
+ aStyleSettings.SetMonoColor( rDCEvt.GetOldSettings()->GetStyleSettings().GetMonoColor() );
+ aSettings.SetStyleSettings( aStyleSettings );
+ SetSettings( aSettings );
+ }
+ }
+}
+
+// -----------------------------------------------------------------
+
+ControlLayoutData::~ControlLayoutData()
+{
+ if( m_pParent )
+ m_pParent->ImplClearLayoutData();
+}
+
+// -----------------------------------------------------------------
+
+Size Control::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return Size( GetTextWidth( GetText() ) + 2 * 12,
+ GetTextHeight() + 2 * 6 );
+ case WINDOWSIZE_PREFERRED:
+ return GetOptimalSize( WINDOWSIZE_MINIMUM );
+ case WINDOWSIZE_MAXIMUM:
+ default:
+ return Size( LONG_MAX, LONG_MAX );
+ }
+}
+
+// -----------------------------------------------------------------
+
+void Control::SetReferenceDevice( OutputDevice* _referenceDevice )
+{
+ if ( mpControlData->mpReferenceDevice == _referenceDevice )
+ return;
+
+ mpControlData->mpReferenceDevice = _referenceDevice;
+ Invalidate();
+}
+
+// -----------------------------------------------------------------
+
+OutputDevice* Control::GetReferenceDevice() const
+{
+ return mpControlData->mpReferenceDevice;
+}
+
+// -----------------------------------------------------------------
+
+const Font& Control::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetLabelFont();
+}
+
+// -----------------------------------------------------------------
+const Color& Control::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetLabelTextColor();
+}
+
+// -----------------------------------------------------------------
+void Control::ImplInitSettings( const BOOL _bFont, const BOOL _bForeground )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if ( _bFont )
+ {
+ Font aFont( GetCanonicalFont( rStyleSettings ) );
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ SetZoomedPointFont( aFont );
+ }
+
+ if ( _bForeground || _bFont )
+ {
+ Color aColor;
+ if ( IsControlForeground() )
+ aColor = GetControlForeground();
+ else
+ aColor = GetCanonicalTextColor( rStyleSettings );
+ SetTextColor( aColor );
+ SetTextFillColor();
+ }
+}
+
+// -----------------------------------------------------------------
+
+void Control::DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect, const XubString& _rStr,
+ USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText ) const
+{
+#ifdef FS_DEBUG
+ if ( !_pVector )
+ {
+ static MetricVector aCharRects;
+ static String sDisplayText;
+ aCharRects.clear();
+ sDisplayText = String();
+ _pVector = &aCharRects;
+ _pDisplayText = &sDisplayText;
+ }
+#endif
+
+ if ( !mpControlData->mpReferenceDevice || ( mpControlData->mpReferenceDevice == &_rTargetDevice ) )
+ {
+ _io_rRect = _rTargetDevice.GetTextRect( _io_rRect, _rStr, _nStyle );
+ _rTargetDevice.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
+ }
+ else
+ {
+ ControlTextRenderer aRenderer( *this, _rTargetDevice, *mpControlData->mpReferenceDevice );
+ _io_rRect = aRenderer.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
+ }
+
+#ifdef FS_DEBUG
+ _rTargetDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ _rTargetDevice.SetLineColor( COL_LIGHTRED );
+ _rTargetDevice.SetFillColor();
+ for ( MetricVector::const_iterator cr = _pVector->begin();
+ cr != _pVector->end();
+ ++cr
+ )
+ {
+ _rTargetDevice.DrawRect( *cr );
+ }
+ _rTargetDevice.Pop();
+#endif
+}
diff --git a/vcl/source/control/edit.cxx b/vcl/source/control/edit.cxx
new file mode 100644
index 000000000000..c0e7b352642c
--- /dev/null
+++ b/vcl/source/control/edit.cxx
@@ -0,0 +1,3140 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/event.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/virdev.hxx>
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+#include <vcl/menu.hxx>
+#include <vcl/cmdevt.h>
+#include <vcl/subedit.hxx>
+#include <vcl/edit.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/controldata.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/window.h>
+
+#include <vos/mutex.hxx>
+
+
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <cppuhelper/weak.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANS_HPP_
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#endif
+#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+
+#ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_
+#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
+#endif
+#include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+#include <com/sun/star/uno/Any.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/configurationhelper.hxx>
+
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <rtl/memory.h>
+
+#include <vcl/unohelp.hxx>
+#include <vcl/unohelp2.hxx>
+
+
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::rtl;
+
+// - Redo
+// - Bei Tracking-Cancel DefaultSelection wieder herstellen
+
+// =======================================================================
+
+static FncGetSpecialChars pImplFncGetSpecialChars = NULL;
+
+// =======================================================================
+
+#define EDIT_ALIGN_LEFT 1
+#define EDIT_ALIGN_CENTER 2
+#define EDIT_ALIGN_RIGHT 3
+
+#define EDIT_DEL_LEFT 1
+#define EDIT_DEL_RIGHT 2
+
+#define EDIT_DELMODE_SIMPLE 11
+#define EDIT_DELMODE_RESTOFWORD 12
+#define EDIT_DELMODE_RESTOFCONTENT 13
+
+// =======================================================================
+
+struct DDInfo
+{
+ Cursor aCursor;
+ Selection aDndStartSel;
+ xub_StrLen nDropPos;
+ BOOL bStarterOfDD;
+ BOOL bDroppedInMe;
+ BOOL bVisCursor;
+
+ DDInfo()
+ {
+ aCursor.SetStyle( CURSOR_SHADOW );
+ nDropPos = 0;
+ bStarterOfDD = FALSE;
+ bDroppedInMe = FALSE;
+ bVisCursor = FALSE;
+ }
+};
+
+// =======================================================================
+
+struct Impl_IMEInfos
+{
+ String aOldTextAfterStartPos;
+ USHORT* pAttribs;
+ xub_StrLen nPos;
+ xub_StrLen nLen;
+ BOOL bCursor;
+ BOOL bWasCursorOverwrite;
+
+ Impl_IMEInfos( xub_StrLen nPos, const String& rOldTextAfterStartPos );
+ ~Impl_IMEInfos();
+
+ void CopyAttribs( const xub_StrLen* pA, xub_StrLen nL );
+ void DestroyAttribs();
+};
+
+// -----------------------------------------------------------------------
+
+Impl_IMEInfos::Impl_IMEInfos( xub_StrLen nP, const String& rOldTextAfterStartPos )
+ : aOldTextAfterStartPos( rOldTextAfterStartPos )
+{
+ nPos = nP;
+ nLen = 0;
+ bCursor = TRUE;
+ pAttribs = NULL;
+ bWasCursorOverwrite = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Impl_IMEInfos::~Impl_IMEInfos()
+{
+ delete[] pAttribs;
+}
+
+// -----------------------------------------------------------------------
+
+void Impl_IMEInfos::CopyAttribs( const xub_StrLen* pA, xub_StrLen nL )
+{
+ nLen = nL;
+ delete[] pAttribs;
+ pAttribs = new USHORT[ nL ];
+ rtl_copyMemory( pAttribs, pA, nL*sizeof(USHORT) );
+}
+
+// -----------------------------------------------------------------------
+
+void Impl_IMEInfos::DestroyAttribs()
+{
+ delete[] pAttribs;
+ pAttribs = NULL;
+ nLen = 0;
+}
+
+// =======================================================================
+
+Edit::Edit( WindowType nType ) :
+ Control( nType )
+{
+ ImplInitEditData();
+}
+
+// -----------------------------------------------------------------------
+
+Edit::Edit( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_EDIT )
+{
+ ImplInitEditData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+Edit::Edit( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_EDIT )
+{
+ ImplInitEditData();
+ rResId.SetRT( RSC_EDIT );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ // Derived MultiLineEdit takes care to call Show only after MultiLineEdit
+ // ctor has already started:
+ if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+Edit::Edit( Window* pParent, const ResId& rResId, bool bDisableAccessibleLabeledByRelation ) :
+ Control( WINDOW_EDIT )
+{
+ ImplInitEditData();
+ rResId.SetRT( RSC_EDIT );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+ if ( bDisableAccessibleLabeledByRelation )
+ ImplGetWindowImpl()->mbDisableAccessibleLabeledByRelation = TRUE;
+
+ // Derived MultiLineEdit takes care to call Show only after MultiLineEdit
+ // ctor has already started:
+ if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+Edit::~Edit()
+{
+ delete mpDDInfo;
+ Cursor* pCursor = GetCursor();
+ if ( pCursor )
+ {
+ SetCursor( NULL );
+ delete pCursor;
+ }
+
+ delete mpIMEInfos;
+
+ if ( mpUpdateDataTimer )
+ delete mpUpdateDataTimer;
+
+ if ( mxDnDListener.is() )
+ {
+ if ( GetDragGestureRecognizer().is() )
+ {
+ uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
+ GetDragGestureRecognizer()->removeDragGestureListener( xDGL );
+ }
+ if ( GetDropTarget().is() )
+ {
+ uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
+ GetDropTarget()->removeDropTargetListener( xDTL );
+ }
+
+ uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY );
+ xEL->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplInitEditData()
+{
+ mpSubEdit = NULL;
+ mpUpdateDataTimer = NULL;
+ mnXOffset = 0;
+ mnAlign = EDIT_ALIGN_LEFT;
+ mnMaxTextLen = EDIT_NOLIMIT;
+ meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
+ mbModified = FALSE;
+ mbInternModified = FALSE;
+ mbReadOnly = FALSE;
+ mbInsertMode = TRUE;
+ mbClickedInSelection = FALSE;
+ mbActivePopup = FALSE;
+ mbIsSubEdit = FALSE;
+ mbInMBDown = FALSE;
+ mpDDInfo = NULL;
+ mpIMEInfos = NULL;
+ mcEchoChar = 0;
+
+ // --- RTL --- no default mirroring for Edit controls
+ // note: controls that use a subedit will revert this (SpinField, ComboBox)
+ EnableRTL( FALSE );
+
+ vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
+ mxDnDListener = pDnDWrapper;
+}
+
+// -----------------------------------------------------------------------
+
+bool Edit::ImplUseNativeBorder( WinBits nStyle )
+{
+ bool bRet =
+ IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
+ && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
+ if( ! bRet && mbIsSubEdit )
+ {
+ Window* pWindow = GetParent();
+ nStyle = pWindow->GetStyle();
+ bRet = pWindow->IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
+ && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
+ }
+ return bRet;
+}
+
+void Edit::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( nStyle );
+ if ( !(nStyle & (WB_CENTER | WB_RIGHT)) )
+ nStyle |= WB_LEFT;
+
+ Control::ImplInit( pParent, nStyle, NULL );
+
+ mbReadOnly = (nStyle & WB_READONLY) != 0;
+
+ mnAlign = EDIT_ALIGN_LEFT;
+
+ // --- RTL --- hack: right align until keyinput and cursor travelling works
+ if( IsRTLEnabled() )
+ mnAlign = EDIT_ALIGN_RIGHT;
+
+ if ( nStyle & WB_RIGHT )
+ mnAlign = EDIT_ALIGN_RIGHT;
+ else if ( nStyle & WB_CENTER )
+ mnAlign = EDIT_ALIGN_CENTER;
+
+ SetCursor( new Cursor );
+
+ SetPointer( Pointer( POINTER_TEXT ) );
+ ImplInitSettings( TRUE, TRUE, TRUE );
+
+ uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
+ uno::Reference< datatransfer::dnd::XDragGestureRecognizer > xDGR = GetDragGestureRecognizer();
+ if ( xDGR.is() )
+ {
+ xDGR->addDragGestureListener( xDGL );
+ uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
+ GetDropTarget()->addDropTargetListener( xDTL );
+ GetDropTarget()->setActive( sal_True );
+ GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+WinBits Edit::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Edit::IsCharInput( const KeyEvent& rKeyEvent )
+{
+ // In the future we must use new Unicode functions for this
+ xub_Unicode cCharCode = rKeyEvent.GetCharCode();
+ return ((cCharCode >= 32) && (cCharCode != 127) &&
+ !rKeyEvent.GetKeyCode().IsMod3() &&
+ !rKeyEvent.GetKeyCode().IsMod2() &&
+ !rKeyEvent.GetKeyCode().IsMod1() );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplModified()
+{
+ mbModified = TRUE;
+ Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if ( bFont )
+ {
+ Font aFont = rStyleSettings.GetFieldFont();
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ SetZoomedPointFont( aFont );
+ ImplClearLayoutData();
+ }
+
+ if ( bFont || bForeground )
+ {
+ Color aTextColor = rStyleSettings.GetFieldTextColor();
+ if ( IsControlForeground() )
+ aTextColor = GetControlForeground();
+ SetTextColor( aTextColor );
+ }
+
+ if ( bBackground )
+ {
+ if ( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
+ {
+ // Transparent background
+ SetBackground();
+ SetFillColor();
+ }
+ else if ( IsControlBackground() )
+ {
+ SetBackground( GetControlBackground() );
+ SetFillColor( GetControlBackground() );
+ }
+ else
+ {
+ SetBackground( rStyleSettings.GetFieldColor() );
+ SetFillColor( rStyleSettings.GetFieldColor() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long Edit::ImplGetExtraOffset() const
+{
+ // MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
+ // but I need an incompatible update for this...
+ // #94095# Use extra offset only when edit has a border
+ long nExtraOffset = 0;
+ if( ( GetStyle() & WB_BORDER ) || ( mbIsSubEdit && ( GetParent()->GetStyle() & WB_BORDER ) ) )
+ nExtraOffset = 2;
+
+ return nExtraOffset;
+}
+
+
+// -----------------------------------------------------------------------
+
+XubString Edit::ImplGetText() const
+{
+ if ( mcEchoChar || (GetStyle() & WB_PASSWORD) )
+ {
+ XubString aText;
+ xub_Unicode cEchoChar;
+ if ( mcEchoChar )
+ cEchoChar = mcEchoChar;
+ else
+ cEchoChar = '*';
+ aText.Fill( maText.Len(), cEchoChar );
+ return aText;
+ }
+ else
+ return maText;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplInvalidateOrRepaint( xub_StrLen nStart, xub_StrLen nEnd )
+{
+ if( IsPaintTransparent() )
+ {
+ Invalidate();
+ // FIXME: this is currently only on aqua
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects )
+ Update();
+ }
+ else
+ ImplRepaint( nStart, nEnd );
+}
+
+// -----------------------------------------------------------------------
+
+long Edit::ImplGetTextYPosition() const
+{
+ if ( GetStyle() & WB_TOP )
+ return ImplGetExtraOffset();
+ else if ( GetStyle() & WB_BOTTOM )
+ return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraOffset();
+ return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplRepaint( xub_StrLen nStart, xub_StrLen nEnd, bool bLayout )
+{
+ if ( !IsReallyVisible() )
+ return;
+
+ XubString aText = ImplGetText();
+ nStart = 0;
+ nEnd = aText.Len();
+
+ sal_Int32 nDXBuffer[256];
+ sal_Int32* pDXBuffer = NULL;
+ sal_Int32* pDX = nDXBuffer;
+
+ if( aText.Len() )
+ {
+ if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
+ {
+ pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
+ pDX = pDXBuffer;
+ }
+
+ GetCaretPositions( aText, pDX, nStart, nEnd );
+ }
+
+ long nTH = GetTextHeight();
+ Point aPos( mnXOffset, ImplGetTextYPosition() );
+
+ if( bLayout )
+ {
+ long nPos = nStart ? pDX[2*nStart] : 0;
+ aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
+
+ MetricVector* pVector = &mpControlData->mpLayoutData->m_aUnicodeBoundRects;
+ String* pDisplayText = &mpControlData->mpLayoutData->m_aDisplayText;
+
+ DrawText( aPos, aText, nStart, nEnd - nStart, pVector, pDisplayText );
+
+ if( pDXBuffer )
+ delete [] pDXBuffer;
+ return;
+ }
+
+ Cursor* pCursor = GetCursor();
+ BOOL bVisCursor = pCursor ? pCursor->IsVisible() : FALSE;
+ if ( pCursor )
+ pCursor->Hide();
+
+ ImplClearBackground( 0, GetOutputSizePixel().Width() );
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ if ( IsEnabled() )
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ else
+ SetTextColor( rStyleSettings.GetDisableColor() );
+
+ // Set background color of the normal text
+ if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
+ {
+ // check if we need to set ControlBackground even in NWF case
+ Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
+ SetLineColor();
+ SetFillColor( GetControlBackground() );
+ DrawRect( Rectangle( aPos, Size( GetOutputSizePixel().Width() - 2*mnXOffset, nTH ) ) );
+ Pop();
+
+ SetTextFillColor( GetControlBackground() );
+ }
+ else if( IsPaintTransparent() || ImplUseNativeBorder( GetStyle() ) )
+ SetTextFillColor();
+ else
+ SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
+
+ BOOL bDrawSelection = maSelection.Len() && ( HasFocus() || ( GetStyle() & WB_NOHIDESELECTION ) || mbActivePopup );
+
+ long nPos = nStart ? pDX[2*nStart] : 0;
+ aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
+ if ( !bDrawSelection && !mpIMEInfos )
+ {
+ DrawText( aPos, aText, nStart, nEnd - nStart );
+ }
+ else
+ {
+ // save graphics state
+ Push();
+ // first calculate higlighted and non highlighted clip regions
+ Region aHiglightClipRegion;
+ Region aNormalClipRegion;
+ Selection aTmpSel( maSelection );
+ aTmpSel.Justify();
+ // selection is highlighted
+ int i;
+ for( i = 0; i < aText.Len(); i++ )
+ {
+ Rectangle aRect( aPos, Size( 10, nTH ) );
+ aRect.Left() = pDX[2*i] + mnXOffset + ImplGetExtraOffset();
+ aRect.Right() = pDX[2*i+1] + mnXOffset + ImplGetExtraOffset();
+ aRect.Justify();
+ bool bHighlight = false;
+ if( i >= aTmpSel.Min() && i < aTmpSel.Max() )
+ bHighlight = true;
+
+ if( mpIMEInfos && mpIMEInfos->pAttribs &&
+ i >= mpIMEInfos->nPos && i < (mpIMEInfos->nPos+mpIMEInfos->nLen ) &&
+ ( mpIMEInfos->pAttribs[i-mpIMEInfos->nPos] & EXTTEXTINPUT_ATTR_HIGHLIGHT) )
+ bHighlight = true;
+
+ if( bHighlight )
+ aHiglightClipRegion.Union( aRect );
+ else
+ aNormalClipRegion.Union( aRect );
+ }
+ // draw normal text
+ Color aNormalTextColor = GetTextColor();
+ SetClipRegion( aNormalClipRegion );
+
+ if( IsPaintTransparent() )
+ SetTextFillColor();
+ else
+ {
+ // Set background color when part of the text is selected
+ if ( ImplUseNativeBorder( GetStyle() ) )
+ {
+ if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
+ SetTextFillColor( GetControlBackground() );
+ else
+ SetTextFillColor();
+ }
+ else
+ SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
+ }
+ DrawText( aPos, aText, nStart, nEnd - nStart );
+
+ // draw highlighted text
+ SetClipRegion( aHiglightClipRegion );
+ SetTextColor( rStyleSettings.GetHighlightTextColor() );
+ SetTextFillColor( rStyleSettings.GetHighlightColor() );
+ DrawText( aPos, aText, nStart, nEnd - nStart );
+
+ // if IME info exists loop over portions and output different font attributes
+ if( mpIMEInfos && mpIMEInfos->pAttribs )
+ {
+ for( int n = 0; n < 2; n++ )
+ {
+ Region aRegion;
+ if( n == 0 )
+ {
+ SetTextColor( aNormalTextColor );
+ if( IsPaintTransparent() )
+ SetTextFillColor();
+ else
+ SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
+ aRegion = aNormalClipRegion;
+ }
+ else
+ {
+ SetTextColor( rStyleSettings.GetHighlightTextColor() );
+ SetTextFillColor( rStyleSettings.GetHighlightColor() );
+ aRegion = aHiglightClipRegion;
+ }
+
+ for( i = 0; i < mpIMEInfos->nLen; )
+ {
+ USHORT nAttr = mpIMEInfos->pAttribs[i];
+ Region aClip;
+ int nIndex = i;
+ while( nIndex < mpIMEInfos->nLen && mpIMEInfos->pAttribs[nIndex] == nAttr) // #112631# check nIndex before using it
+ {
+ Rectangle aRect( aPos, Size( 10, nTH ) );
+ aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset();
+ aRect.Right() = pDX[2*(nIndex+mpIMEInfos->nPos)+1] + mnXOffset + ImplGetExtraOffset();
+ aRect.Justify();
+ aClip.Union( aRect );
+ nIndex++;
+ }
+ i = nIndex;
+ if( aClip.Intersect( aRegion ) && nAttr )
+ {
+ Font aFont = GetFont();
+ if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
+ aFont.SetUnderline( UNDERLINE_SINGLE );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
+ aFont.SetUnderline( UNDERLINE_BOLD );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
+ aFont.SetUnderline( UNDERLINE_DOTTED );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
+ aFont.SetUnderline( UNDERLINE_DOTTED );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
+ {
+ aFont.SetUnderline( UNDERLINE_WAVE );
+ SetTextLineColor( Color( COL_LIGHTGRAY ) );
+ }
+ SetFont( aFont );
+
+ if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
+ SetTextColor( Color( COL_RED ) );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
+ SetTextColor( Color( COL_LIGHTGRAY ) );
+
+ SetClipRegion( aClip );
+ DrawText( aPos, aText, nStart, nEnd - nStart );
+ }
+ }
+ }
+ }
+
+ // restore graphics state
+ Pop();
+ }
+
+ if ( bVisCursor && ( !mpIMEInfos || mpIMEInfos->bCursor ) )
+ pCursor->Show();
+
+ if( pDXBuffer )
+ delete [] pDXBuffer;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplDelete( const Selection& rSelection, BYTE nDirection, BYTE nMode )
+{
+ XubString aText = ImplGetText();
+
+ // loeschen moeglich?
+ if ( !rSelection.Len() &&
+ (((rSelection.Min() == 0) && (nDirection == EDIT_DEL_LEFT)) ||
+ ((rSelection.Max() == aText.Len()) && (nDirection == EDIT_DEL_RIGHT))) )
+ return;
+
+ ImplClearLayoutData();
+
+ Selection aSelection( rSelection );
+ aSelection.Justify();
+
+ if ( !aSelection.Len() )
+ {
+ uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
+ if ( nDirection == EDIT_DEL_LEFT )
+ {
+ if ( nMode == EDIT_DELMODE_RESTOFWORD )
+ {
+ i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ if ( aBoundary.startPos == aSelection.Min() )
+ aBoundary = xBI->previousWord( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ aSelection.Min() = aBoundary.startPos;
+ }
+ else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
+ {
+ aSelection.Min() = 0;
+ }
+ else
+ {
+ sal_Int32 nCount = 1;
+ aSelection.Min() = xBI->previousCharacters( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
+ }
+ }
+ else
+ {
+ if ( nMode == EDIT_DELMODE_RESTOFWORD )
+ {
+ i18n::Boundary aBoundary = xBI->nextWord( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ aSelection.Max() = aBoundary.startPos;
+ }
+ else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
+ {
+ aSelection.Max() = aText.Len();
+ }
+ else
+ {
+ sal_Int32 nCount = 1;
+ aSelection.Max() = xBI->nextCharacters( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );;
+ }
+ }
+ }
+
+ maText.Erase( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
+ maSelection.Min() = aSelection.Min();
+ maSelection.Max() = aSelection.Min();
+ ImplAlignAndPaint();
+ mbInternModified = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+String Edit::ImplGetValidString( const String& rString ) const
+{
+ String aValidString( rString );
+ aValidString.EraseAllChars( _LF );
+ aValidString.EraseAllChars( _CR );
+ aValidString.SearchAndReplaceAll( '\t', ' ' );
+ return aValidString;
+}
+
+// -----------------------------------------------------------------------
+Reference < i18n::XBreakIterator > Edit::ImplGetBreakIterator() const
+{
+ //!! since we don't want to become incompatible in the next minor update
+ //!! where this code will get integrated into, xISC will be a local
+ //!! variable instead of a class member!
+ Reference < i18n::XBreakIterator > xBI;
+// if ( !xBI.is() )
+ {
+ Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
+ Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) );
+ if ( xI.is() )
+ {
+ Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XBreakIterator >*)0) );
+ x >>= xBI;
+ }
+ }
+ return xBI;
+}
+// -----------------------------------------------------------------------
+
+Reference < i18n::XExtendedInputSequenceChecker > Edit::ImplGetInputSequenceChecker() const
+{
+ //!! since we don't want to become incompatible in the next minor update
+ //!! where this code will get integrated into, xISC will be a local
+ //!! variable instead of a class member!
+ Reference < i18n::XExtendedInputSequenceChecker > xISC;
+// if ( !xISC.is() )
+ {
+ Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
+ Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) );
+ if ( xI.is() )
+ {
+ Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XExtendedInputSequenceChecker >*)0) );
+ x >>= xISC;
+ }
+ }
+ return xISC;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ShowTruncationWarning( Window* pParent )
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ {
+ WarningBox aBox( pParent, ResId( SV_EDIT_WARNING_BOX, *pResMgr ) );
+ aBox.Execute();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool Edit::ImplTruncateToMaxLen( rtl::OUString& rStr, sal_uInt32 nSelectionLen ) const
+{
+ bool bWasTruncated = false;
+ const sal_uInt32 nMaxLen = mnMaxTextLen < 65534 ? mnMaxTextLen : 65534;
+ sal_uInt32 nLenAfter = static_cast<sal_uInt32>(maText.Len()) + rStr.getLength() - nSelectionLen;
+ if ( nLenAfter > nMaxLen )
+ {
+ sal_uInt32 nErasePos = nMaxLen - static_cast<sal_uInt32>(maText.Len()) + nSelectionLen;
+ rStr = rStr.copy( 0, nErasePos );
+ bWasTruncated = true;
+ }
+ return bWasTruncated;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplInsertText( const XubString& rStr, const Selection* pNewSel, sal_Bool bIsUserInput )
+{
+ Selection aSelection( maSelection );
+ aSelection.Justify();
+
+ rtl::OUString aNewText( ImplGetValidString( rStr ) );
+ ImplTruncateToMaxLen( aNewText, aSelection.Len() );
+
+ ImplClearLayoutData();
+
+ if ( aSelection.Len() )
+ maText.Erase( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
+ else if ( !mbInsertMode && (aSelection.Max() < maText.Len()) )
+ maText.Erase( (xub_StrLen)aSelection.Max(), 1 );
+
+ // take care of input-sequence-checking now
+ if (bIsUserInput && rStr.Len())
+ {
+ DBG_ASSERT( rStr.Len() == 1, "unexpected string length. User input is expected to providse 1 char only!" );
+
+ // determine if input-sequence-checking should be applied or not
+ //
+ static OUString sModule( OUString::createFromAscii( "/org.openoffice.Office.Common/I18N" ) );
+ static OUString sRelNode( OUString::createFromAscii( "CTL" ) );
+ static OUString sCTLSequenceChecking( OUString::createFromAscii( "CTLSequenceChecking" ) );
+ static OUString sCTLSequenceCheckingRestricted( OUString::createFromAscii( "CTLSequenceCheckingRestricted" ) );
+ static OUString sCTLSequenceCheckingTypeAndReplace( OUString::createFromAscii( "CTLSequenceCheckingTypeAndReplace" ) );
+ static OUString sCTLFont( OUString::createFromAscii( "CTLFont" ) );
+ //
+ sal_Bool bCTLSequenceChecking = sal_False;
+ sal_Bool bCTLSequenceCheckingRestricted = sal_False;
+ sal_Bool bCTLSequenceCheckingTypeAndReplace = sal_False;
+ sal_Bool bCTLFontEnabled = sal_False;
+ sal_Bool bIsInputSequenceChecking = sal_False;
+ //
+ // get access to the configuration of this office module
+ try
+ {
+ Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
+ Reference< container::XNameAccess > xModuleCfg( ::comphelper::ConfigurationHelper::openConfig(
+ xMSF,
+ sModule,
+ ::comphelper::ConfigurationHelper::E_READONLY ),
+ uno::UNO_QUERY );
+
+ //!! get values from configuration.
+ //!! we can't use SvtCTLOptions here since vcl must not be linked
+ //!! against svtools. (It is already the other way around.)
+ Any aCTLSequenceChecking = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceChecking );
+ Any aCTLSequenceCheckingRestricted = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingRestricted );
+ Any aCTLSequenceCheckingTypeAndReplace = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingTypeAndReplace );
+ Any aCTLFontEnabled = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLFont );
+ aCTLSequenceChecking >>= bCTLSequenceChecking;
+ aCTLSequenceCheckingRestricted >>= bCTLSequenceCheckingRestricted;
+ aCTLSequenceCheckingTypeAndReplace >>= bCTLSequenceCheckingTypeAndReplace;
+ aCTLFontEnabled >>= bCTLFontEnabled;
+ }
+ catch(...)
+ {
+ bIsInputSequenceChecking = sal_False; // continue with inserting the new text
+ }
+ //
+ uno::Reference < i18n::XBreakIterator > xBI( ImplGetBreakIterator(), UNO_QUERY );
+ bIsInputSequenceChecking = rStr.Len() == 1 &&
+ bCTLFontEnabled &&
+ bCTLSequenceChecking &&
+ aSelection.Min() > 0 && /* first char needs not to be checked */
+ xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rStr, 0 );
+
+
+ uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
+ if (bIsInputSequenceChecking && (xISC = ImplGetInputSequenceChecker()).is())
+ {
+ sal_Unicode cChar = rStr.GetChar(0);
+ xub_StrLen nTmpPos = static_cast< xub_StrLen >( aSelection.Min() );
+ sal_Int16 nCheckMode = bCTLSequenceCheckingRestricted ?
+ i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
+
+ // the text that needs to be checked is only the one
+ // before the current cursor position
+ rtl::OUString aOldText( maText.Copy(0, nTmpPos) );
+ rtl::OUString aTmpText( aOldText );
+ if (bCTLSequenceCheckingTypeAndReplace)
+ {
+ xISC->correctInputSequence( aTmpText, nTmpPos - 1, cChar, nCheckMode );
+
+ // find position of first character that has changed
+ sal_Int32 nOldLen = aOldText.getLength();
+ sal_Int32 nTmpLen = aTmpText.getLength();
+ const sal_Unicode *pOldTxt = aOldText.getStr();
+ const sal_Unicode *pTmpTxt = aTmpText.getStr();
+ sal_Int32 nChgPos = 0;
+ while ( nChgPos < nOldLen && nChgPos < nTmpLen &&
+ pOldTxt[nChgPos] == pTmpTxt[nChgPos] )
+ ++nChgPos;
+
+ xub_StrLen nChgLen = static_cast< xub_StrLen >( nTmpLen - nChgPos );
+ String aChgText( aTmpText.copy( nChgPos ), nChgLen );
+
+ // remove text from first pos to be changed to current pos
+ maText.Erase( static_cast< xub_StrLen >( nChgPos ), static_cast< xub_StrLen >( nTmpPos - nChgPos ) );
+
+ if (aChgText.Len())
+ {
+ aNewText = aChgText;
+ aSelection.Min() = nChgPos; // position for new text to be inserted
+ }
+ else
+ aNewText = String::EmptyString();
+ }
+ else
+ {
+ // should the character be ignored (i.e. not get inserted) ?
+ if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, cChar, nCheckMode ))
+ aNewText = String::EmptyString();
+ }
+ }
+
+ // at this point now we will insert the non-empty text 'normally' some lines below...
+ }
+
+ if ( aNewText.getLength() )
+ maText.Insert( String( aNewText ), (xub_StrLen)aSelection.Min() );
+
+ if ( !pNewSel )
+ {
+ maSelection.Min() = aSelection.Min() + aNewText.getLength();
+ maSelection.Max() = maSelection.Min();
+ }
+ else
+ {
+ maSelection = *pNewSel;
+ if ( maSelection.Min() > maText.Len() )
+ maSelection.Min() = maText.Len();
+ if ( maSelection.Max() > maText.Len() )
+ maSelection.Max() = maText.Len();
+ }
+
+ ImplAlignAndPaint();
+ mbInternModified = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplSetText( const XubString& rText, const Selection* pNewSelection )
+{
+ // Der Text wird dadurch geloescht das der alte Text komplett 'selektiert'
+ // wird, dann InsertText, damit flackerfrei.
+ if ( ( rText.Len() <= mnMaxTextLen ) && ( (rText != maText) || (pNewSelection && (*pNewSelection != maSelection)) ) )
+ {
+ ImplClearLayoutData();
+ maSelection.Min() = 0;
+ maSelection.Max() = maText.Len();
+ if ( mnXOffset || HasPaintEvent() )
+ {
+ mnXOffset = 0;
+ maText = ImplGetValidString( rText );
+
+ // #i54929# recalculate mnXOffset before ImplSetSelection,
+ // else cursor ends up in wrong position
+ ImplAlign();
+
+ if ( pNewSelection )
+ ImplSetSelection( *pNewSelection, FALSE );
+
+ if ( mnXOffset && !pNewSelection )
+ maSelection.Max() = 0;
+
+ Invalidate();
+ }
+ else
+ ImplInsertText( rText, pNewSelection );
+
+ ImplCallEventListeners( VCLEVENT_EDIT_MODIFY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int Edit::ImplGetNativeControlType()
+{
+ int nCtrl = 0;
+ Window *pControl = mbIsSubEdit ? GetParent() : this;
+
+ switch( pControl->GetType() )
+ {
+ case WINDOW_COMBOBOX:
+ case WINDOW_PATTERNBOX:
+ case WINDOW_NUMERICBOX:
+ case WINDOW_METRICBOX:
+ case WINDOW_CURRENCYBOX:
+ case WINDOW_DATEBOX:
+ case WINDOW_TIMEBOX:
+ case WINDOW_LONGCURRENCYBOX:
+ nCtrl = CTRL_COMBOBOX;
+ break;
+
+ case WINDOW_MULTILINEEDIT:
+ if ( GetWindow( WINDOW_BORDER ) != this )
+ nCtrl = CTRL_MULTILINE_EDITBOX;
+ else
+ nCtrl = CTRL_EDITBOX_NOBORDER;
+ break;
+
+ case WINDOW_EDIT:
+ case WINDOW_PATTERNFIELD:
+ case WINDOW_METRICFIELD:
+ case WINDOW_CURRENCYFIELD:
+ case WINDOW_DATEFIELD:
+ case WINDOW_TIMEFIELD:
+ case WINDOW_LONGCURRENCYFIELD:
+ case WINDOW_NUMERICFIELD:
+ case WINDOW_SPINFIELD:
+ if( pControl->GetStyle() & WB_SPIN )
+ nCtrl = CTRL_SPINBOX;
+ else
+ {
+ if ( GetWindow( WINDOW_BORDER ) != this )
+ nCtrl = CTRL_EDITBOX;
+ else
+ nCtrl = CTRL_EDITBOX_NOBORDER;
+ }
+ break;
+
+ default:
+ nCtrl = CTRL_EDITBOX;
+ }
+ return nCtrl;
+}
+
+void Edit::ImplClearBackground( long nXStart, long nXEnd )
+{
+ /*
+ * note: at this point the cursor must be switched off already
+ */
+ Point aTmpPoint;
+ Rectangle aRect( aTmpPoint, GetOutputSizePixel() );
+ aRect.Left() = nXStart;
+ aRect.Right() = nXEnd;
+
+ if( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
+ {
+ // draw the inner part by painting the whole control using its border window
+ Window *pControl = this;
+ Window *pBorder = GetWindow( WINDOW_BORDER );
+ if( pBorder == this )
+ {
+ // we have no border, use parent
+ pControl = mbIsSubEdit ? GetParent() : this;
+ pBorder = pControl->GetWindow( WINDOW_BORDER );
+ if( pBorder == this )
+ pBorder = GetParent();
+ }
+
+ if( pBorder )
+ {
+ // set proper clipping region to not overdraw the whole control
+ Region aClipRgn = GetPaintRegion();
+ if( !aClipRgn.IsNull() )
+ {
+ // transform clipping region to border window's coordinate system
+ if( IsRTLEnabled() != pBorder->IsRTLEnabled() && Application::GetSettings().GetLayoutRTL() )
+ {
+ // need to mirror in case border is not RTL but edit is (or vice versa)
+
+ // mirror
+ Rectangle aBounds( aClipRgn.GetBoundRect() );
+ int xNew = GetOutputSizePixel().Width() - aBounds.GetWidth() - aBounds.Left();
+ aClipRgn.Move( xNew - aBounds.Left(), 0 );
+
+ // move offset of border window
+ Point aBorderOffs;
+ aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
+ aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
+ }
+ else
+ {
+ // normal case
+ Point aBorderOffs;
+ aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
+ aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
+ }
+
+ Region oldRgn( pBorder->GetClipRegion() );
+ pBorder->SetClipRegion( aClipRgn );
+
+ pBorder->Paint( Rectangle() );
+
+ pBorder->SetClipRegion( oldRgn );
+ }
+ else
+ pBorder->Paint( Rectangle() );
+
+ }
+ }
+ else
+ Erase( aRect );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplShowCursor( BOOL bOnlyIfVisible )
+{
+ if ( !IsUpdateMode() || ( bOnlyIfVisible && !IsReallyVisible() ) )
+ return;
+
+ Cursor* pCursor = GetCursor();
+ XubString aText = ImplGetText();
+
+ long nTextPos = 0;
+
+ sal_Int32 nDXBuffer[256];
+ sal_Int32* pDXBuffer = NULL;
+ sal_Int32* pDX = nDXBuffer;
+
+ if( aText.Len() )
+ {
+ if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
+ {
+ pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
+ pDX = pDXBuffer;
+ }
+
+ GetCaretPositions( aText, pDX, 0, aText.Len() );
+
+ if( maSelection.Max() < aText.Len() )
+ nTextPos = pDX[ 2*maSelection.Max() ];
+ else
+ nTextPos = pDX[ 2*aText.Len()-1 ];
+ }
+
+ long nCursorWidth = 0;
+ if ( !mbInsertMode && !maSelection.Len() && (maSelection.Max() < aText.Len()) )
+ nCursorWidth = GetTextWidth( aText, (xub_StrLen)maSelection.Max(), 1 );
+ long nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
+
+ // Cursor muss im sichtbaren Bereich landen:
+ const Size aOutSize = GetOutputSizePixel();
+ if ( (nCursorPosX < 0) || (nCursorPosX >= aOutSize.Width()) )
+ {
+ long nOldXOffset = mnXOffset;
+
+ if ( nCursorPosX < 0 )
+ {
+ mnXOffset = - nTextPos;
+ long nMaxX = 0;
+ mnXOffset += aOutSize.Width() / 5;
+ if ( mnXOffset > nMaxX )
+ mnXOffset = nMaxX;
+ }
+ else
+ {
+ mnXOffset = (aOutSize.Width()-ImplGetExtraOffset()) - nTextPos;
+ // Etwas mehr?
+ if ( (aOutSize.Width()-ImplGetExtraOffset()) < nTextPos )
+ {
+ long nMaxNegX = (aOutSize.Width()-ImplGetExtraOffset()) - GetTextWidth( aText );
+ mnXOffset -= aOutSize.Width() / 5;
+ if ( mnXOffset < nMaxNegX ) // beides negativ...
+ mnXOffset = nMaxNegX;
+ }
+ }
+
+ nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
+ if ( nCursorPosX == aOutSize.Width() ) // dann nicht sichtbar...
+ nCursorPosX--;
+
+ if ( mnXOffset != nOldXOffset )
+ ImplInvalidateOrRepaint();
+ }
+
+ const long nTextHeight = GetTextHeight();
+ const long nCursorPosY = ImplGetTextYPosition();
+ pCursor->SetPos( Point( nCursorPosX, nCursorPosY ) );
+ pCursor->SetSize( Size( nCursorWidth, nTextHeight ) );
+ pCursor->Show();
+
+ if( pDXBuffer )
+ delete [] pDXBuffer;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplAlign()
+{
+ long nTextWidth = GetTextWidth( ImplGetText() );
+ long nOutWidth = GetOutputSizePixel().Width();
+
+ if ( mnAlign == EDIT_ALIGN_LEFT )
+ {
+ if( mnXOffset && ( nTextWidth < nOutWidth ) )
+ mnXOffset = 0;
+
+ }
+ else if ( mnAlign == EDIT_ALIGN_RIGHT )
+ {
+ long nMinXOffset = nOutWidth - nTextWidth - 1 - ImplGetExtraOffset();
+ bool bRTL = IsRTLEnabled();
+ if( mbIsSubEdit && GetParent() )
+ bRTL = GetParent()->IsRTLEnabled();
+ if( bRTL )
+ {
+ if( nTextWidth < nOutWidth )
+ mnXOffset = nMinXOffset;
+ }
+ else
+ {
+ if( nTextWidth < nOutWidth )
+ mnXOffset = nMinXOffset;
+ else if ( mnXOffset < nMinXOffset )
+ mnXOffset = nMinXOffset;
+ }
+ }
+ else if( mnAlign == EDIT_ALIGN_CENTER )
+ {
+ // Mit Abfrage schoener, wenn gescrollt, dann aber nicht zentriert im gescrollten Zustand...
+// if ( nTextWidth < nOutWidth )
+ mnXOffset = (nOutWidth - nTextWidth) / 2;
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplAlignAndPaint()
+{
+ ImplAlign();
+ ImplInvalidateOrRepaint( 0, STRING_LEN );
+ ImplShowCursor();
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen Edit::ImplGetCharPos( const Point& rWindowPos ) const
+{
+ xub_StrLen nIndex = STRING_LEN;
+ String aText = ImplGetText();
+
+ sal_Int32 nDXBuffer[256];
+ sal_Int32* pDXBuffer = NULL;
+ sal_Int32* pDX = nDXBuffer;
+ if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
+ {
+ pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
+ pDX = pDXBuffer;
+ }
+
+ GetCaretPositions( aText, pDX, 0, aText.Len() );
+ long nX = rWindowPos.X() - mnXOffset - ImplGetExtraOffset();
+ for( int i = 0; i < aText.Len(); i++ )
+ {
+ if( (pDX[2*i] >= nX && pDX[2*i+1] <= nX) ||
+ (pDX[2*i+1] >= nX && pDX[2*i] <= nX))
+ {
+ nIndex = sal::static_int_cast<xub_StrLen>(i);
+ if( pDX[2*i] < pDX[2*i+1] )
+ {
+ if( nX > (pDX[2*i]+pDX[2*i+1])/2 )
+ nIndex++;
+ }
+ else
+ {
+ if( nX < (pDX[2*i]+pDX[2*i+1])/2 )
+ nIndex++;
+ }
+ break;
+ }
+ }
+ if( nIndex == STRING_LEN )
+ {
+ nIndex = 0;
+ long nDiff = Abs( pDX[0]-nX );
+ for( int i = 1; i < aText.Len(); i++ )
+ {
+ long nNewDiff = Abs( pDX[2*i]-nX );
+
+ if( nNewDiff < nDiff )
+ {
+ nIndex = sal::static_int_cast<xub_StrLen>(i);
+ nDiff = nNewDiff;
+ }
+ }
+ if( nIndex == aText.Len()-1 && Abs( pDX[2*nIndex+1] - nX ) < nDiff )
+ nIndex = STRING_LEN;
+ }
+
+ if( pDXBuffer )
+ delete [] pDXBuffer;
+
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplSetCursorPos( xub_StrLen nChar, BOOL bSelect )
+{
+ Selection aSelection( maSelection );
+ aSelection.Max() = nChar;
+ if ( !bSelect )
+ aSelection.Min() = aSelection.Max();
+ ImplSetSelection( aSelection );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ xub_StrLen nTextLength = ReadShortRes();
+ if ( nTextLength )
+ SetMaxTextLen( nTextLength );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplCopyToSelectionClipboard()
+{
+ if ( GetSelection().Len() )
+ {
+ ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(GetPrimarySelection());
+ ImplCopy( aSelection );
+ }
+}
+
+void Edit::ImplCopy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
+{
+ ::vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplPaste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
+{
+ if ( rxClipboard.is() )
+ {
+ uno::Reference< datatransfer::XTransferable > xDataObj;
+
+ const sal_uInt32 nRef = Application::ReleaseSolarMutex();
+
+ try
+ {
+ xDataObj = rxClipboard->getContents();
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+
+ Application::AcquireSolarMutex( nRef );
+
+ if ( xDataObj.is() )
+ {
+ datatransfer::DataFlavor aFlavor;
+ SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
+ try
+ {
+ uno::Any aData = xDataObj->getTransferData( aFlavor );
+ ::rtl::OUString aText;
+ aData >>= aText;
+ if( ImplTruncateToMaxLen( aText, maSelection.Len() ) )
+ ShowTruncationWarning( const_cast<Edit*>(this) );
+ ReplaceSelected( aText );
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( mpSubEdit )
+ {
+ Control::MouseButtonDown( rMEvt );
+ return;
+ }
+
+ xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
+ Selection aSelection( maSelection );
+ aSelection.Justify();
+
+ if ( rMEvt.GetClicks() < 4 )
+ {
+ mbClickedInSelection = FALSE;
+ if ( rMEvt.GetClicks() == 3 )
+ {
+ ImplSetSelection( Selection( 0, 0xFFFF ) );
+ ImplCopyToSelectionClipboard();
+
+ }
+ else if ( rMEvt.GetClicks() == 2 )
+ {
+ uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
+ i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ ImplSetSelection( Selection( aBoundary.startPos, aBoundary.endPos ) );
+ ImplCopyToSelectionClipboard();
+ }
+ else if ( !rMEvt.IsShift() && HasFocus() && aSelection.IsInside( nChar ) )
+ mbClickedInSelection = TRUE;
+ else if ( rMEvt.IsLeft() )
+ ImplSetCursorPos( nChar, rMEvt.IsShift() );
+
+ if ( !mbClickedInSelection && rMEvt.IsLeft() && ( rMEvt.GetClicks() == 1 ) )
+ StartTracking( STARTTRACK_SCROLLREPEAT );
+ }
+
+ mbInMBDown = TRUE; // Dann im GetFocus nicht alles selektieren
+ GrabFocus();
+ mbInMBDown = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ if ( mbClickedInSelection && rMEvt.IsLeft() )
+ {
+ xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
+ ImplSetCursorPos( nChar, FALSE );
+ mbClickedInSelection = FALSE;
+ }
+ else if ( rMEvt.IsMiddle() && !mbReadOnly &&
+ ( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
+ {
+ ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(Window::GetPrimarySelection());
+ ImplPaste( aSelection );
+ ImplModified();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Tracking( const TrackingEvent& rTEvt )
+{
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ if ( mbClickedInSelection )
+ {
+ xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
+ ImplSetCursorPos( nChar, FALSE );
+ mbClickedInSelection = FALSE;
+ }
+ else if ( rTEvt.GetMouseEvent().IsLeft() )
+ {
+ ImplCopyToSelectionClipboard();
+ }
+ }
+ else
+ {
+ if( !mbClickedInSelection )
+ {
+ xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
+ ImplSetCursorPos( nChar, TRUE );
+ }
+ }
+
+ if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
+ mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
+{
+ BOOL bDone = FALSE;
+ USHORT nCode = rKEvt.GetKeyCode().GetCode();
+ KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
+
+ mbInternModified = FALSE;
+
+ if ( eFunc != KEYFUNC_DONTKNOW )
+ {
+ switch ( eFunc )
+ {
+ case KEYFUNC_CUT:
+ {
+ if ( !mbReadOnly && maSelection.Len() && !(GetStyle() & WB_PASSWORD) )
+ {
+ Cut();
+ ImplModified();
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ case KEYFUNC_COPY:
+ {
+ if ( !(GetStyle() & WB_PASSWORD) )
+ {
+ Copy();
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ case KEYFUNC_PASTE:
+ {
+ if ( !mbReadOnly )
+ {
+ Paste();
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ case KEYFUNC_UNDO:
+ {
+ if ( !mbReadOnly )
+ {
+ Undo();
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ default: // wird dann evtl. unten bearbeitet.
+ eFunc = KEYFUNC_DONTKNOW;
+ }
+ }
+
+ if ( !bDone && rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
+ {
+ if ( nCode == KEY_A )
+ {
+ ImplSetSelection( Selection( 0, maText.Len() ) );
+ bDone = TRUE;
+ }
+ else if ( rKEvt.GetKeyCode().IsShift() && (nCode == KEY_S) )
+ {
+ if ( pImplFncGetSpecialChars )
+ {
+ Selection aSaveSel = GetSelection(); // Falls jemand in Get/LoseFocus die Selektion verbiegt, z.B. URL-Zeile...
+ XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
+ SetSelection( aSaveSel );
+ if ( aChars.Len() )
+ {
+ ImplInsertText( aChars );
+ ImplModified();
+ }
+ bDone = TRUE;
+ }
+ }
+ }
+
+ if ( eFunc == KEYFUNC_DONTKNOW && ! bDone )
+ {
+ switch ( nCode )
+ {
+ case com::sun::star::awt::Key::SELECT_ALL:
+ {
+ ImplSetSelection( Selection( 0, maText.Len() ) );
+ bDone = TRUE;
+ }
+ break;
+
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_HOME:
+ case KEY_END:
+ case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
+ case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
+ case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
+ case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
+ {
+ if ( !rKEvt.GetKeyCode().IsMod2() )
+ {
+ ImplClearLayoutData();
+ uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
+
+ Selection aSel( maSelection );
+ bool bWord = rKEvt.GetKeyCode().IsMod1();
+ bool bSelect = rKEvt.GetKeyCode().IsShift();
+ bool bGoLeft = (nCode == KEY_LEFT);
+ bool bGoRight = (nCode == KEY_RIGHT);
+ bool bGoHome = (nCode == KEY_HOME);
+ bool bGoEnd = (nCode == KEY_END);
+
+ switch( nCode )
+ {
+ case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
+ bGoRight = bWord = true;break;
+ case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
+ bGoRight = bSelect = bWord = true;break;
+ case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
+ bGoLeft = bWord = true;break;
+ case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
+ bGoLeft = bSelect = bWord = true;break;
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
+ bSelect = true;
+ // fallthrough intended
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
+ bGoHome = true;break;
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
+ bSelect = true;
+ // fallthrough intended
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
+ bGoEnd = true;break;
+ default:
+ break;
+ };
+
+ // Range wird in ImplSetSelection geprueft...
+ if ( bGoLeft && aSel.Max() )
+ {
+ if ( bWord )
+ {
+ i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ if ( aBoundary.startPos == aSel.Max() )
+ aBoundary = xBI->previousWord( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ aSel.Max() = aBoundary.startPos;
+ }
+ else
+ {
+ sal_Int32 nCount = 1;
+ aSel.Max() = xBI->previousCharacters( maText, aSel.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
+ }
+ }
+ else if ( bGoRight && ( aSel.Max() < maText.Len() ) )
+ {
+ if ( bWord )
+ {
+ i18n::Boundary aBoundary = xBI->nextWord( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ aSel.Max() = aBoundary.startPos;
+ }
+ else
+ {
+ sal_Int32 nCount = 1;
+ aSel.Max() = xBI->nextCharacters( maText, aSel.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
+ }
+ }
+ else if ( bGoHome )
+ {
+ aSel.Max() = 0;
+ }
+ else if ( bGoEnd )
+ {
+ aSel.Max() = 0xFFFF;
+ }
+
+ if ( !bSelect )
+ aSel.Min() = aSel.Max();
+
+ if ( aSel != GetSelection() )
+ {
+ ImplSetSelection( aSel );
+ ImplCopyToSelectionClipboard();
+ }
+
+ if ( bGoEnd && maAutocompleteHdl.IsSet() && !rKEvt.GetKeyCode().GetModifier() )
+ {
+ if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
+ {
+ meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
+ maAutocompleteHdl.Call( this );
+ }
+ }
+
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
+ case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
+ case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
+ case KEY_BACKSPACE:
+ case KEY_DELETE:
+ {
+ if ( !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
+ {
+ BYTE nDel = (nCode == KEY_DELETE) ? EDIT_DEL_RIGHT : EDIT_DEL_LEFT;
+ BYTE nMode = rKEvt.GetKeyCode().IsMod1() ? EDIT_DELMODE_RESTOFWORD : EDIT_DELMODE_SIMPLE;
+ if ( (nMode == EDIT_DELMODE_RESTOFWORD) && rKEvt.GetKeyCode().IsShift() )
+ nMode = EDIT_DELMODE_RESTOFCONTENT;
+ switch( nCode )
+ {
+ case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
+ nDel = EDIT_DEL_LEFT;
+ nMode = EDIT_DELMODE_RESTOFWORD;
+ break;
+ case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
+ nDel = EDIT_DEL_RIGHT;
+ nMode = EDIT_DELMODE_RESTOFWORD;
+ break;
+ case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
+ nDel = EDIT_DEL_LEFT;
+ nMode = EDIT_DELMODE_RESTOFCONTENT;
+ break;
+ case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
+ nDel = EDIT_DEL_RIGHT;
+ nMode = EDIT_DELMODE_RESTOFCONTENT;
+ break;
+ default: break;
+ }
+ xub_StrLen nOldLen = maText.Len();
+ ImplDelete( maSelection, nDel, nMode );
+ if ( maText.Len() != nOldLen )
+ ImplModified();
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ case KEY_INSERT:
+ {
+ if ( !mpIMEInfos && !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
+ {
+ SetInsertMode( !mbInsertMode );
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ case KEY_TAB:
+ {
+ if ( !mbReadOnly && maAutocompleteHdl.IsSet() &&
+ maSelection.Min() && (maSelection.Min() == maText.Len()) &&
+ !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
+ {
+ // Kein Autocomplete wenn alles Selektiert oder Edit leer, weil dann
+ // keine vernuenftige Tab-Steuerung!
+ if ( rKEvt.GetKeyCode().IsShift() )
+ meAutocompleteAction = AUTOCOMPLETE_TABBACKWARD;
+ else
+ meAutocompleteAction = AUTOCOMPLETE_TABFORWARD;
+
+ maAutocompleteHdl.Call( this );
+
+ // Wurde nichts veraendert, dann TAB fuer DialogControl
+ if ( GetSelection().Len() )
+ bDone = TRUE;
+ }
+ }
+ break;
+
+ default:
+ {
+ if ( IsCharInput( rKEvt ) )
+ {
+ bDone = TRUE; // Auch bei ReadOnly die Zeichen schlucken.
+ if ( !mbReadOnly )
+ {
+ ImplInsertText( rKEvt.GetCharCode(), 0, sal_True );
+ if ( maAutocompleteHdl.IsSet() )
+ {
+ if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
+ {
+ meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
+ maAutocompleteHdl.Call( this );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( mbInternModified )
+ ImplModified();
+
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::KeyInput( const KeyEvent& rKEvt )
+{
+ if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
+ mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
+
+ if ( mpSubEdit || !ImplHandleKeyEvent( rKEvt ) )
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<Edit*>(this)->ImplRepaint( 0, STRING_LEN, true );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Paint( const Rectangle& )
+{
+ if ( !mpSubEdit )
+ ImplRepaint();
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Resize()
+{
+ if ( !mpSubEdit && IsReallyVisible() )
+ {
+ Control::Resize();
+ // Wegen vertikaler Zentrierung...
+ mnXOffset = 0;
+ ImplAlign();
+ Invalidate();
+ ImplShowCursor();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ ImplInitSettings( TRUE, TRUE, TRUE );
+
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Font aFont = GetDrawPixelFont( pDev );
+ OutDevType eOutDevType = pDev->GetOutDevType();
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ pDev->SetTextFillColor();
+
+ // Border/Background
+ pDev->SetLineColor();
+ pDev->SetFillColor();
+ BOOL bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
+ BOOL bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
+ if ( bBorder || bBackground )
+ {
+ Rectangle aRect( aPos, aSize );
+ if ( bBorder )
+ {
+ ImplDrawFrame( pDev, aRect );
+ }
+ if ( bBackground )
+ {
+ pDev->SetFillColor( GetControlBackground() );
+ pDev->DrawRect( aRect );
+ }
+ }
+
+ // Inhalt
+ if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ else
+ {
+ if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ pDev->SetTextColor( rStyleSettings.GetDisableColor() );
+ }
+ else
+ {
+ pDev->SetTextColor( GetTextColor() );
+ }
+ }
+
+ XubString aText = ImplGetText();
+ long nTextHeight = pDev->GetTextHeight();
+ long nTextWidth = pDev->GetTextWidth( aText );
+ long nOnePixel = GetDrawPixel( pDev, 1 );
+ long nOffX = 3*nOnePixel;
+ long nOffY = (aSize.Height() - nTextHeight) / 2;
+
+ // Clipping?
+ if ( (nOffY < 0) ||
+ ((nOffY+nTextHeight) > aSize.Height()) ||
+ ((nOffX+nTextWidth) > aSize.Width()) )
+ {
+ Rectangle aClip( aPos, aSize );
+ if ( nTextHeight > aSize.Height() )
+ aClip.Bottom() += nTextHeight-aSize.Height()+1; // Damit HP-Drucker nicht 'weg-optimieren'
+ pDev->IntersectClipRegion( aClip );
+ }
+
+ if ( GetStyle() & WB_CENTER )
+ {
+ aPos.X() += (aSize.Width() - nTextWidth) / 2;
+ nOffX = 0;
+ }
+ else if ( GetStyle() & WB_RIGHT )
+ {
+ aPos.X() += aSize.Width() - nTextWidth;
+ nOffX = -nOffX;
+ }
+
+ pDev->DrawText( Point( aPos.X() + nOffX, aPos.Y() + nOffY ), aText );
+ pDev->Pop();
+
+ if ( GetSubEdit() )
+ {
+ GetSubEdit()->Draw( pDev, rPos, rSize, nFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplInvalidateOutermostBorder( Window* pWin )
+{
+ // allow control to show focused state
+ Window *pInvalWin = pWin, *pBorder = pWin;
+ while( ( pBorder = pInvalWin->GetWindow( WINDOW_BORDER ) ) != pInvalWin && pBorder &&
+ pInvalWin->ImplGetFrame() == pBorder->ImplGetFrame() )
+ {
+ pInvalWin = pBorder;
+ }
+
+ pInvalWin->Invalidate( INVALIDATE_CHILDREN | INVALIDATE_UPDATE );
+}
+
+void Edit::GetFocus()
+{
+ if ( mpSubEdit )
+ mpSubEdit->ImplGrabFocus( GetGetFocusFlags() );
+ else if ( !mbActivePopup )
+ {
+ maUndoText = maText;
+
+ ULONG nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
+ if ( !( GetStyle() & (WB_NOHIDESELECTION|WB_READONLY) )
+ && ( GetGetFocusFlags() & (GETFOCUS_INIT|GETFOCUS_TAB|GETFOCUS_CURSOR|GETFOCUS_MNEMONIC) ) )
+ {
+ if ( nSelOptions & SELECTION_OPTION_SHOWFIRST )
+ {
+ maSelection.Min() = maText.Len();
+ maSelection.Max() = 0;
+ }
+ else
+ {
+ maSelection.Min() = 0;
+ maSelection.Max() = maText.Len();
+ }
+ if ( mbIsSubEdit )
+ ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
+ else
+ ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
+ }
+
+ ImplShowCursor();
+
+ // FIXME: this is currently only on aqua
+ // check for other platforms that need similar handling
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
+ {
+ ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
+ }
+ else if ( maSelection.Len() )
+ {
+ // Selektion malen
+ if ( !HasPaintEvent() )
+ ImplInvalidateOrRepaint();
+ else
+ Invalidate();
+ }
+
+ SetInputContext( InputContext( GetFont(), !IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
+ }
+
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+Window* Edit::GetPreferredKeyInputWindow()
+{
+ if ( mpSubEdit )
+ return mpSubEdit->GetPreferredKeyInputWindow();
+ else
+ return this;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::LoseFocus()
+{
+ if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
+ {
+ //notify an update latest when the focus is lost
+ mpUpdateDataTimer->Stop();
+ mpUpdateDataTimer->Timeout();
+ }
+
+ if ( !mpSubEdit )
+ {
+ // FIXME: this is currently only on aqua
+ // check for other platforms that need similar handling
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
+ {
+ ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
+ }
+
+ if ( !mbActivePopup && !( GetStyle() & WB_NOHIDESELECTION ) && maSelection.Len() )
+ ImplInvalidateOrRepaint(); // Selektion malen
+ }
+
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
+ {
+ PopupMenu* pPopup = Edit::CreatePopupMenu();
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_HIDEDISABLED )
+ pPopup->SetMenuFlags( MENU_FLAG_HIDEDISABLEDENTRIES );
+
+ if ( !maSelection.Len() )
+ {
+ pPopup->EnableItem( SV_MENU_EDIT_CUT, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_COPY, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_DELETE, FALSE );
+ }
+
+ if ( IsReadOnly() )
+ {
+ pPopup->EnableItem( SV_MENU_EDIT_CUT, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_PASTE, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_DELETE, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, FALSE );
+ }
+ else
+ {
+ // Paste nur, wenn Text im Clipboard
+ BOOL bData = FALSE;
+ uno::Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
+ if ( xClipboard.is() )
+ {
+ const sal_uInt32 nRef = Application::ReleaseSolarMutex();
+ uno::Reference< datatransfer::XTransferable > xDataObj = xClipboard->getContents();
+ Application::AcquireSolarMutex( nRef );
+ if ( xDataObj.is() )
+ {
+ datatransfer::DataFlavor aFlavor;
+ SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
+ bData = xDataObj->isDataFlavorSupported( aFlavor );
+ }
+ }
+ pPopup->EnableItem( SV_MENU_EDIT_PASTE, bData );
+ }
+
+ if ( maUndoText == maText )
+ pPopup->EnableItem( SV_MENU_EDIT_UNDO, FALSE );
+ if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.Len() ) )
+ pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, FALSE );
+ if ( !pImplFncGetSpecialChars )
+ {
+ USHORT nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL );
+ pPopup->RemoveItem( nPos );
+ pPopup->RemoveItem( nPos-1 );
+ }
+
+ mbActivePopup = TRUE;
+ Selection aSaveSel = GetSelection(); // Falls jemand in Get/LoseFocus die Selektion verbiegt, z.B. URL-Zeile...
+ Point aPos = rCEvt.GetMousePosPixel();
+ if ( !rCEvt.IsMouseEvent() )
+ {
+ // !!! Irgendwann einmal Menu zentriert in der Selektion anzeigen !!!
+ Size aSize = GetOutputSizePixel();
+ aPos = Point( aSize.Width()/2, aSize.Height()/2 );
+ }
+ USHORT n = pPopup->Execute( this, aPos );
+ Edit::DeletePopupMenu( pPopup );
+ SetSelection( aSaveSel );
+ switch ( n )
+ {
+ case SV_MENU_EDIT_UNDO:
+ Undo();
+ ImplModified();
+ break;
+ case SV_MENU_EDIT_CUT:
+ Cut();
+ ImplModified();
+ break;
+ case SV_MENU_EDIT_COPY:
+ Copy();
+ break;
+ case SV_MENU_EDIT_PASTE:
+ Paste();
+ ImplModified();
+ break;
+ case SV_MENU_EDIT_DELETE:
+ DeleteSelected();
+ ImplModified();
+ break;
+ case SV_MENU_EDIT_SELECTALL:
+ ImplSetSelection( Selection( 0, maText.Len() ) );
+ break;
+ case SV_MENU_EDIT_INSERTSYMBOL:
+ {
+ XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
+ SetSelection( aSaveSel );
+ if ( aChars.Len() )
+ {
+ ImplInsertText( aChars );
+ ImplModified();
+ }
+ }
+ break;
+ }
+ mbActivePopup = FALSE;
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_VOICE )
+ {
+ const CommandVoiceData* pData = rCEvt.GetVoiceData();
+ if ( pData->GetType() == VOICECOMMANDTYPE_DICTATION )
+ {
+ switch ( pData->GetCommand() )
+ {
+ case DICTATIONCOMMAND_UNKNOWN:
+ {
+ ReplaceSelected( pData->GetText() );
+ }
+ break;
+ case DICTATIONCOMMAND_LEFT:
+ {
+ ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1 ) ) );
+ }
+ break;
+ case DICTATIONCOMMAND_RIGHT:
+ {
+ ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_RIGHT, KEY_MOD1 ) ) );
+ }
+ break;
+ case DICTATIONCOMMAND_UNDO:
+ {
+ Undo();
+ }
+ break;
+ case DICTATIONCOMMAND_DEL:
+ {
+ ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1|KEY_SHIFT ) ) );
+ DeleteSelected();
+ }
+ break;
+ }
+ }
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
+ {
+ DeleteSelected();
+ delete mpIMEInfos;
+ xub_StrLen nPos = (xub_StrLen)maSelection.Max();
+ mpIMEInfos = new Impl_IMEInfos( nPos, maText.Copy( nPos ) );
+ mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
+ {
+ BOOL bInsertMode = !mpIMEInfos->bWasCursorOverwrite;
+ delete mpIMEInfos;
+ mpIMEInfos = NULL;
+ // Font wieder ohne Attribute einstellen, wird jetzt im Repaint nicht
+ // mehr neu initialisiert
+ ImplInitSettings( TRUE, FALSE, FALSE );
+
+ SetInsertMode( bInsertMode );
+
+ ImplModified();
+
+ // #i25161# call auto complete handler for ext text commit also
+ if ( maAutocompleteHdl.IsSet() )
+ {
+ if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
+ {
+ meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
+ maAutocompleteHdl.Call( this );
+ }
+ }
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
+ {
+ const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
+
+ maText.Erase( mpIMEInfos->nPos, mpIMEInfos->nLen );
+ maText.Insert( pData->GetText(), mpIMEInfos->nPos );
+ if ( mpIMEInfos->bWasCursorOverwrite )
+ {
+ USHORT nOldIMETextLen = mpIMEInfos->nLen;
+ USHORT nNewIMETextLen = pData->GetText().Len();
+ if ( ( nOldIMETextLen > nNewIMETextLen ) &&
+ ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) )
+ {
+ // restore old characters
+ USHORT nRestore = nOldIMETextLen - nNewIMETextLen;
+ maText.Insert( mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ), mpIMEInfos->nPos + nNewIMETextLen );
+ }
+ else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
+ ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) )
+ {
+ // overwrite
+ USHORT nOverwrite = nNewIMETextLen - nOldIMETextLen;
+ if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.Len() )
+ nOverwrite = mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen;
+ maText.Erase( mpIMEInfos->nPos + nNewIMETextLen, nOverwrite );
+ }
+ }
+
+
+ if ( pData->GetTextAttr() )
+ {
+ mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() );
+ mpIMEInfos->bCursor = pData->IsCursorVisible();
+ }
+ else
+ {
+ mpIMEInfos->DestroyAttribs();
+ }
+
+ ImplAlignAndPaint();
+ xub_StrLen nCursorPos = mpIMEInfos->nPos + pData->GetCursorPos();
+ SetSelection( Selection( nCursorPos, nCursorPos ) );
+ SetInsertMode( !pData->IsCursorOverwrite() );
+
+ if ( pData->IsCursorVisible() )
+ GetCursor()->Show();
+ else
+ GetCursor()->Hide();
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
+ {
+ if ( mpIMEInfos )
+ {
+ xub_StrLen nCursorPos = (USHORT)GetSelection().Max();
+ SetCursorRect( NULL, GetTextWidth(
+ maText, nCursorPos, mpIMEInfos->nPos+mpIMEInfos->nLen-nCursorPos ) );
+ }
+ else
+ {
+ SetCursorRect();
+ }
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_SELECTIONCHANGE )
+ {
+ const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
+ Selection aSelection( pData->GetStart(), pData->GetEnd() );
+ SetSelection(aSelection);
+ }
+ else
+ Control::Command( rCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ if ( !mpSubEdit )
+ {
+ mnXOffset = 0; // Falls vorher GrabFocus, als Groesse noch falsch.
+ ImplAlign();
+ if ( !mpSubEdit )
+ ImplShowCursor( FALSE );
+ }
+ // update background (eventual SetPaintTransparent)
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ }
+ else if ( nType == STATE_CHANGE_ENABLE )
+ {
+ if ( !mpSubEdit )
+ {
+ // Es aendert sich nur die Textfarbe...
+ ImplInvalidateOrRepaint( 0, 0xFFFF );
+ }
+ }
+ else if ( nType == STATE_CHANGE_STYLE || nType == STATE_CHANGE_MIRRORING )
+ {
+ WinBits nStyle = GetStyle();
+ if( nType == STATE_CHANGE_STYLE )
+ {
+ nStyle = ImplInitStyle( GetStyle() );
+ SetStyle( nStyle );
+ }
+
+ USHORT nOldAlign = mnAlign;
+ mnAlign = EDIT_ALIGN_LEFT;
+
+ // --- RTL --- hack: right align until keyinput and cursor travelling works
+ // edits are always RTL disabled
+ // however the parent edits contain the correct setting
+ if( mbIsSubEdit && GetParent()->IsRTLEnabled() )
+ {
+ if( GetParent()->GetStyle() & WB_LEFT )
+ mnAlign = EDIT_ALIGN_RIGHT;
+ if ( nType == STATE_CHANGE_MIRRORING )
+ SetLayoutMode( TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT );
+ }
+ else if( mbIsSubEdit && !GetParent()->IsRTLEnabled() )
+ {
+ if ( nType == STATE_CHANGE_MIRRORING )
+ SetLayoutMode( TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT );
+ }
+
+ if ( nStyle & WB_RIGHT )
+ mnAlign = EDIT_ALIGN_RIGHT;
+ else if ( nStyle & WB_CENTER )
+ mnAlign = EDIT_ALIGN_CENTER;
+ if ( maText.Len() && ( mnAlign != nOldAlign ) )
+ {
+ ImplAlign();
+ Invalidate();
+ }
+
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ if ( !mpSubEdit )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ ImplShowCursor( TRUE );
+ Invalidate();
+ }
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ if ( !mpSubEdit )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ ImplShowCursor();
+ Invalidate();
+ }
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ if ( !mpSubEdit )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ if ( !mpSubEdit )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+ }
+
+ Control::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ if ( !mpSubEdit )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ ImplShowCursor( TRUE );
+ Invalidate();
+ }
+ }
+
+ Control::DataChanged( rDCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplShowDDCursor()
+{
+ if ( !mpDDInfo->bVisCursor )
+ {
+ long nTextWidth = GetTextWidth( maText, 0, mpDDInfo->nDropPos );
+ long nTextHeight = GetTextHeight();
+ Rectangle aCursorRect( Point( nTextWidth + mnXOffset, (GetOutputSize().Height()-nTextHeight)/2 ), Size( 2, nTextHeight ) );
+ mpDDInfo->aCursor.SetWindow( this );
+ mpDDInfo->aCursor.SetPos( aCursorRect.TopLeft() );
+ mpDDInfo->aCursor.SetSize( aCursorRect.GetSize() );
+ mpDDInfo->aCursor.Show();
+ mpDDInfo->bVisCursor = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplHideDDCursor()
+{
+ if ( mpDDInfo && mpDDInfo->bVisCursor )
+ {
+ mpDDInfo->aCursor.Hide();
+ mpDDInfo->bVisCursor = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Modify()
+{
+ if ( mbIsSubEdit )
+ {
+ ((Edit*)GetParent())->Modify();
+ }
+ else
+ {
+ if ( mpUpdateDataTimer )
+ mpUpdateDataTimer->Start();
+
+ if ( ImplCallEventListenersAndHandler( VCLEVENT_EDIT_MODIFY, maModifyHdl, this ) )
+ // have been destroyed while calling into the handlers
+ return;
+
+ // #i13677# notify edit listeners about caret position change
+ ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
+
+ // FIXME: this is currently only on aqua
+ // check for other platforms that need similar handling
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
+ {
+ ImplInvalidateOutermostBorder( this );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::UpdateData()
+{
+ maUpdateDataHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Edit, ImplUpdateDataHdl, Timer*, EMPTYARG )
+{
+ UpdateData();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::EnableUpdateData( ULONG nTimeout )
+{
+ if ( !nTimeout )
+ DisableUpdateData();
+ else
+ {
+ if ( !mpUpdateDataTimer )
+ {
+ mpUpdateDataTimer = new Timer;
+ mpUpdateDataTimer->SetTimeoutHdl( LINK( this, Edit, ImplUpdateDataHdl ) );
+ }
+
+ mpUpdateDataTimer->SetTimeout( nTimeout );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetEchoChar( xub_Unicode c )
+{
+ mcEchoChar = c;
+ if ( mpSubEdit )
+ mpSubEdit->SetEchoChar( c );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetReadOnly( BOOL bReadOnly )
+{
+ if ( mbReadOnly != bReadOnly )
+ {
+ mbReadOnly = bReadOnly;
+ if ( mpSubEdit )
+ mpSubEdit->SetReadOnly( bReadOnly );
+
+ StateChanged( STATE_CHANGE_READONLY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetAutocompleteHdl( const Link& rHdl )
+{
+ maAutocompleteHdl = rHdl;
+ if ( mpSubEdit )
+ mpSubEdit->SetAutocompleteHdl( rHdl );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetInsertMode( BOOL bInsert )
+{
+ if ( bInsert != mbInsertMode )
+ {
+ mbInsertMode = bInsert;
+ if ( mpSubEdit )
+ mpSubEdit->SetInsertMode( bInsert );
+ else
+ ImplShowCursor();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Edit::IsInsertMode() const
+{
+ if ( mpSubEdit )
+ return mpSubEdit->IsInsertMode();
+ else
+ return mbInsertMode;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetMaxTextLen( xub_StrLen nMaxLen )
+{
+ mnMaxTextLen = nMaxLen ? nMaxLen : EDIT_NOLIMIT;
+
+ if ( mpSubEdit )
+ mpSubEdit->SetMaxTextLen( mnMaxTextLen );
+ else
+ {
+ if ( maText.Len() > mnMaxTextLen )
+ ImplDelete( Selection( mnMaxTextLen, maText.Len() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetSelection( const Selection& rSelection )
+{
+ // Wenn von aussen z.B. im MouseButtonDown die Selektion geaendert wird,
+ // soll nicht gleich ein Tracking() zuschlagen und die Selektion aendern.
+ if ( IsTracking() )
+ EndTracking();
+ else if ( mpSubEdit && mpSubEdit->IsTracking() )
+ mpSubEdit->EndTracking();
+
+ ImplSetSelection( rSelection );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ImplSetSelection( const Selection& rSelection, BOOL bPaint )
+{
+ if ( mpSubEdit )
+ mpSubEdit->ImplSetSelection( rSelection );
+ else
+ {
+ if ( rSelection != maSelection )
+ {
+ Selection aOld( maSelection );
+ Selection aNew( rSelection );
+
+ if ( aNew.Min() > maText.Len() )
+ aNew.Min() = maText.Len();
+ if ( aNew.Max() > maText.Len() )
+ aNew.Max() = maText.Len();
+ if ( aNew.Min() < 0 )
+ aNew.Min() = 0;
+ if ( aNew.Max() < 0 )
+ aNew.Max() = 0;
+
+ if ( aNew != maSelection )
+ {
+ ImplClearLayoutData();
+ maSelection = aNew;
+
+ if ( bPaint && ( aOld.Len() || aNew.Len() || IsPaintTransparent() ) )
+ ImplInvalidateOrRepaint( 0, maText.Len() );
+ ImplShowCursor();
+ if ( mbIsSubEdit )
+ ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
+ else
+ ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
+ // #103511# notify combobox listeners of deselection
+ if( !maSelection && GetParent() && GetParent()->GetType() == WINDOW_COMBOBOX )
+ ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_COMBOBOX_DESELECT );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Selection& Edit::GetSelection() const
+{
+ if ( mpSubEdit )
+ return mpSubEdit->GetSelection();
+ else
+ return maSelection;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ReplaceSelected( const XubString& rStr )
+{
+ if ( mpSubEdit )
+ mpSubEdit->ReplaceSelected( rStr );
+ else
+ ImplInsertText( rStr );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::DeleteSelected()
+{
+ if ( mpSubEdit )
+ mpSubEdit->DeleteSelected();
+ else
+ {
+ if ( maSelection.Len() )
+ ImplDelete( maSelection, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString Edit::GetSelected() const
+{
+ if ( mpSubEdit )
+ return mpSubEdit->GetSelected();
+ else
+ {
+ Selection aSelection( maSelection );
+ aSelection.Justify();
+ return maText.Copy( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Cut()
+{
+ if ( !(GetStyle() & WB_PASSWORD ) )
+ {
+ Copy();
+ ReplaceSelected( ImplGetSVEmptyStr() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Copy()
+{
+ if ( !(GetStyle() & WB_PASSWORD ) )
+ {
+ ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
+ ImplCopy( aClipboard );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Paste()
+{
+ ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
+ ImplPaste( aClipboard );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::Undo()
+{
+ if ( mpSubEdit )
+ mpSubEdit->Undo();
+ else
+ {
+ XubString aText( maText );
+ ImplDelete( Selection( 0, aText.Len() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
+ ImplInsertText( maUndoText );
+ ImplSetSelection( Selection( 0, maUndoText.Len() ) );
+ maUndoText = aText;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetText( const XubString& rStr )
+{
+ if ( mpSubEdit )
+ mpSubEdit->SetText( rStr ); // Nicht direkt ImplSetText, falls SetText ueberladen
+ else
+ {
+ Selection aNewSel( 0, 0 ); // Damit nicht gescrollt wird
+ ImplSetText( rStr, &aNewSel );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetText( const XubString& rStr, const Selection& rSelection )
+{
+ if ( mpSubEdit )
+ mpSubEdit->SetText( rStr, rSelection );
+ else
+ ImplSetText( rStr, &rSelection );
+}
+
+// -----------------------------------------------------------------------
+
+XubString Edit::GetText() const
+{
+ if ( mpSubEdit )
+ return mpSubEdit->GetText();
+ else
+ return maText;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetModifyFlag()
+{
+ if ( mpSubEdit )
+ mpSubEdit->mbModified = TRUE;
+ else
+ mbModified = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::ClearModifyFlag()
+{
+ if ( mpSubEdit )
+ mpSubEdit->mbModified = FALSE;
+ else
+ mbModified = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetSubEdit( Edit* pEdit )
+{
+ mpSubEdit = pEdit;
+ if ( mpSubEdit )
+ {
+ SetPointer( POINTER_ARROW ); // Nur das SubEdit hat den BEAM...
+ mpSubEdit->mbIsSubEdit = TRUE;
+
+ mpSubEdit->SetReadOnly( mbReadOnly );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size Edit::CalcMinimumSize() const
+{
+ Size aSize ( GetTextWidth( GetText() ), GetTextHeight() );
+ // do not create edit fields in which one cannot enter anything
+ // a default minimum width should exist for at least 3 characters
+ Size aMinSize ( CalcSize( 3 ) );
+ if( aSize.Width() < aMinSize.Width() )
+ aSize.Width() = aMinSize.Width();
+ // add some space between text entry and border
+ aSize.Height() += 4;
+
+ aSize = CalcWindowSize( aSize );
+
+ // ask NWF what if it has an opinion, too
+ ImplControlValue aControlValue;
+ Rectangle aRect( Point( 0, 0 ), aSize );
+ Rectangle aContent, aBound;
+ if( const_cast<Edit*>(this)->GetNativeControlRegion(
+ CTRL_EDITBOX, PART_ENTIRE_CONTROL,
+ aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ if( aBound.GetHeight() > aSize.Height() )
+ aSize.Height() = aBound.GetHeight();
+ }
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+Size Edit::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Control::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size Edit::CalcSize( xub_StrLen nChars ) const
+{
+ // Breite fuer n Zeichen, unabhaengig vom Inhalt.
+ // Funktioniert nur bei FixedFont richtig, sonst Mittelwert.
+ Size aSz( GetTextWidth( XubString( 'x' ) ), GetTextHeight() );
+ aSz.Width() *= nChars;
+ aSz = CalcWindowSize( aSz );
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen Edit::GetMaxVisChars() const
+{
+ const Window* pW = mpSubEdit ? mpSubEdit : this;
+ long nOutWidth = pW->GetOutputSizePixel().Width();
+ long nCharWidth = GetTextWidth( XubString( 'x' ) );
+ return nCharWidth ? (xub_StrLen)(nOutWidth/nCharWidth) : 0;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen Edit::GetCharPos( const Point& rWindowPos ) const
+{
+ return ImplGetCharPos( rWindowPos );
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::SetGetSpecialCharsFunction( FncGetSpecialChars fn )
+{
+ pImplFncGetSpecialChars = fn;
+}
+
+// -----------------------------------------------------------------------
+
+FncGetSpecialChars Edit::GetGetSpecialCharsFunction()
+{
+ return pImplFncGetSpecialChars;
+}
+
+// -----------------------------------------------------------------------
+
+PopupMenu* Edit::CreatePopupMenu()
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( ! pResMgr )
+ return new PopupMenu();
+
+ PopupMenu* pPopup = new PopupMenu( ResId( SV_RESID_MENU_EDIT, *pResMgr ) );
+ pPopup->SetAccelKey( SV_MENU_EDIT_UNDO, KeyCode( KEYFUNC_UNDO ) );
+ pPopup->SetAccelKey( SV_MENU_EDIT_CUT, KeyCode( KEYFUNC_CUT ) );
+ pPopup->SetAccelKey( SV_MENU_EDIT_COPY, KeyCode( KEYFUNC_COPY ) );
+ pPopup->SetAccelKey( SV_MENU_EDIT_PASTE, KeyCode( KEYFUNC_PASTE ) );
+ pPopup->SetAccelKey( SV_MENU_EDIT_DELETE, KeyCode( KEYFUNC_DELETE ) );
+ pPopup->SetAccelKey( SV_MENU_EDIT_SELECTALL, KeyCode( KEY_A, FALSE, TRUE, FALSE, FALSE ) );
+ pPopup->SetAccelKey( SV_MENU_EDIT_INSERTSYMBOL, KeyCode( KEY_S, TRUE, TRUE, FALSE, FALSE ) );
+ return pPopup;
+}
+
+// -----------------------------------------------------------------------
+
+void Edit::DeletePopupMenu( PopupMenu* pMenu )
+{
+ delete pMenu;
+}
+
+// ::com::sun::star::datatransfer::dnd::XDragGestureListener
+void Edit::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ if ( !IsTracking() && maSelection.Len() &&
+ !(GetStyle() & WB_PASSWORD) && (!mpDDInfo || mpDDInfo->bStarterOfDD == FALSE) ) // Kein Mehrfach D&D
+ {
+ Selection aSel( maSelection );
+ aSel.Justify();
+
+ // Nur wenn Maus in der Selektion...
+ Point aMousePos( rDGE.DragOriginX, rDGE.DragOriginY );
+ xub_StrLen nChar = ImplGetCharPos( aMousePos );
+ if ( (nChar >= aSel.Min()) && (nChar < aSel.Max()) )
+ {
+ if ( !mpDDInfo )
+ mpDDInfo = new DDInfo;
+
+ mpDDInfo->bStarterOfDD = TRUE;
+ mpDDInfo->aDndStartSel = aSel;
+
+
+ if ( IsTracking() )
+ EndTracking(); // Vor D&D Tracking ausschalten
+
+ ::vcl::unohelper::TextDataObject* pDataObj = new ::vcl::unohelper::TextDataObject( GetSelected() );
+ sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
+ if ( !IsReadOnly() )
+ nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
+ rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mxDnDListener );
+ if ( GetCursor() )
+ GetCursor()->Hide();
+
+ }
+ }
+}
+
+// ::com::sun::star::datatransfer::dnd::XDragSourceListener
+void Edit::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ if ( rDSDE.DropSuccess && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
+ {
+ Selection aSel( mpDDInfo->aDndStartSel );
+ if ( mpDDInfo->bDroppedInMe )
+ {
+ if ( aSel.Max() > mpDDInfo->nDropPos )
+ {
+ long nLen = aSel.Len();
+ aSel.Min() += nLen;
+ aSel.Max() += nLen;
+ }
+ }
+ ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
+ ImplModified();
+ }
+
+ ImplHideDDCursor();
+ delete mpDDInfo;
+ mpDDInfo = NULL;
+}
+
+// ::com::sun::star::datatransfer::dnd::XDropTargetListener
+void Edit::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ BOOL bChanges = FALSE;
+ if ( !mbReadOnly && mpDDInfo )
+ {
+ ImplHideDDCursor();
+
+ Selection aSel( maSelection );
+ aSel.Justify();
+
+ if ( aSel.Len() && !mpDDInfo->bStarterOfDD )
+ ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
+
+ mpDDInfo->bDroppedInMe = TRUE;
+
+ aSel.Min() = mpDDInfo->nDropPos;
+ aSel.Max() = mpDDInfo->nDropPos;
+ ImplSetSelection( aSel );
+
+ uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
+ if ( xDataObj.is() )
+ {
+ datatransfer::DataFlavor aFlavor;
+ SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
+ if ( xDataObj->isDataFlavorSupported( aFlavor ) )
+ {
+ uno::Any aData = xDataObj->getTransferData( aFlavor );
+ ::rtl::OUString aText;
+ aData >>= aText;
+ ImplInsertText( aText );
+ bChanges = TRUE;
+ ImplModified();
+ }
+ }
+
+ if ( !mpDDInfo->bStarterOfDD )
+ {
+ delete mpDDInfo;
+ mpDDInfo = NULL;
+ }
+ }
+
+ rDTDE.Context->dropComplete( bChanges );
+}
+
+void Edit::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( !mpDDInfo )
+ {
+ mpDDInfo = new DDInfo;
+ }
+// sal_Bool bTextContent = mbReadOnly ? sal_False : sal_True; // quiery from rDTDEE.SupportedDataFlavors()
+// if ( bTextContent )
+// rDTDEE.Context->acceptDrop(datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE);
+// else
+// rDTDEE.Context->rejectDrop();
+}
+
+void Edit::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ ImplHideDDCursor();
+}
+
+void Edit::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
+
+ xub_StrLen nPrevDropPos = mpDDInfo->nDropPos;
+ mpDDInfo->nDropPos = ImplGetCharPos( aMousePos );
+
+ /*
+ Size aOutSize = GetOutputSizePixel();
+ if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
+ {
+ // Scroll?
+ // No, I will not receive events in this case....
+ }
+ */
+
+ Selection aSel( maSelection );
+ aSel.Justify();
+
+ // Don't accept drop in selection or read-only field...
+ if ( IsReadOnly() || aSel.IsInside( mpDDInfo->nDropPos ) )
+ {
+ ImplHideDDCursor();
+ rDTDE.Context->rejectDrag();
+ }
+ else
+ {
+ // Alten Cursor wegzeichnen...
+ if ( !mpDDInfo->bVisCursor || ( nPrevDropPos != mpDDInfo->nDropPos ) )
+ {
+ ImplHideDDCursor();
+ ImplShowDDCursor();
+ }
+ rDTDE.Context->acceptDrag( rDTDE.DropAction );
+ }
+}
+
+ImplSubEdit::ImplSubEdit( Edit* pParent, WinBits nStyle ) :
+ Edit( pParent, nStyle )
+{
+ pParent->SetSubEdit( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSubEdit::Modify()
+{
+ GetParent()->Modify();
+}
+
+XubString Edit::GetSurroundingText() const
+{
+ if ( mpSubEdit )
+ return mpSubEdit->GetSurroundingText();
+ else
+ return maText;
+}
+
+Selection Edit::GetSurroundingTextSelection() const
+{
+ return GetSelection();
+}
diff --git a/vcl/source/control/field.cxx b/vcl/source/control/field.cxx
new file mode 100644
index 000000000000..090aa2a84163
--- /dev/null
+++ b/vcl/source/control/field.cxx
@@ -0,0 +1,2474 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _BIGINT_HXX
+#define _TOOLS_BIGINT
+#include "tools/bigint.hxx"
+#endif
+
+#include "tools/debug.hxx"
+
+#include "tools/rc.h"
+#include "tools/resary.hxx"
+#include "vcl/svids.hrc"
+#include "vcl/field.hxx"
+#include "vcl/event.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/unohelp.hxx"
+#include "i18nutil/unicode.hxx"
+
+#include "rtl/math.hxx"
+
+
+#include <unotools/localedatawrapper.hxx>
+
+using namespace ::com::sun::star;
+
+static ResStringArray *strAllUnits = NULL;
+
+// -----------------------------------------------------------------------
+
+#define FORMAT_NUMERIC 1
+#define FORMAT_METRIC 2
+#define FORMAT_CURRENCY 3
+
+// -----------------------------------------------------------------------
+
+static sal_Int64 ImplPower10( USHORT n )
+{
+ USHORT i;
+ sal_Int64 nValue = 1;
+
+ for ( i=0; i < n; i++ )
+ nValue *= 10;
+
+ return nValue;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplNumericProcessKeyInput( Edit*, const KeyEvent& rKEvt,
+ BOOL bStrictFormat, BOOL bThousandSep,
+ const LocaleDataWrapper& rLocaleDataWrappper )
+{
+ if ( !bStrictFormat )
+ return FALSE;
+ else
+ {
+ xub_Unicode cChar = rKEvt.GetCharCode();
+ USHORT nGroup = rKEvt.GetKeyCode().GetGroup();
+
+ if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
+ (nGroup == KEYGROUP_MISC) ||
+ ((cChar >= '0') && (cChar <= '9')) ||
+ (cChar == rLocaleDataWrappper.getNumDecimalSep() ) ||
+ (bThousandSep && (cChar == rLocaleDataWrappper.getNumThousandSep())) ||
+ (cChar == '-') )
+ return FALSE;
+ else
+ return TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplNumericGetValue( const XubString& rStr, double& rValue,
+ USHORT nDecDigits, const LocaleDataWrapper& rLocaleDataWrappper,
+ BOOL bCurrency = FALSE )
+{
+ XubString aStr = rStr;
+ XubString aStr1;
+ XubString aStr2;
+ BOOL bNegative = FALSE;
+ xub_StrLen nDecPos;
+ xub_StrLen i;
+
+ // Reaktion auf leeren String
+ if ( !rStr.Len() )
+ return FALSE;
+
+ // Fuehrende und nachfolgende Leerzeichen entfernen
+ aStr.EraseLeadingAndTrailingChars( ' ' );
+
+ // Position des Dezimalpunktes suchen
+ nDecPos = aStr.Search( rLocaleDataWrappper.getNumDecimalSep() );
+ if ( nDecPos != STRING_NOTFOUND )
+ {
+ aStr1 = aStr.Copy( 0, nDecPos );
+ aStr2 = aStr.Copy( nDecPos+1 );
+ }
+ else
+ aStr1 = aStr;
+
+ // Negativ ?
+ if ( bCurrency )
+ {
+ if ( (aStr.GetChar( 0 ) == '(') && (aStr.GetChar( aStr.Len()-1 ) == ')') )
+ bNegative = TRUE;
+ if ( !bNegative )
+ {
+ for ( i=0; i < aStr.Len(); i++ )
+ {
+ if ( (aStr.GetChar( i ) >= '0') && (aStr.GetChar( i ) <= '9') )
+ break;
+ else if ( aStr.GetChar( i ) == '-' )
+ {
+ bNegative = TRUE;
+ break;
+ }
+ }
+ }
+ if ( !bNegative && bCurrency && aStr.Len() )
+ {
+ USHORT nFormat = rLocaleDataWrappper.getCurrNegativeFormat();
+ if ( (nFormat == 3) || (nFormat == 6) ||
+ (nFormat == 7) || (nFormat == 10) )
+ {
+ for ( i = (xub_StrLen)(aStr.Len()-1); i > 0; i++ )
+ {
+ if ( (aStr.GetChar( i ) >= '0') && (aStr.GetChar( i ) <= '9') )
+ break;
+ else if ( aStr.GetChar( i ) == '-' )
+ {
+ bNegative = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( aStr1.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ }
+
+ // Alle unerwuenschten Zeichen rauswerfen
+ for ( i=0; i < aStr1.Len(); )
+ {
+ if ( (aStr1.GetChar( i ) >= '0') && (aStr1.GetChar( i ) <= '9') )
+ i++;
+ else
+ aStr1.Erase( i, 1 );
+ }
+ for ( i=0; i < aStr2.Len(); )
+ {
+ if ( (aStr2.GetChar( i ) >= '0') && (aStr2.GetChar( i ) <= '9') )
+ i++;
+ else
+ aStr2.Erase( i, 1 );
+ }
+
+ if ( !aStr1.Len() && !aStr2.Len() )
+ return FALSE;
+
+ if ( !aStr1.Len() )
+ aStr1.Insert( '0' );
+ if ( bNegative )
+ aStr1.Insert( '-', 0 );
+
+ // Nachkommateil zurechtstutzen und dabei runden
+ BOOL bRound = FALSE;
+ if ( aStr2.Len() > nDecDigits )
+ {
+ if ( aStr2.GetChar( nDecDigits ) >= '5' )
+ bRound = TRUE;
+ aStr2.Erase( nDecDigits );
+ }
+ if ( aStr2.Len() < nDecDigits )
+ aStr2.Expand( nDecDigits, '0' );
+
+ aStr = aStr1;
+ aStr += aStr2;
+
+ // Bereichsueberpruefung
+ double nValue = aStr.ToDouble();
+ if ( bRound )
+ {
+ if ( !bNegative )
+ nValue++;
+ else
+ nValue--;
+ }
+
+ rValue = nValue;
+
+ return TRUE;
+}
+
+static void ImplUpdateSeparators( const String& rOldDecSep, const String& rNewDecSep,
+ const String& rOldThSep, const String& rNewThSep,
+ Edit* pEdit )
+{
+ bool bChangeDec = (rOldDecSep != rNewDecSep);
+ bool bChangeTh = (rOldThSep != rNewThSep );
+
+ if( bChangeDec || bChangeTh )
+ {
+ BOOL bUpdateMode = pEdit->IsUpdateMode();
+ pEdit->SetUpdateMode( FALSE );
+ String aText = pEdit->GetText();
+ if( bChangeDec )
+ aText.SearchAndReplaceAll( rNewDecSep, rOldDecSep );
+ if( bChangeTh )
+ aText.SearchAndReplaceAll( rNewThSep, rOldThSep );
+ pEdit->SetText( aText );
+
+ ComboBox* pCombo = dynamic_cast<ComboBox*>(pEdit);
+ if( pCombo )
+ {
+ // update box entries
+ USHORT nEntryCount = pCombo->GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ aText = pCombo->GetEntry( i );
+ if( bChangeDec )
+ aText.SearchAndReplaceAll( rNewDecSep, rOldDecSep );
+ if( bChangeTh )
+ aText.SearchAndReplaceAll( rNewThSep, rOldThSep );
+ pCombo->RemoveEntry( i );
+ pCombo->InsertEntry( aText, i );
+ }
+ }
+ if( bUpdateMode )
+ pEdit->SetUpdateMode( bUpdateMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FormatterBase::FormatterBase( Edit* pField )
+{
+ mpField = pField;
+ mpLocaleDataWrapper = NULL;
+ mbReformat = FALSE;
+ mbStrictFormat = FALSE;
+ mbEmptyFieldValue = FALSE;
+ mbEmptyFieldValueEnabled = FALSE;
+ mbDefaultLocale = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+FormatterBase::~FormatterBase()
+{
+ delete mpLocaleDataWrapper;
+}
+
+// -----------------------------------------------------------------------
+
+LocaleDataWrapper& FormatterBase::ImplGetLocaleDataWrapper() const
+{
+ if ( !mpLocaleDataWrapper )
+ {
+ ((FormatterBase*)this)->mpLocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetLocale() );
+ }
+ return *mpLocaleDataWrapper;
+}
+
+const LocaleDataWrapper& FormatterBase::GetLocaleDataWrapper() const
+{
+ return ImplGetLocaleDataWrapper();
+}
+
+// -----------------------------------------------------------------------
+
+void FormatterBase::Reformat()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void FormatterBase::ReformatAll()
+{
+ Reformat();
+};
+
+// -----------------------------------------------------------------------
+
+void FormatterBase::SetStrictFormat( BOOL bStrict )
+{
+ if ( bStrict != mbStrictFormat )
+ {
+ mbStrictFormat = bStrict;
+ if ( mbStrictFormat )
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FormatterBase::SetLocale( const lang::Locale& rLocale )
+{
+ ImplGetLocaleDataWrapper().setLocale( rLocale );
+ mbDefaultLocale = FALSE;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+const lang::Locale& FormatterBase::GetLocale() const
+{
+ if ( !mpLocaleDataWrapper || mbDefaultLocale )
+ {
+ if ( mpField )
+ return mpField->GetSettings().GetLocale();
+ else
+ return Application::GetSettings().GetLocale();
+ }
+
+ return mpLocaleDataWrapper->getLocale();
+}
+
+// -----------------------------------------------------------------------
+
+const AllSettings& FormatterBase::GetFieldSettings() const
+{
+ if ( mpField )
+ return mpField->GetSettings();
+ else
+ return Application::GetSettings();
+}
+
+// -----------------------------------------------------------------------
+
+void FormatterBase::SetFieldText( const XubString& rText, BOOL bKeepSelection )
+{
+ if ( mpField )
+ {
+ Selection aNewSelection( 0xFFFF, 0xFFFF );
+ if ( bKeepSelection )
+ aNewSelection = mpField->GetSelection();
+
+ ImplSetText( rText, &aNewSelection );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FormatterBase::ImplSetText( const XubString& rText, Selection* pNewSelection )
+{
+ if ( mpField )
+ {
+ if ( pNewSelection )
+ mpField->SetText( rText, *pNewSelection );
+ else
+ {
+ Selection aSel = mpField->GetSelection();
+ aSel.Min() = aSel.Max();
+ mpField->SetText( rText, aSel );
+ }
+
+ MarkToBeReformatted( FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FormatterBase::SetEmptyFieldValue()
+{
+ if ( mpField )
+ mpField->SetText( ImplGetSVEmptyStr() );
+ mbEmptyFieldValue = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FormatterBase::IsEmptyFieldValue() const
+{
+ return (!mpField || !mpField->GetText().Len());
+}
+
+// -----------------------------------------------------------------------
+
+BOOL NumericFormatter::ImplNumericReformat( const XubString& rStr, double& rValue,
+ XubString& rOutStr )
+{
+ if ( !ImplNumericGetValue( rStr, rValue, GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
+ return TRUE;
+ else
+ {
+ double nTempVal = rValue;
+ // caution: precision loss in double cast
+ if ( nTempVal > mnMax )
+ nTempVal = (double)mnMax;
+ else if ( nTempVal < mnMin )
+ nTempVal = (double)mnMin;
+
+ if ( GetErrorHdl().IsSet() && (rValue != nTempVal) )
+ {
+ mnCorrectedValue = (sal_Int64)nTempVal;
+ if ( !GetErrorHdl().Call( this ) )
+ {
+ mnCorrectedValue = 0;
+ return FALSE;
+ }
+ else
+ mnCorrectedValue = 0;
+ }
+
+ rOutStr = CreateFieldText( (sal_Int64)nTempVal );
+ return TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::ImplInit()
+{
+ mnFieldValue = 0;
+ mnLastValue = 0;
+ mnMin = 0;
+ mnMax = 0x7FFFFFFFFFFFFFFFLL;
+ mnCorrectedValue = 0;
+ mnDecimalDigits = 2;
+ mnType = FORMAT_NUMERIC;
+ mbThousandSep = TRUE;
+ mbShowTrailingZeros = TRUE;
+
+ // for fields
+ mnSpinSize = 1;
+ mnFirst = mnMin;
+ mnLast = mnMax;
+
+ SetDecimalDigits( 0 );
+}
+
+// -----------------------------------------------------------------------
+
+NumericFormatter::NumericFormatter()
+{
+ ImplInit();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::ImplLoadRes( const ResId& rResId )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+
+ if( pMgr )
+ {
+ ULONG nMask = pMgr->ReadLong();
+
+ if ( NUMERICFORMATTER_MIN & nMask )
+ mnMin = pMgr->ReadLong();
+
+ if ( NUMERICFORMATTER_MAX & nMask )
+ mnMax = pMgr->ReadLong();
+
+ if ( NUMERICFORMATTER_STRICTFORMAT & nMask )
+ SetStrictFormat( (BOOL)pMgr->ReadShort() );
+
+ if ( NUMERICFORMATTER_DECIMALDIGITS & nMask )
+ SetDecimalDigits( pMgr->ReadShort() );
+
+ if ( NUMERICFORMATTER_VALUE & nMask )
+ {
+ mnFieldValue = pMgr->ReadLong();
+ if ( mnFieldValue > mnMax )
+ mnFieldValue = mnMax;
+ else if ( mnFieldValue < mnMin )
+ mnFieldValue = mnMin;
+ mnLastValue = mnFieldValue;
+ }
+
+ if ( NUMERICFORMATTER_NOTHOUSANDSEP & nMask )
+ SetUseThousandSep( !(BOOL)pMgr->ReadShort() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+NumericFormatter::~NumericFormatter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::SetMin( sal_Int64 nNewMin )
+{
+ mnMin = nNewMin;
+ if ( !IsEmptyFieldValue() )
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::SetMax( sal_Int64 nNewMax )
+{
+ mnMax = nNewMax;
+ if ( !IsEmptyFieldValue() )
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::SetUseThousandSep( BOOL b )
+{
+ mbThousandSep = b;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::SetDecimalDigits( USHORT nDigits )
+{
+ mnDecimalDigits = nDigits;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::SetShowTrailingZeros( BOOL bShowTrailingZeros )
+{
+ if ( mbShowTrailingZeros != bShowTrailingZeros )
+ {
+ mbShowTrailingZeros = bShowTrailingZeros;
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT NumericFormatter::GetDecimalDigits() const
+{
+ return mnDecimalDigits;
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::SetValue( sal_Int64 nNewValue )
+{
+ SetUserValue( nNewValue );
+ mnFieldValue = mnLastValue;
+ SetEmptyFieldValueData( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+XubString NumericFormatter::CreateFieldText( sal_Int64 nValue ) const
+{
+ return ImplGetLocaleDataWrapper().getNum( nValue, GetDecimalDigits(), IsUseThousandSep(), IsShowTrailingZeros() );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::ImplSetUserValue( sal_Int64 nNewValue, Selection* pNewSelection )
+{
+ if ( nNewValue > mnMax )
+ nNewValue = mnMax;
+ else if ( nNewValue < mnMin )
+ nNewValue = mnMin;
+ mnLastValue = nNewValue;
+
+ if ( GetField() )
+ ImplSetText( CreateFieldText( nNewValue ), pNewSelection );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::SetUserValue( sal_Int64 nNewValue )
+{
+ ImplSetUserValue( nNewValue );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 NumericFormatter::GetValue() const
+{
+ if ( !GetField() )
+ return 0;
+
+ double nTempValue;
+
+ if ( ImplNumericGetValue( GetField()->GetText(), nTempValue,
+ GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
+ {
+ // caution: precision loss in double cast
+ if ( nTempValue > mnMax )
+ nTempValue = (double)mnMax;
+ else if ( nTempValue < mnMin )
+ nTempValue = (double)mnMin;
+ return (sal_Int64)nTempValue;
+ }
+ else
+ return mnLastValue;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL NumericFormatter::IsValueModified() const
+{
+ if ( ImplGetEmptyFieldValue() )
+ return !IsEmptyFieldValue();
+ else if ( GetValue() != mnFieldValue )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Fraction NumericFormatter::ConvertToFraction( sal_Int64 nValue )
+{
+ // caution: precision loss in double cast (and in fraction anyhow)
+ return Fraction( (double)nValue/(double)ImplPower10( GetDecimalDigits() ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 NumericFormatter::ConvertToLong( const Fraction& rValue )
+{
+ Fraction aFract = rValue;
+ aFract *= Fraction( (long)ImplPower10( GetDecimalDigits() ), 1 );
+ return (sal_Int64)(double)aFract;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 NumericFormatter::Normalize( sal_Int64 nValue ) const
+{
+ return (nValue * ImplPower10( GetDecimalDigits() ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 NumericFormatter::Denormalize( sal_Int64 nValue ) const
+{
+ sal_Int64 nFactor = ImplPower10( GetDecimalDigits() );
+ if( nValue < 0 )
+ return ((nValue-(nFactor/2)) / nFactor );
+ else
+ return ((nValue+(nFactor/2)) / nFactor );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::Reformat()
+{
+ if ( !GetField() )
+ return;
+
+ if ( !GetField()->GetText().Len() && ImplGetEmptyFieldValue() )
+ return;
+
+ XubString aStr;
+ // caution: precision loss in double cast
+ double nTemp = (double)mnLastValue;
+ BOOL bOK = ImplNumericReformat( GetField()->GetText(), nTemp, aStr );
+ mnLastValue = (sal_Int64)nTemp;
+ if ( !bOK )
+ return;
+
+ if ( aStr.Len() )
+ ImplSetText( aStr );
+ else
+ SetValue( mnLastValue );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::FieldUp()
+{
+ sal_Int64 nValue = GetValue();
+ nValue += mnSpinSize;
+ if ( nValue > mnMax )
+ nValue = mnMax;
+
+ ImplNewFieldValue( nValue );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::FieldDown()
+{
+ sal_Int64 nValue = GetValue();
+ nValue -= mnSpinSize;
+ if ( nValue < mnMin )
+ nValue = mnMin;
+
+ ImplNewFieldValue( nValue );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::FieldFirst()
+{
+ ImplNewFieldValue( mnFirst );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::FieldLast()
+{
+ ImplNewFieldValue( mnLast );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericFormatter::ImplNewFieldValue( sal_Int64 nNewValue )
+{
+ if ( GetField() )
+ {
+ // !!! TH-18.2.99: Wenn wir Zeit haben sollte mal geklaert werden,
+ // !!! warum nicht bei ImplSetUserValue() geprueft wird, ob
+ // !!! sich der Wert aendert. Denn auch hier muesste dieses
+ // !!! gemacht werden, da ansonsten der Modify-Aufruf
+ // !!! nicht gemacht werden duerfte. Jedenfalls sollten die
+ // !!! Wege von ImplNewFieldValue, ImplSetUserValue und
+ // !!! ImplSetText ueberprueft und klarer gestalltet (mit Kommentar)
+ // !!! werden, damit wir mal wissen, was dort ablaeuft!!!
+
+ Selection aSelection = GetField()->GetSelection();
+ aSelection.Justify();
+ XubString aText = GetField()->GetText();
+ // Wenn bis ans Ende selektiert war, soll das auch so bleiben...
+ if ( (xub_StrLen)aSelection.Max() == aText.Len() )
+ {
+ if ( !aSelection.Len() )
+ aSelection.Min() = SELECTION_MAX;
+ aSelection.Max() = SELECTION_MAX;
+ }
+
+ sal_Int64 nOldLastValue = mnLastValue;
+ ImplSetUserValue( nNewValue, &aSelection );
+ mnLastValue = nOldLastValue;
+
+ // Modify am Edit wird nur bei KeyInput gesetzt...
+ if ( GetField()->GetText() != aText )
+ {
+ GetField()->SetModifyFlag();
+ GetField()->Modify();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+NumericField::NumericField( Window* pParent, WinBits nWinStyle ) :
+ SpinField( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+NumericField::NumericField( Window* pParent, const ResId& rResId ) :
+ SpinField( WINDOW_NUMERICFIELD )
+{
+ rResId.SetRT( RSC_NUMERICFIELD );
+ WinBits nStyle = ImplInitRes( rResId ) ;
+ SpinField::ImplInit( pParent, nStyle );
+ SetField( this );
+ ImplLoadRes( rResId );
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericField::ImplLoadRes( const ResId& rResId )
+{
+ SpinField::ImplLoadRes( rResId );
+ NumericFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+
+ ULONG nMask = ReadLongRes();
+
+ if ( NUMERICFIELD_FIRST & nMask )
+ mnFirst = ReadLongRes();
+
+ if ( NUMERICFIELD_LAST & nMask )
+ mnLast = ReadLongRes();
+
+ if ( NUMERICFIELD_SPINSIZE & nMask )
+ mnSpinSize = ReadLongRes();
+}
+
+// -----------------------------------------------------------------------
+
+NumericField::~NumericField()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long NumericField::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplNumericProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return SpinField::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long NumericField::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return SpinField::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SpinField::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ String sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ String sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void NumericField::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ SpinField::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericField::Up()
+{
+ FieldUp();
+ SpinField::Up();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericField::Down()
+{
+ FieldDown();
+ SpinField::Down();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericField::First()
+{
+ FieldFirst();
+ SpinField::First();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericField::Last()
+{
+ FieldLast();
+ SpinField::Last();
+}
+
+// -----------------------------------------------------------------------
+
+NumericBox::NumericBox( Window* pParent, WinBits nWinStyle ) :
+ ComboBox( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+NumericBox::NumericBox( Window* pParent, const ResId& rResId ) :
+ ComboBox( WINDOW_NUMERICBOX )
+{
+ rResId.SetRT( RSC_NUMERICBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ComboBox::ImplInit( pParent, nStyle );
+ SetField( this );
+ ComboBox::ImplLoadRes( rResId );
+ NumericFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+NumericBox::~NumericBox()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long NumericBox::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplNumericProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return ComboBox::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long NumericBox::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return ComboBox::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ ComboBox::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ String sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ String sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void NumericBox::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ ComboBox::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void NumericBox::ReformatAll()
+{
+ double nValue;
+ XubString aStr;
+ SetUpdateMode( FALSE );
+ USHORT nEntryCount = GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ ImplNumericReformat( GetEntry( i ), nValue, aStr );
+ RemoveEntry( i );
+ InsertEntry( aStr, i );
+ }
+ NumericFormatter::Reformat();
+ SetUpdateMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericBox::InsertValue( sal_Int64 nValue, USHORT nPos )
+{
+ ComboBox::InsertEntry( CreateFieldText( nValue ), nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void NumericBox::RemoveValue( sal_Int64 nValue )
+{
+ ComboBox::RemoveEntry( CreateFieldText( nValue ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 NumericBox::GetValue( USHORT nPos ) const
+{
+ double nValue = 0;
+ ImplNumericGetValue( ComboBox::GetEntry( nPos ), nValue, GetDecimalDigits(), ImplGetLocaleDataWrapper() );
+ return (sal_Int64)nValue;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT NumericBox::GetValuePos( sal_Int64 nValue ) const
+{
+ return ComboBox::GetEntryPos( CreateFieldText( nValue ) );
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplMetricProcessKeyInput( Edit* pEdit, const KeyEvent& rKEvt,
+ BOOL, BOOL bUseThousandSep, const LocaleDataWrapper& rWrapper )
+{
+ // Es gibt hier kein sinnvolles StrictFormat, also alle
+ // Zeichen erlauben
+ return ImplNumericProcessKeyInput( pEdit, rKEvt, FALSE, bUseThousandSep, rWrapper );
+}
+
+// -----------------------------------------------------------------------
+
+static XubString ImplMetricGetUnitText( const XubString& rStr )
+{
+ // Einheitentext holen
+ XubString aStr;
+ for ( short i = rStr.Len()-1; i >= 0; i-- )
+ {
+ xub_Unicode c = rStr.GetChar( i );
+ if ( unicode::isAlpha( c ) ||
+ (c == '\'') || (c == '\"') || (c == '%' ) )
+ aStr.Insert( c, 0 );
+ else
+ {
+ if ( aStr.Len() )
+ break;
+ }
+ }
+ return aStr;
+
+/*
+ // MT: #90545# Preparation for translated strings...
+ String aMetricText;
+ for ( USHORT n = rStr.Len(); n; )
+ {
+ sal_Unicode c = rStr.GetChar( --n );
+ sal_Int32 nType = xCharClass->getStringType( rStr, n, 1, rLocale );
+
+ if ( CharClass::isLetterType( nType ) )
+ {
+ aMetricText.Insert( c, 0 );
+ }
+ else
+ {
+ if ( aMetricText.Len() )
+ break;
+ }
+ }
+*/
+}
+
+// -----------------------------------------------------------------------
+
+// #104355# support localized mesaurements
+
+static String ImplMetricToString( FieldUnit rUnit )
+{
+ if( !strAllUnits )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ strAllUnits = new ResStringArray( ResId (SV_FUNIT_STRINGS, *pResMgr) );
+ }
+ // return unit's default string (ie, the first one )
+ for( USHORT i=0; i < strAllUnits->Count(); i++ )
+ if( (FieldUnit) strAllUnits->GetValue( i ) == rUnit )
+ return strAllUnits->GetString( i );
+
+ return String();
+}
+
+static FieldUnit ImplStringToMetric( const String &rMetricString )
+{
+ if( !strAllUnits )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ strAllUnits = new ResStringArray( ResId (SV_FUNIT_STRINGS, *pResMgr) );
+ }
+ // return FieldUnit
+ String aStr( rMetricString );
+ aStr.ToLowerAscii();
+ for( USHORT i=0; i < strAllUnits->Count(); i++ )
+ if ( strAllUnits->GetString( i ).Equals( aStr ) )
+ return (FieldUnit) strAllUnits->GetValue( i );
+
+ return FUNIT_NONE;
+}
+
+// -----------------------------------------------------------------------
+
+static FieldUnit ImplMetricGetUnit( const XubString& rStr )
+{
+ XubString aStr = ImplMetricGetUnitText( rStr );
+ return ImplStringToMetric( aStr );
+}
+
+#define K *1000L
+#define M *1000000L
+#define X *5280L
+
+static const sal_Int64 aImplFactor[FUNIT_MILE+1][FUNIT_MILE+1] =
+{ /*
+mm/100 mm cm m km twip point pica inch foot mile */
+{ 1, 100, 1 K, 100 K, 100 M, 2540, 2540, 2540, 2540,2540*12,2540*12 X },
+{ 1, 1, 10, 1 K, 1 M, 2540, 2540, 2540, 2540,2540*12,2540*12 X },
+{ 1, 1, 1, 100, 100 K, 254, 254, 254, 254, 254*12, 254*12 X },
+{ 1, 1, 1, 1, 1 K, 254, 254, 254, 254, 254*12, 254*12 X },
+{ 1, 1, 1, 1, 1, 0, 254, 254, 254, 254*12, 254*12 X },
+{ 1440,144 K,144 K,14400 K, 0, 1, 20, 240, 1440,1440*12,1440*12 X },
+{ 72, 7200, 7200, 720 K, 720 M, 1, 1, 12, 72, 72*12, 72*12 X },
+{ 6, 600, 600, 60 K, 60 M, 1, 1, 1, 6, 6*12, 6*12 X },
+{ 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 12, 12 X },
+{ 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 1, 1 X },
+{ 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 1, 1 }
+};
+
+#undef X
+#undef M
+#undef K
+// twip in km 254/14400 M
+
+static FieldUnit eDefaultUnit = FUNIT_NONE;
+
+FieldUnit MetricField::GetDefaultUnit() { return eDefaultUnit; }
+void MetricField::SetDefaultUnit( FieldUnit meUnit ) { eDefaultUnit = meUnit; }
+
+static FieldUnit ImplMap2FieldUnit( MapUnit meUnit, long& nDecDigits )
+{
+ switch( meUnit )
+ {
+ case MAP_100TH_MM :
+ nDecDigits -= 2;
+ return FUNIT_MM;
+ case MAP_10TH_MM :
+ nDecDigits -= 1;
+ return FUNIT_MM;
+ case MAP_MM :
+ return FUNIT_MM;
+ case MAP_CM :
+ return FUNIT_CM;
+ case MAP_1000TH_INCH :
+ nDecDigits -= 3;
+ return FUNIT_INCH;
+ case MAP_100TH_INCH :
+ nDecDigits -= 2;
+ return FUNIT_INCH;
+ case MAP_10TH_INCH :
+ nDecDigits -= 1;
+ return FUNIT_INCH;
+ case MAP_INCH :
+ return FUNIT_INCH;
+ case MAP_POINT :
+ return FUNIT_POINT;
+ case MAP_TWIP :
+ return FUNIT_TWIP;
+ default:
+ DBG_ERROR( "default eInUnit" );
+ break;
+ }
+ return FUNIT_NONE;
+}
+
+// -----------------------------------------------------------------------
+
+static double nonValueDoubleToValueDouble( double nValue )
+{
+ return rtl::math::isFinite( nValue ) ? nValue : 0.0;
+}
+
+sal_Int64 MetricField::ConvertValue( sal_Int64 nValue, sal_Int64 mnBaseValue, USHORT nDecDigits,
+ FieldUnit eInUnit, FieldUnit eOutUnit )
+{
+ // caution: precision loss in double cast
+ return static_cast<sal_Int64>(
+ // #150733# cast double to sal_Int64 can throw a
+ // EXCEPTION_FLT_INVALID_OPERATION on Windows
+ nonValueDoubleToValueDouble(
+ ConvertDoubleValue( (double)nValue, mnBaseValue, nDecDigits,
+ eInUnit, eOutUnit ) ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricField::ConvertValue( sal_Int64 nValue, USHORT nDigits,
+ MapUnit eInUnit, FieldUnit eOutUnit )
+{
+ return static_cast<sal_Int64>(
+ // #150733# cast double to sal_Int64 can throw a
+ // EXCEPTION_FLT_INVALID_OPERATION on Windows
+ nonValueDoubleToValueDouble(
+ ConvertDoubleValue( nValue, nDigits, eInUnit, eOutUnit ) ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricField::ConvertValue( sal_Int64 nValue, USHORT nDigits,
+ FieldUnit eInUnit, MapUnit eOutUnit )
+{
+ return static_cast<sal_Int64>(
+ // #150733# cast double to sal_Int64 can throw a
+ // EXCEPTION_FLT_INVALID_OPERATION on Windows
+ nonValueDoubleToValueDouble(
+ ConvertDoubleValue( nValue, nDigits, eInUnit, eOutUnit ) ) );
+}
+
+// -----------------------------------------------------------------------
+
+double MetricField::ConvertDoubleValue( double nValue, sal_Int64 mnBaseValue, USHORT nDecDigits,
+ FieldUnit eInUnit, FieldUnit eOutUnit )
+{
+ if ( eInUnit != eOutUnit )
+ {
+ sal_Int64 nMult = 1, nDiv = 1;
+
+ if ( eInUnit == FUNIT_PERCENT )
+ {
+ if ( (mnBaseValue <= 0) || (nValue <= 0) )
+ return nValue;
+ nDiv = 100;
+ for ( USHORT i=0; i < nDecDigits; i++ )
+ nDiv *= 10;
+
+ nMult = mnBaseValue;
+ }
+ else if ( eOutUnit == FUNIT_PERCENT ||
+ eOutUnit == FUNIT_CUSTOM ||
+ eOutUnit == FUNIT_NONE ||
+ eInUnit == FUNIT_CUSTOM ||
+ eInUnit == FUNIT_NONE )
+ return nValue;
+ else
+ {
+ if ( eOutUnit == FUNIT_100TH_MM )
+ eOutUnit = FUNIT_NONE;
+ if ( eInUnit == FUNIT_100TH_MM )
+ eInUnit = FUNIT_NONE;
+
+ nDiv = aImplFactor[eInUnit][eOutUnit];
+ nMult = aImplFactor[eOutUnit][eInUnit];
+
+ DBG_ASSERT( nMult > 0, "illegal *" );
+ DBG_ASSERT( nDiv > 0, "illegal /" );
+ }
+
+ if ( nMult != 1 && nMult > 0 )
+ nValue *= nMult;
+ if ( nDiv != 1 && nDiv > 0 )
+ {
+ nValue += ( nValue < 0 ) ? (-nDiv/2) : (nDiv/2);
+ nValue /= nDiv;
+ }
+ }
+
+ return nValue;
+}
+
+// -----------------------------------------------------------------------
+
+double MetricField::ConvertDoubleValue( double nValue, USHORT nDigits,
+ MapUnit eInUnit, FieldUnit eOutUnit )
+{
+ if ( eOutUnit == FUNIT_PERCENT ||
+ eOutUnit == FUNIT_CUSTOM ||
+ eOutUnit == FUNIT_NONE ||
+ eInUnit == MAP_PIXEL ||
+ eInUnit == MAP_SYSFONT ||
+ eInUnit == MAP_APPFONT ||
+ eInUnit == MAP_RELATIVE )
+ {
+ DBG_ERROR( "invalid parameters" );
+ return nValue;
+ }
+
+ long nDecDigits = nDigits;
+ FieldUnit eFieldUnit = ImplMap2FieldUnit( eInUnit, nDecDigits );
+
+ if ( nDecDigits < 0 )
+ {
+ while ( nDecDigits )
+ {
+ nValue += 5;
+ nValue /= 10;
+ nDecDigits++;
+ }
+ }
+ else
+ {
+ while ( nDecDigits )
+ {
+ nValue *= 10;
+ nDecDigits--;
+ }
+ }
+
+ if ( eFieldUnit != eOutUnit )
+ {
+ sal_Int64 nDiv = aImplFactor[eFieldUnit][eOutUnit];
+ sal_Int64 nMult = aImplFactor[eOutUnit][eFieldUnit];
+
+ DBG_ASSERT( nMult > 0, "illegal *" );
+ DBG_ASSERT( nDiv > 0, "illegal /" );
+
+ if ( nMult != 1 && nMult > 0)
+ nValue *= nMult;
+ if ( nDiv != 1 && nDiv > 0 )
+ {
+ nValue += (nValue < 0) ? (-nDiv/2) : (nDiv/2);
+ nValue /= nDiv;
+ }
+ }
+ return nValue;
+}
+
+// -----------------------------------------------------------------------
+
+double MetricField::ConvertDoubleValue( double nValue, USHORT nDigits,
+ FieldUnit eInUnit, MapUnit eOutUnit )
+{
+ if ( eInUnit == FUNIT_PERCENT ||
+ eInUnit == FUNIT_CUSTOM ||
+ eInUnit == FUNIT_NONE ||
+ eOutUnit == MAP_PIXEL ||
+ eOutUnit == MAP_SYSFONT ||
+ eOutUnit == MAP_APPFONT ||
+ eOutUnit == MAP_RELATIVE )
+ {
+ DBG_ERROR( "invalid parameters" );
+ return nValue;
+ }
+
+ long nDecDigits = nDigits;
+ FieldUnit eFieldUnit = ImplMap2FieldUnit( eOutUnit, nDecDigits );
+
+ if ( nDecDigits < 0 )
+ {
+ while ( nDecDigits )
+ {
+ nValue *= 10;
+ nDecDigits++;
+ }
+ }
+ else
+ {
+ while ( nDecDigits )
+ {
+ nValue += 5;
+ nValue /= 10;
+ nDecDigits--;
+ }
+ }
+
+ if ( eFieldUnit != eInUnit )
+ {
+ sal_Int64 nDiv = aImplFactor[eInUnit][eFieldUnit];
+ sal_Int64 nMult = aImplFactor[eFieldUnit][eInUnit];
+
+ DBG_ASSERT( nMult > 0, "illegal *" );
+ DBG_ASSERT( nDiv > 0, "illegal /" );
+
+ if( nMult != 1 && nMult > 0 )
+ nValue *= nMult;
+ if( nDiv != 1 && nDiv > 0 )
+ {
+ nValue += (nValue < 0) ? (-nDiv/2) : (nDiv/2);
+ nValue /= nDiv;
+ }
+ }
+ return nValue;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplMetricGetValue( const XubString& rStr, double& rValue, sal_Int64 nBaseValue,
+ USHORT nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper, FieldUnit eUnit )
+{
+ // Zahlenwert holen
+ if ( !ImplNumericGetValue( rStr, rValue, nDecDigits, rLocaleDataWrapper ) )
+ return FALSE;
+
+ // Einheit rausfinden
+ FieldUnit eEntryUnit = ImplMetricGetUnit( rStr );
+
+ // Einheiten umrechnen
+ rValue = MetricField::ConvertDoubleValue( rValue, nBaseValue, nDecDigits, eEntryUnit, eUnit );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MetricFormatter::ImplMetricReformat( const XubString& rStr, double& rValue, XubString& rOutStr )
+{
+ if ( !ImplMetricGetValue( rStr, rValue, mnBaseValue, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit ) )
+ return TRUE;
+ else
+ {
+ double nTempVal = rValue;
+ // caution: precision loss in double cast
+ if ( nTempVal > GetMax() )
+ nTempVal = (double)GetMax();
+ else if ( nTempVal < GetMin())
+ nTempVal = (double)GetMin();
+
+ if ( GetErrorHdl().IsSet() && (rValue != nTempVal) )
+ {
+ mnCorrectedValue = (sal_Int64)nTempVal;
+ if ( !GetErrorHdl().Call( this ) )
+ {
+ mnCorrectedValue = 0;
+ return FALSE;
+ }
+ else
+ mnCorrectedValue = 0;
+ }
+
+ rOutStr = CreateFieldText( (sal_Int64)nTempVal );
+ return TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline void MetricFormatter::ImplInit()
+{
+ mnBaseValue = 0;
+ meUnit = MetricField::GetDefaultUnit();
+ mnType = FORMAT_METRIC;
+}
+
+// -----------------------------------------------------------------------
+
+MetricFormatter::MetricFormatter()
+{
+ ImplInit();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::ImplLoadRes( const ResId& rResId )
+{
+ NumericFormatter::ImplLoadRes( rResId );
+
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ {
+ ULONG nMask = pMgr->ReadLong();
+
+ if ( METRICFORMATTER_UNIT & nMask )
+ meUnit = (FieldUnit)pMgr->ReadLong();
+
+ if ( METRICFORMATTER_CUSTOMUNITTEXT & nMask )
+ maCustomUnitText = pMgr->ReadString();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MetricFormatter::~MetricFormatter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetUnit( FieldUnit eNewUnit )
+{
+ if ( eNewUnit == FUNIT_100TH_MM )
+ {
+ SetDecimalDigits( GetDecimalDigits() + 2 );
+ meUnit = FUNIT_MM;
+ }
+ else
+ meUnit = eNewUnit;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetCustomUnitText( const XubString& rStr )
+{
+ maCustomUnitText = rStr;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit )
+{
+ SetUserValue( nNewValue, eInUnit );
+ mnFieldValue = mnLastValue;
+}
+
+// -----------------------------------------------------------------------
+
+XubString MetricFormatter::CreateFieldText( sal_Int64 nValue ) const
+{
+ XubString aStr = NumericFormatter::CreateFieldText( nValue );
+
+ if( meUnit == FUNIT_CUSTOM )
+ aStr += maCustomUnitText;
+ else
+ aStr += ImplMetricToString( meUnit );
+
+ return aStr;
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetUserValue( sal_Int64 nNewValue, FieldUnit eInUnit )
+{
+ // Umrechnen auf eingestellte Einheiten
+ nNewValue = MetricField::ConvertValue( nNewValue, mnBaseValue, GetDecimalDigits(), eInUnit, meUnit );
+ NumericFormatter::SetUserValue( nNewValue );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricFormatter::GetValue( FieldUnit eOutUnit ) const
+{
+ if ( !GetField() )
+ return 0;
+
+ double nTempValue;
+ // caution: precision loss in double cast
+ if ( !ImplMetricGetValue( GetField()->GetText(), nTempValue, mnBaseValue, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit ) )
+ nTempValue = (double)mnLastValue;
+
+ // caution: precision loss in double cast
+ if ( nTempValue > mnMax )
+ nTempValue = (double)mnMax;
+ else if ( nTempValue < mnMin )
+ nTempValue = (double)mnMin;
+
+ // Umrechnen auf gewuenschte Einheiten
+ return MetricField::ConvertValue( (sal_Int64)nTempValue, mnBaseValue, GetDecimalDigits(), meUnit, eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetValue( sal_Int64 nValue )
+{
+ // Implementation not inline, because it is a virtual Function
+ SetValue( nValue, FUNIT_NONE );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricFormatter::GetValue() const
+{
+ // Implementation not inline, because it is a virtual Function
+ return GetValue( FUNIT_NONE );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetMin( sal_Int64 nNewMin, FieldUnit eInUnit )
+{
+ // Umrechnen auf gewuenschte Einheiten
+ NumericFormatter::SetMin( MetricField::ConvertValue( nNewMin, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricFormatter::GetMin( FieldUnit eOutUnit ) const
+{
+ // Umrechnen auf gewuenschte Einheiten
+ return MetricField::ConvertValue( NumericFormatter::GetMin(), mnBaseValue,
+ GetDecimalDigits(), meUnit, eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetMax( sal_Int64 nNewMax, FieldUnit eInUnit )
+{
+ // Umrechnen auf gewuenschte Einheiten
+ NumericFormatter::SetMax( MetricField::ConvertValue( nNewMax, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricFormatter::GetMax( FieldUnit eOutUnit ) const
+{
+ // Umrechnen auf gewuenschte Einheiten
+ return MetricField::ConvertValue( NumericFormatter::GetMax(), mnBaseValue,
+ GetDecimalDigits(), meUnit, eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::SetBaseValue( sal_Int64 nNewBase, FieldUnit eInUnit )
+{
+ mnBaseValue = MetricField::ConvertValue( nNewBase, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricFormatter::GetBaseValue( FieldUnit eOutUnit ) const
+{
+ // Umrechnen auf gewuenschte Einheiten
+ return MetricField::ConvertValue( mnBaseValue, mnBaseValue, GetDecimalDigits(),
+ meUnit, eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricFormatter::Reformat()
+{
+ if ( !GetField() )
+ return;
+
+ XubString aText = GetField()->GetText();
+ if ( meUnit == FUNIT_CUSTOM )
+ maCurUnitText = ImplMetricGetUnitText( aText );
+
+ XubString aStr;
+ // caution: precision loss in double cast
+ double nTemp = (double)mnLastValue;
+ BOOL bOK = ImplMetricReformat( aText, nTemp, aStr );
+ mnLastValue = (sal_Int64)nTemp;
+
+ if ( !bOK )
+ return;
+
+ if ( aStr.Len() )
+ {
+ ImplSetText( aStr );
+ if ( meUnit == FUNIT_CUSTOM )
+ CustomConvert();
+ }
+ else
+ SetValue( mnLastValue );
+ maCurUnitText.Erase();
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricFormatter::GetCorrectedValue( FieldUnit eOutUnit ) const
+{
+ // Umrechnen auf gewuenschte Einheiten
+ return MetricField::ConvertValue( mnCorrectedValue, mnBaseValue, GetDecimalDigits(),
+ meUnit, eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+MetricField::MetricField( Window* pParent, WinBits nWinStyle ) :
+ SpinField( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+MetricField::MetricField( Window* pParent, const ResId& rResId ) :
+ SpinField( WINDOW_METRICFIELD )
+{
+ rResId.SetRT( RSC_METRICFIELD );
+ WinBits nStyle = ImplInitRes( rResId ) ;
+ SpinField::ImplInit( pParent, nStyle );
+ SetField( this );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::ImplLoadRes( const ResId& rResId )
+{
+ SpinField::ImplLoadRes( rResId );
+ MetricFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+
+ ULONG nMask = ReadLongRes();
+
+ if ( METRICFIELD_FIRST & nMask )
+ mnFirst = ReadLongRes();
+
+ if ( METRICFIELD_LAST & nMask )
+ mnLast = ReadLongRes();
+
+ if ( METRICFIELD_SPINSIZE & nMask )
+ mnSpinSize = ReadLongRes();
+
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+MetricField::~MetricField()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::SetFirst( sal_Int64 nNewFirst, FieldUnit eInUnit )
+{
+ // convert
+ nNewFirst = MetricField::ConvertValue( nNewFirst, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit );
+ mnFirst = nNewFirst;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricField::GetFirst( FieldUnit eOutUnit ) const
+{
+ // convert
+ return MetricField::ConvertValue( mnFirst, mnBaseValue, GetDecimalDigits(),
+ meUnit, eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::SetLast( sal_Int64 nNewLast, FieldUnit eInUnit )
+{
+ // Umrechnen
+ nNewLast = MetricField::ConvertValue( nNewLast, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit );
+ mnLast = nNewLast;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricField::GetLast( FieldUnit eOutUnit ) const
+{
+ // Umrechnen
+ return MetricField::ConvertValue( mnLast, mnBaseValue, GetDecimalDigits(),
+ meUnit, eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+long MetricField::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplMetricProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return SpinField::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long MetricField::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return SpinField::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SpinField::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ String sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ String sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ SpinField::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::Up()
+{
+ FieldUp();
+ SpinField::Up();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::Down()
+{
+ FieldDown();
+ SpinField::Down();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::First()
+{
+ FieldFirst();
+ SpinField::First();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::Last()
+{
+ FieldLast();
+ SpinField::Last();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricField::CustomConvert()
+{
+ maCustomConvertLink.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+MetricBox::MetricBox( Window* pParent, WinBits nWinStyle ) :
+ ComboBox( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+MetricBox::MetricBox( Window* pParent, const ResId& rResId ) :
+ ComboBox( WINDOW_METRICBOX )
+{
+ rResId.SetRT( RSC_METRICBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ComboBox::ImplInit( pParent, nStyle );
+ SetField( this );
+ Reformat();
+ ComboBox::ImplLoadRes( rResId );
+ MetricFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+MetricBox::~MetricBox()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long MetricBox::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplMetricProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return ComboBox::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long MetricBox::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return ComboBox::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ ComboBox::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ String sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ String sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void MetricBox::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ ComboBox::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void MetricBox::ReformatAll()
+{
+ double nValue;
+ XubString aStr;
+ SetUpdateMode( FALSE );
+ USHORT nEntryCount = GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ ImplMetricReformat( GetEntry( i ), nValue, aStr );
+ RemoveEntry( i );
+ InsertEntry( aStr, i );
+ }
+ MetricFormatter::Reformat();
+ SetUpdateMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricBox::CustomConvert()
+{
+ maCustomConvertLink.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricBox::InsertValue( sal_Int64 nValue, FieldUnit eInUnit, USHORT nPos )
+{
+ // Umrechnen auf eingestellte Einheiten
+ nValue = MetricField::ConvertValue( nValue, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit );
+ ComboBox::InsertEntry( CreateFieldText( nValue ), nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void MetricBox::RemoveValue( sal_Int64 nValue, FieldUnit eInUnit )
+{
+ // Umrechnen auf eingestellte Einheiten
+ nValue = MetricField::ConvertValue( nValue, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit );
+ ComboBox::RemoveEntry( CreateFieldText( nValue ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricBox::GetValue( USHORT nPos, FieldUnit eOutUnit ) const
+{
+ double nValue = 0;
+ ImplMetricGetValue( ComboBox::GetEntry( nPos ), nValue, mnBaseValue,
+ GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit );
+
+ // Umrechnen auf eingestellte Einheiten
+ sal_Int64 nRetValue = MetricField::ConvertValue( (sal_Int64)nValue, mnBaseValue, GetDecimalDigits(),
+ meUnit, eOutUnit );
+
+ return nRetValue;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT MetricBox::GetValuePos( sal_Int64 nValue, FieldUnit eInUnit ) const
+{
+ // Umrechnen auf eingestellte Einheiten
+ nValue = MetricField::ConvertValue( nValue, mnBaseValue, GetDecimalDigits(),
+ eInUnit, meUnit );
+ return ComboBox::GetEntryPos( CreateFieldText( nValue ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricBox::GetValue( FieldUnit eOutUnit ) const
+{
+ // Implementation not inline, because it is a virtual Function
+ return MetricFormatter::GetValue( eOutUnit );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 MetricBox::GetValue() const
+{
+ // Implementation not inline, because it is a virtual Function
+ return GetValue( FUNIT_NONE );
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplCurrencyProcessKeyInput( Edit* pEdit, const KeyEvent& rKEvt,
+ BOOL, BOOL bUseThousandSep, const LocaleDataWrapper& rWrapper )
+{
+ // Es gibt hier kein sinnvolles StrictFormat, also alle
+ // Zeichen erlauben
+ return ImplNumericProcessKeyInput( pEdit, rKEvt, FALSE, bUseThousandSep, rWrapper );
+}
+
+// -----------------------------------------------------------------------
+
+inline BOOL ImplCurrencyGetValue( const XubString& rStr, double& rValue,
+ USHORT nDecDigits, const LocaleDataWrapper& rWrapper )
+{
+ // Zahlenwert holen
+ return ImplNumericGetValue( rStr, rValue, nDecDigits, rWrapper, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL CurrencyFormatter::ImplCurrencyReformat( const XubString& rStr,
+ XubString& rOutStr )
+{
+ double nValue;
+ if ( !ImplNumericGetValue( rStr, nValue, GetDecimalDigits(), ImplGetLocaleDataWrapper(), TRUE ) )
+ return TRUE;
+ else
+ {
+ double nTempVal = nValue;
+ // caution: precision loss in double cast
+ if ( nTempVal > GetMax() )
+ nTempVal = (double)GetMax();
+ else if ( nTempVal < GetMin())
+ nTempVal = (double)GetMin();
+
+ if ( GetErrorHdl().IsSet() && (nValue != nTempVal) )
+ {
+ mnCorrectedValue = (sal_Int64)nTempVal;
+ if ( !GetErrorHdl().Call( this ) )
+ {
+ mnCorrectedValue = 0;
+ return FALSE;
+ }
+ else
+ mnCorrectedValue = 0;
+ }
+
+ rOutStr = CreateFieldText( (long)nTempVal );
+ return TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline void CurrencyFormatter::ImplInit()
+{
+ mnType = FORMAT_CURRENCY;
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyFormatter::CurrencyFormatter()
+{
+ ImplInit();
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyFormatter::~CurrencyFormatter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyFormatter::SetCurrencySymbol( const String& rStr )
+{
+ maCurrencySymbol= rStr;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+String CurrencyFormatter::GetCurrencySymbol() const
+{
+ return maCurrencySymbol.Len() ? maCurrencySymbol : ImplGetLocaleDataWrapper().getCurrSymbol();
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyFormatter::SetValue( sal_Int64 nNewValue )
+{
+ SetUserValue( nNewValue );
+ mnFieldValue = mnLastValue;
+ SetEmptyFieldValueData( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+XubString CurrencyFormatter::CreateFieldText( sal_Int64 nValue ) const
+{
+ return ImplGetLocaleDataWrapper().getCurr( nValue, GetDecimalDigits(), GetCurrencySymbol(), IsUseThousandSep() );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 CurrencyFormatter::GetValue() const
+{
+ if ( !GetField() )
+ return 0;
+
+ double nTempValue;
+ if ( ImplCurrencyGetValue( GetField()->GetText(), nTempValue, GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
+ {
+ // caution: precision loss in double cast
+ if ( nTempValue > mnMax )
+ nTempValue = (double)mnMax;
+ else if ( nTempValue < mnMin )
+ nTempValue = (double)mnMin;
+ return (sal_Int64)nTempValue;
+ }
+ else
+ return mnLastValue;
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyFormatter::Reformat()
+{
+ if ( !GetField() )
+ return;
+
+ XubString aStr;
+ BOOL bOK = ImplCurrencyReformat( GetField()->GetText(), aStr );
+ if ( !bOK )
+ return;
+
+ if ( aStr.Len() )
+ {
+ ImplSetText( aStr );
+ // caution: precision loss in double cast
+ double nTemp = (double)mnLastValue;
+ ImplCurrencyGetValue( aStr, nTemp, GetDecimalDigits(), ImplGetLocaleDataWrapper() );
+ mnLastValue = (sal_Int64)nTemp;
+ }
+ else
+ SetValue( mnLastValue );
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyField::CurrencyField( Window* pParent, WinBits nWinStyle ) :
+ SpinField( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyField::CurrencyField( Window* pParent, const ResId& rResId ) :
+ SpinField( WINDOW_CURRENCYFIELD )
+{
+ rResId.SetRT( RSC_CURRENCYFIELD );
+ WinBits nStyle = ImplInitRes( rResId );
+ SpinField::ImplInit( pParent, nStyle);
+ SetField( this );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyField::ImplLoadRes( const ResId& rResId )
+{
+ SpinField::ImplLoadRes( rResId );
+ CurrencyFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+
+ ULONG nMask = ReadLongRes();
+
+ if ( CURRENCYFIELD_FIRST & nMask )
+ mnFirst = ReadLongRes();
+
+ if ( CURRENCYFIELD_LAST & nMask )
+ mnLast = ReadLongRes();
+
+ if ( CURRENCYFIELD_SPINSIZE & nMask )
+ mnSpinSize = ReadLongRes();
+
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyField::~CurrencyField()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long CurrencyField::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplCurrencyProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return SpinField::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long CurrencyField::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return SpinField::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SpinField::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ String sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ String sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyField::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ SpinField::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyField::Up()
+{
+ FieldUp();
+ SpinField::Up();
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyField::Down()
+{
+ FieldDown();
+ SpinField::Down();
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyField::First()
+{
+ FieldFirst();
+ SpinField::First();
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyField::Last()
+{
+ FieldLast();
+ SpinField::Last();
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyBox::CurrencyBox( Window* pParent, WinBits nWinStyle ) :
+ ComboBox( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyBox::CurrencyBox( Window* pParent, const ResId& rResId ) :
+ ComboBox( WINDOW_CURRENCYBOX )
+{
+ rResId.SetRT( RSC_CURRENCYBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ComboBox::ImplInit( pParent, nStyle );
+ CurrencyFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ SetField( this );
+ ComboBox::ImplLoadRes( rResId );
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+CurrencyBox::~CurrencyBox()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long CurrencyBox::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplCurrencyProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return ComboBox::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long CurrencyBox::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return ComboBox::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ ComboBox::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ String sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ String sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
+ String sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
+ ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyBox::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ ComboBox::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyBox::ReformatAll()
+{
+ XubString aStr;
+ SetUpdateMode( FALSE );
+ USHORT nEntryCount = GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ ImplCurrencyReformat( GetEntry( i ), aStr );
+ RemoveEntry( i );
+ InsertEntry( aStr, i );
+ }
+ CurrencyFormatter::Reformat();
+ SetUpdateMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyBox::InsertValue( sal_Int64 nValue, USHORT nPos )
+{
+ ComboBox::InsertEntry( CreateFieldText( nValue ), nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void CurrencyBox::RemoveValue( sal_Int64 nValue )
+{
+ ComboBox::RemoveEntry( CreateFieldText( nValue ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 CurrencyBox::GetValue( USHORT nPos ) const
+{
+ double nValue = 0;
+ ImplCurrencyGetValue( ComboBox::GetEntry( nPos ), nValue, GetDecimalDigits(), ImplGetLocaleDataWrapper() );
+ return (sal_Int64)nValue;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT CurrencyBox::GetValuePos( sal_Int64 nValue ) const
+{
+ return ComboBox::GetEntryPos( CreateFieldText( nValue ) );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Int64 CurrencyBox::GetValue() const
+{
+ // Implementation not inline, because it is a virtual Function
+ return CurrencyFormatter::GetValue();
+}
diff --git a/vcl/source/control/field2.cxx b/vcl/source/control/field2.cxx
new file mode 100644
index 000000000000..8ae2ecff41b9
--- /dev/null
+++ b/vcl/source/control/field2.cxx
@@ -0,0 +1,3469 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#ifndef _SV_EVENT_HXX
+#include <vcl/field.hxx>
+#endif
+#include <vcl/svapp.hxx>
+#include <vcl/sound.hxx>
+#include <vcl/event.hxx>
+#include <vcl/field.hxx>
+#include <i18npool/mslangid.hxx>
+
+#include <vcl/unohelp.hxx>
+
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+#include <com/sun/star/i18n/KCharacterType.hpp>
+
+
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/misccfg.hxx>
+
+using namespace ::com::sun::star;
+
+// =======================================================================
+
+#define EDITMASK_LITERAL 'L'
+#define EDITMASK_ALPHA 'a'
+#define EDITMASK_UPPERALPHA 'A'
+#define EDITMASK_ALPHANUM 'c'
+#define EDITMASK_UPPERALPHANUM 'C'
+#define EDITMASK_NUM 'N'
+#define EDITMASK_NUMSPACE 'n'
+#define EDITMASK_ALLCHAR 'x'
+#define EDITMASK_UPPERALLCHAR 'X'
+
+uno::Reference< i18n::XCharacterClassification > ImplGetCharClass()
+{
+ static uno::Reference< i18n::XCharacterClassification > xCharClass;
+ if ( !xCharClass.is() )
+ xCharClass = vcl::unohelper::CreateCharacterClassification();
+
+ return xCharClass;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Unicode* ImplAddString( sal_Unicode* pBuf, const String& rStr )
+{
+ if ( rStr.Len() == 1 )
+ *pBuf++ = rStr.GetChar(0);
+ else if ( rStr.Len() == 0 )
+ ;
+ else
+ {
+ memcpy( pBuf, rStr.GetBuffer(), rStr.Len() * sizeof(sal_Unicode) );
+ pBuf += rStr.Len();
+ }
+ return pBuf;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Unicode* ImplAddNum( sal_Unicode* pBuf, ULONG nNumber, int nMinLen )
+{
+ // fill temp buffer with digits
+ sal_Unicode aTempBuf[30];
+ sal_Unicode* pTempBuf = aTempBuf;
+ do
+ {
+ *pTempBuf = (sal_Unicode)(nNumber % 10) + '0';
+ pTempBuf++;
+ nNumber /= 10;
+ if ( nMinLen )
+ nMinLen--;
+ }
+ while ( nNumber );
+
+ // fill with zeros up to the minimal length
+ while ( nMinLen > 0 )
+ {
+ *pBuf = '0';
+ pBuf++;
+ nMinLen--;
+ }
+
+ // copy temp buffer to real buffer
+ do
+ {
+ pTempBuf--;
+ *pBuf = *pTempBuf;
+ pBuf++;
+ }
+ while ( pTempBuf != aTempBuf );
+
+ return pBuf;
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplGetNum( const sal_Unicode*& rpBuf, BOOL& rbError )
+{
+ if ( !*rpBuf )
+ {
+ rbError = TRUE;
+ return 0;
+ }
+
+ USHORT nNumber = 0;
+ while( ( *rpBuf >= '0' ) && ( *rpBuf <= '9' ) )
+ {
+ nNumber *= 10;
+ nNumber += *rpBuf - '0';
+ rpBuf++;
+ }
+
+ return nNumber;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSkipDelimiters( const sal_Unicode*& rpBuf )
+{
+ while( ( *rpBuf == ',' ) || ( *rpBuf == '.' ) || ( *rpBuf == ';' ) ||
+ ( *rpBuf == ':' ) || ( *rpBuf == '-' ) || ( *rpBuf == '/' ) )
+ {
+ rpBuf++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplIsPatternChar( xub_Unicode cChar, sal_Char cEditMask )
+{
+ sal_Int32 nType = 0;
+
+ try
+ {
+ String aCharStr( cChar );
+ nType = ImplGetCharClass()->getStringType( aCharStr, 0, aCharStr.Len(), Application::GetSettings().GetLocale() );
+ }
+ catch ( ::com::sun::star::uno::Exception& )
+ {
+ DBG_ERRORFILE( "ImplIsPatternChar: Exception caught!" );
+ return FALSE;
+ }
+
+ if ( (cEditMask == EDITMASK_ALPHA) || (cEditMask == EDITMASK_UPPERALPHA) )
+ {
+ if( !CharClass::isLetterType( nType ) )
+ return FALSE;
+ }
+ else if ( cEditMask == EDITMASK_NUM )
+ {
+ if( !CharClass::isNumericType( nType ) )
+ return FALSE;
+ }
+ else if ( (cEditMask == EDITMASK_ALPHANUM) || (cEditMask == EDITMASK_UPPERALPHANUM) )
+ {
+ if( !CharClass::isLetterNumericType( nType ) )
+ return FALSE;
+ }
+ else if ( (cEditMask == EDITMASK_ALLCHAR) || (cEditMask == EDITMASK_UPPERALLCHAR) )
+ {
+ if ( cChar < 32 )
+ return FALSE;
+ }
+ else if ( cEditMask == EDITMASK_NUMSPACE )
+ {
+ if ( !CharClass::isNumericType( nType ) && ( cChar != ' ' ) )
+ return FALSE;
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static xub_Unicode ImplPatternChar( xub_Unicode cChar, sal_Char cEditMask )
+{
+ if ( ImplIsPatternChar( cChar, cEditMask ) )
+ {
+ if ( (cEditMask == EDITMASK_UPPERALPHA) ||
+ (cEditMask == EDITMASK_UPPERALPHANUM) ||
+ ( cEditMask == EDITMASK_UPPERALLCHAR ) )
+ {
+ cChar = ImplGetCharClass()->toUpper( String(cChar),0,1,Application::GetSettings().GetLocale() )[0];
+ }
+ return cChar;
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplKommaPointCharEqual( xub_Unicode c1, xub_Unicode c2 )
+{
+ if ( c1 == c2 )
+ return TRUE;
+ else if ( ((c1 == '.') || (c1 == ',')) &&
+ ((c2 == '.') || (c2 == ',')) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static XubString ImplPatternReformat( const XubString& rStr,
+ const ByteString& rEditMask,
+ const XubString& rLiteralMask,
+ USHORT nFormatFlags )
+{
+ if ( !rEditMask.Len() )
+ return rStr;
+
+ XubString aStr = rStr;
+ XubString aOutStr = rLiteralMask;
+ xub_Unicode cTempChar;
+ xub_Unicode cChar;
+ xub_Unicode cLiteral;
+ sal_Char cMask;
+ xub_StrLen nStrIndex = 0;
+ xub_StrLen i = 0;
+ xub_StrLen n;
+
+ while ( i < rEditMask.Len() )
+ {
+ if ( nStrIndex >= aStr.Len() )
+ break;
+
+ cChar = aStr.GetChar(nStrIndex);
+ cLiteral = rLiteralMask.GetChar(i);
+ cMask = rEditMask.GetChar(i);
+
+ // Aktuelle Position ein Literal
+ if ( cMask == EDITMASK_LITERAL )
+ {
+ // Wenn es das Literal-Zeichen ist, uebernehmen, ansonsten
+ // ignorieren, da es das naechste gueltige Zeichen vom String
+ // sein kann
+ if ( ImplKommaPointCharEqual( cChar, cLiteral ) )
+ nStrIndex++;
+ else
+ {
+ // Ansonsten testen wir, ob es ein ungueltiges Zeichen ist.
+ // Dies ist dann der Fall, wenn es nicht in das Muster
+ // des naechsten nicht Literal-Zeichens passt
+ n = i+1;
+ while ( n < rEditMask.Len() )
+ {
+ if ( rEditMask.GetChar(n) != EDITMASK_LITERAL )
+ {
+ if ( !ImplIsPatternChar( cChar, rEditMask.GetChar(n) ) )
+ nStrIndex++;
+ break;
+ }
+
+ n++;
+ }
+ }
+ }
+ else
+ {
+ // Gueltiges Zeichen an der Stelle
+ cTempChar = ImplPatternChar( cChar, cMask );
+ if ( cTempChar )
+ {
+ // dann Zeichen uebernehmen
+ aOutStr.SetChar( i, cTempChar );
+ nStrIndex++;
+ }
+ else
+ {
+ // Wenn es das Literalzeichen ist, uebernehmen
+ if ( cLiteral == cChar )
+ nStrIndex++;
+ else
+ {
+ // Wenn das ungueltige Zeichen das naechste Literalzeichen
+ // sein kann, dann springen wir bis dahin vor, ansonten
+ // das Zeichen ignorieren
+ // Nur machen, wenn leere Literale erlaubt sind
+ if ( nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS )
+ {
+ n = i;
+ while ( n < rEditMask.Len() )
+ {
+ if ( rEditMask.GetChar( n ) == EDITMASK_LITERAL )
+ {
+ if ( ImplKommaPointCharEqual( cChar, rLiteralMask.GetChar( n ) ) )
+ i = n+1;
+
+ break;
+ }
+
+ n++;
+ }
+ }
+
+ nStrIndex++;
+ continue;
+ }
+ }
+ }
+
+ i++;
+ }
+
+ return aOutStr;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplPatternMaxPos( const XubString rStr, const ByteString& rEditMask,
+ USHORT nFormatFlags, BOOL bSameMask,
+ USHORT nCursorPos, USHORT& rPos )
+{
+
+ // Letzte Position darf nicht groesser als der enthaltene String sein
+ xub_StrLen nMaxPos = rStr.Len();
+
+ // Wenn keine leeren Literale erlaubt sind, auch Leerzeichen
+ // am Ende ignorieren
+ if ( bSameMask && !(nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS) )
+ {
+ while ( nMaxPos )
+ {
+ if ( (rEditMask.GetChar(nMaxPos-1) != EDITMASK_LITERAL) &&
+ (rStr.GetChar(nMaxPos-1) != ' ') )
+ break;
+ nMaxPos--;
+ }
+
+ // Wenn wir vor einem Literal stehen, dann solange weitersuchen,
+ // bis erste Stelle nach Literal
+ xub_StrLen nTempPos = nMaxPos;
+ while ( nTempPos < rEditMask.Len() )
+ {
+ if ( rEditMask.GetChar(nTempPos) != EDITMASK_LITERAL )
+ {
+ nMaxPos = nTempPos;
+ break;
+ }
+ nTempPos++;
+ }
+ }
+
+ if ( rPos > nMaxPos )
+ rPos = nMaxPos;
+ // Zeichen sollte nicht nach links wandern
+ if ( rPos < nCursorPos )
+ rPos = nCursorPos;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplPatternProcessStrictModify( Edit* pEdit,
+ const ByteString& rEditMask,
+ const XubString& rLiteralMask,
+ USHORT nFormatFlags, BOOL bSameMask )
+{
+ XubString aText = pEdit->GetText();
+
+ // Leerzeichen am Anfang entfernen
+ if ( bSameMask && !(nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS) )
+ {
+ xub_StrLen i = 0;
+ xub_StrLen nMaxLen = aText.Len();
+ while ( i < nMaxLen )
+ {
+ if ( (rEditMask.GetChar( i ) != EDITMASK_LITERAL) &&
+ (aText.GetChar( i ) != ' ') )
+ break;
+
+ i++;
+ }
+ // Alle Literalzeichen beibehalten
+ while ( i && (rEditMask.GetChar( i ) == EDITMASK_LITERAL) )
+ i--;
+ aText.Erase( 0, i );
+ }
+
+ XubString aNewText = ImplPatternReformat( aText, rEditMask, rLiteralMask, nFormatFlags );
+ if ( aNewText != aText )
+ {
+ // Selection so anpassen, das diese wenn sie vorher am Ende
+ // stand, immer noch am Ende steht
+ Selection aSel = pEdit->GetSelection();
+ ULONG nMaxSel = Max( aSel.Min(), aSel.Max() );
+ if ( nMaxSel >= aText.Len() )
+ {
+ xub_StrLen nMaxPos = aNewText.Len();
+ ImplPatternMaxPos( aNewText, rEditMask, nFormatFlags, bSameMask, (xub_StrLen)nMaxSel, nMaxPos );
+ if ( aSel.Min() == aSel.Max() )
+ {
+ aSel.Min() = nMaxPos;
+ aSel.Max() = aSel.Min();
+ }
+ else if ( aSel.Min() > aSel.Max() )
+ aSel.Min() = nMaxPos;
+ else
+ aSel.Max() = nMaxPos;
+ }
+ pEdit->SetText( aNewText, aSel );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static xub_StrLen ImplPatternLeftPos( const ByteString& rEditMask, xub_StrLen nCursorPos )
+{
+ // Vorheriges Zeichen suchen, was kein Literal ist
+ xub_StrLen nNewPos = nCursorPos;
+ xub_StrLen nTempPos = nNewPos;
+ while ( nTempPos )
+ {
+ if ( rEditMask.GetChar(nTempPos-1) != EDITMASK_LITERAL )
+ {
+ nNewPos = nTempPos-1;
+ break;
+ }
+ nTempPos--;
+ }
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+static xub_StrLen ImplPatternRightPos( const XubString& rStr, const ByteString& rEditMask,
+ USHORT nFormatFlags, BOOL bSameMask,
+ xub_StrLen nCursorPos )
+{
+ // Naechstes Zeichen suchen, was kein Literal ist
+ xub_StrLen nNewPos = nCursorPos;
+ xub_StrLen nTempPos = nNewPos;
+ while ( nTempPos < rEditMask.Len() )
+ {
+ if ( rEditMask.GetChar(nTempPos+1) != EDITMASK_LITERAL )
+ {
+ nNewPos = nTempPos+1;
+ break;
+ }
+ nTempPos++;
+ }
+ ImplPatternMaxPos( rStr, rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplPatternProcessKeyInput( Edit* pEdit, const KeyEvent& rKEvt,
+ const ByteString& rEditMask,
+ const XubString& rLiteralMask,
+ BOOL bStrictFormat,
+ USHORT nFormatFlags,
+ BOOL bSameMask,
+ BOOL& rbInKeyInput )
+{
+ if ( !rEditMask.Len() || !bStrictFormat )
+ return FALSE;
+
+ Selection aOldSel = pEdit->GetSelection();
+ KeyCode aCode = rKEvt.GetKeyCode();
+ xub_Unicode cChar = rKEvt.GetCharCode();
+ USHORT nKeyCode = aCode.GetCode();
+ BOOL bShift = aCode.IsShift();
+ xub_StrLen nCursorPos = (xub_StrLen)aOldSel.Max();
+ xub_StrLen nNewPos;
+ xub_StrLen nTempPos;
+
+ if ( nKeyCode && !aCode.IsMod1() && !aCode.IsMod2() )
+ {
+ if ( nKeyCode == KEY_LEFT )
+ {
+ Selection aSel( ImplPatternLeftPos( rEditMask, nCursorPos ) );
+ if ( bShift )
+ aSel.Min() = aOldSel.Min();
+ pEdit->SetSelection( aSel );
+ return TRUE;
+ }
+ else if ( nKeyCode == KEY_RIGHT )
+ {
+ // Hier nehmen wir Selectionsanfang als minimum, da falls durch
+ // Focus alles selektiert ist, ist eine kleine Position schon
+ // erlaubt.
+ Selection aSel( aOldSel );
+ aSel.Justify();
+ nCursorPos = (xub_StrLen)aSel.Min();
+ aSel.Max() = ImplPatternRightPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos );
+ if ( bShift )
+ aSel.Min() = aOldSel.Min();
+ else
+ aSel.Min() = aSel.Max();
+ pEdit->SetSelection( aSel );
+ return TRUE;
+ }
+ else if ( nKeyCode == KEY_HOME )
+ {
+ // Home ist Position des ersten nicht literalen Zeichens
+ nNewPos = 0;
+ while ( (nNewPos < rEditMask.Len()) &&
+ (rEditMask.GetChar(nNewPos) == EDITMASK_LITERAL) )
+ nNewPos++;
+ // Home sollte nicht nach rechts wandern
+ if ( nCursorPos < nNewPos )
+ nNewPos = nCursorPos;
+ Selection aSel( nNewPos );
+ if ( bShift )
+ aSel.Min() = aOldSel.Min();
+ pEdit->SetSelection( aSel );
+ return TRUE;
+ }
+ else if ( nKeyCode == KEY_END )
+ {
+ // End ist die Position des letzten nicht literalen Zeichens
+ nNewPos = rEditMask.Len();
+ while ( nNewPos &&
+ (rEditMask.GetChar(nNewPos-1) == EDITMASK_LITERAL) )
+ nNewPos--;
+ // Hier nehmen wir Selectionsanfang als minimum, da falls durch
+ // Focus alles selektiert ist, ist eine kleine Position schon
+ // erlaubt.
+ Selection aSel( aOldSel );
+ aSel.Justify();
+ nCursorPos = (xub_StrLen)aSel.Min();
+ ImplPatternMaxPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
+ aSel.Max() = nNewPos;
+ if ( bShift )
+ aSel.Min() = aOldSel.Min();
+ else
+ aSel.Min() = aSel.Max();
+ pEdit->SetSelection( aSel );
+ return TRUE;
+ }
+ else if ( (nKeyCode == KEY_BACKSPACE) || (nKeyCode == KEY_DELETE) )
+ {
+ XubString aStr( pEdit->GetText() );
+ XubString aOldStr = aStr;
+ Selection aSel = aOldSel;
+
+ aSel.Justify();
+ nNewPos = (xub_StrLen)aSel.Min();
+
+ // Wenn Selection, dann diese Loeschen
+ if ( aSel.Len() )
+ {
+ if ( bSameMask )
+ aStr.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
+ else
+ {
+ XubString aRep = rLiteralMask.Copy( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
+ aStr.Replace( (xub_StrLen)aSel.Min(), aRep.Len(), aRep );
+ }
+ }
+ else
+ {
+ if ( nKeyCode == KEY_BACKSPACE )
+ {
+ nTempPos = nNewPos;
+ nNewPos = ImplPatternLeftPos( rEditMask, nTempPos );
+ }
+ else
+ nTempPos = ImplPatternRightPos( aStr, rEditMask, nFormatFlags, bSameMask, nNewPos );
+
+ if ( nNewPos != nTempPos )
+ {
+ if ( bSameMask )
+ {
+ if ( rEditMask.GetChar( nNewPos ) != EDITMASK_LITERAL )
+ aStr.Erase( nNewPos, 1 );
+ }
+ else
+ {
+ XubString aTempStr = rLiteralMask.Copy( nNewPos, 1 );
+ aStr.Replace( nNewPos, aTempStr.Len(), aTempStr );
+ }
+ }
+ }
+
+ if ( aOldStr != aStr )
+ {
+ if ( bSameMask )
+ aStr = ImplPatternReformat( aStr, rEditMask, rLiteralMask, nFormatFlags );
+ rbInKeyInput = TRUE;
+ pEdit->SetText( aStr, Selection( nNewPos ) );
+ pEdit->SetModifyFlag();
+ pEdit->Modify();
+ rbInKeyInput = FALSE;
+ }
+ else
+ pEdit->SetSelection( Selection( nNewPos ) );
+
+ return TRUE;
+ }
+ else if ( nKeyCode == KEY_INSERT )
+ {
+ // InsertModus kann man beim PatternField nur einstellen,
+ // wenn Maske an jeder Eingabeposition die gleiche
+ // ist
+ if ( !bSameMask )
+ {
+ Sound::Beep();
+ return TRUE;
+ }
+ }
+ }
+
+ if ( rKEvt.GetKeyCode().IsMod2() || (cChar < 32) || (cChar == 127) )
+ return FALSE;
+
+ Selection aSel = aOldSel;
+ aSel.Justify();
+ nNewPos = (xub_StrLen)aSel.Min();
+
+ if ( nNewPos < rEditMask.Len() )
+ {
+ xub_Unicode cPattChar = ImplPatternChar( cChar, rEditMask.GetChar(nNewPos) );
+ if ( cPattChar )
+ cChar = cPattChar;
+ else
+ {
+ // Wenn kein gueltiges Zeichen, dann testen wir, ob der
+ // Anwender zum naechsten Literal springen wollte. Dies machen
+ // wir nur, wenn er hinter einem Zeichen steht, damit
+ // eingebene Literale die automatisch uebersprungenen wurden
+ // nicht dazu fuehren, das der Anwender dann da steht, wo
+ // er nicht stehen wollte.
+ if ( nNewPos &&
+ (rEditMask.GetChar(nNewPos-1) != EDITMASK_LITERAL) &&
+ !aSel.Len() )
+ {
+ // Naechstes Zeichen suchen, was kein Literal ist
+ nTempPos = nNewPos;
+ while ( nTempPos < rEditMask.Len() )
+ {
+ if ( rEditMask.GetChar(nTempPos) == EDITMASK_LITERAL )
+ {
+ // Gilt nur, wenn ein Literalzeichen vorhanden
+ if ( (rEditMask.GetChar(nTempPos+1) != EDITMASK_LITERAL ) &&
+ ImplKommaPointCharEqual( cChar, rLiteralMask.GetChar(nTempPos) ) )
+ {
+ nTempPos++;
+ ImplPatternMaxPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nNewPos, nTempPos );
+ if ( nTempPos > nNewPos )
+ {
+ pEdit->SetSelection( Selection( nTempPos ) );
+ return TRUE;
+ }
+ }
+ break;
+ }
+ nTempPos++;
+ }
+ }
+
+ cChar = 0;
+ }
+ }
+ else
+ cChar = 0;
+ if ( cChar )
+ {
+ XubString aStr = pEdit->GetText();
+ BOOL bError = FALSE;
+ if ( bSameMask && pEdit->IsInsertMode() )
+ {
+ // Text um Spacezeichen und Literale am Ende kuerzen, bis zur
+ // aktuellen Position
+ xub_StrLen n = aStr.Len();
+ while ( n && (n > nNewPos) )
+ {
+ if ( (aStr.GetChar( n-1 ) != ' ') &&
+ ((n > rEditMask.Len()) || (rEditMask.GetChar(n-1) != EDITMASK_LITERAL)) )
+ break;
+
+ n--;
+ }
+ aStr.Erase( n );
+
+ if ( aSel.Len() )
+ aStr.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
+
+ if ( aStr.Len() < rEditMask.Len() )
+ {
+ // String evtl. noch bis Cursor-Position erweitern
+ if ( aStr.Len() < nNewPos )
+ aStr += rLiteralMask.Copy( aStr.Len(), nNewPos-aStr.Len() );
+ if ( nNewPos < aStr.Len() )
+ aStr.Insert( cChar, nNewPos );
+ else if ( nNewPos < rEditMask.Len() )
+ aStr += cChar;
+ aStr = ImplPatternReformat( aStr, rEditMask, rLiteralMask, nFormatFlags );
+ }
+ else
+ bError = TRUE;
+ }
+ else
+ {
+ if ( aSel.Len() )
+ {
+ // Selection loeschen
+ XubString aRep = rLiteralMask.Copy( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
+ aStr.Replace( (xub_StrLen)aSel.Min(), aRep.Len(), aRep );
+ }
+
+ if ( nNewPos < aStr.Len() )
+ aStr.SetChar( nNewPos, cChar );
+ else if ( nNewPos < rEditMask.Len() )
+ aStr += cChar;
+ }
+
+ if ( bError )
+ Sound::Beep();
+ else
+ {
+ rbInKeyInput = TRUE;
+ Selection aNewSel( ImplPatternRightPos( aStr, rEditMask, nFormatFlags, bSameMask, nNewPos ) );
+ pEdit->SetText( aStr, aNewSel );
+ pEdit->SetModifyFlag();
+ pEdit->Modify();
+ rbInKeyInput = FALSE;
+ }
+ }
+ else
+ Sound::Beep();
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void PatternFormatter::ImplSetMask( const ByteString& rEditMask,
+ const XubString& rLiteralMask )
+{
+ maEditMask = rEditMask;
+ maLiteralMask = rLiteralMask;
+ mbSameMask = TRUE;
+
+ if ( maEditMask.Len() != maLiteralMask.Len() )
+ {
+ if ( maEditMask.Len() < maLiteralMask.Len() )
+ maLiteralMask.Erase( maEditMask.Len() );
+ else
+ maLiteralMask.Expand( maEditMask.Len(), ' ' );
+ }
+
+ // StrictModus erlaubt nur Input-Mode, wenn als Maske nur
+ // gleiche Zeichen zugelassen werden und als Vorgabe nur
+ // Spacezeichen vorgegeben werden, die durch die Maske
+ // nicht zugelassen sind
+ xub_StrLen i = 0;
+ sal_Char c = 0;
+ while ( i < rEditMask.Len() )
+ {
+ sal_Char cTemp = rEditMask.GetChar( i );
+ if ( cTemp != EDITMASK_LITERAL )
+ {
+ if ( (cTemp == EDITMASK_ALLCHAR) ||
+ (cTemp == EDITMASK_UPPERALLCHAR) ||
+ (cTemp == EDITMASK_NUMSPACE) )
+ {
+ mbSameMask = FALSE;
+ break;
+ }
+ if ( i < rLiteralMask.Len() )
+ {
+ if ( rLiteralMask.GetChar( i ) != ' ' )
+ {
+ mbSameMask = FALSE;
+ break;
+ }
+ }
+ if ( !c )
+ c = cTemp;
+ if ( cTemp != c )
+ {
+ mbSameMask = FALSE;
+ break;
+ }
+ }
+ i++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+PatternFormatter::PatternFormatter()
+{
+ mnFormatFlags = 0;
+ mbSameMask = TRUE;
+ mbInPattKeyInput = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void PatternFormatter::ImplLoadRes( const ResId& rResId )
+{
+ ByteString aEditMask;
+ XubString aLiteralMask;
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ {
+ ULONG nMask = pMgr->ReadLong();
+
+ if ( PATTERNFORMATTER_STRICTFORMAT & nMask )
+ SetStrictFormat( (BOOL)pMgr->ReadShort() );
+
+ if ( PATTERNFORMATTER_EDITMASK & nMask )
+ aEditMask = ByteString( pMgr->ReadString(), RTL_TEXTENCODING_ASCII_US );
+
+ if ( PATTERNFORMATTER_LITTERALMASK & nMask )
+ aLiteralMask = pMgr->ReadString();
+
+ if ( (PATTERNFORMATTER_EDITMASK | PATTERNFORMATTER_LITTERALMASK) & nMask )
+ ImplSetMask( aEditMask, aLiteralMask );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+PatternFormatter::~PatternFormatter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void PatternFormatter::SetMask( const ByteString& rEditMask,
+ const XubString& rLiteralMask )
+{
+ ImplSetMask( rEditMask, rLiteralMask );
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void PatternFormatter::SetString( const XubString& rStr )
+{
+ maFieldString = rStr;
+ if ( GetField() )
+ {
+ GetField()->SetText( rStr );
+ MarkToBeReformatted( FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString PatternFormatter::GetString() const
+{
+ if ( !GetField() )
+ return ImplGetSVEmptyStr();
+ else
+ return ImplPatternReformat( GetField()->GetText(), maEditMask, maLiteralMask, mnFormatFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void PatternFormatter::Reformat()
+{
+ if ( GetField() )
+ {
+ ImplSetText( ImplPatternReformat( GetField()->GetText(), maEditMask, maLiteralMask, mnFormatFlags ) );
+ if ( !mbSameMask && IsStrictFormat() && !GetField()->IsReadOnly() )
+ GetField()->SetInsertMode( FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PatternFormatter::SelectFixedFont()
+{
+ if ( GetField() )
+ {
+ Font aFont = OutputDevice::GetDefaultFont( DEFAULTFONT_FIXED, Application::GetSettings().GetLanguage(), 0 );
+ Font aControlFont;
+ aControlFont.SetName( aFont.GetName() );
+ aControlFont.SetFamily( aFont.GetFamily() );
+ aControlFont.SetPitch( aFont.GetPitch() );
+ GetField()->SetControlFont( aControlFont );
+ }
+}
+
+ // -----------------------------------------------------------------------
+
+PatternField::PatternField( Window* pParent, WinBits nWinStyle ) :
+ SpinField( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+PatternField::PatternField( Window* pParent, const ResId& rResId ) :
+ SpinField( WINDOW_PATTERNFIELD )
+{
+ rResId.SetRT( RSC_PATTERNFIELD );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ SetField( this );
+ SpinField::ImplLoadRes( rResId );
+ PatternFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+PatternField::~PatternField()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long PatternField::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
+ IsStrictFormat(), GetFormatFlags(),
+ ImplIsSameMask(), ImplGetInPattKeyInput() ) )
+ return 1;
+ }
+
+ return SpinField::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long PatternField::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return SpinField::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void PatternField::Modify()
+{
+ if ( !ImplGetInPattKeyInput() )
+ {
+ if ( IsStrictFormat() )
+ ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
+ else
+ MarkToBeReformatted( TRUE );
+ }
+
+ SpinField::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+PatternBox::PatternBox( Window* pParent, WinBits nWinStyle ) :
+ ComboBox( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+PatternBox::PatternBox( Window* pParent, const ResId& rResId ) :
+ ComboBox( WINDOW_PATTERNBOX )
+{
+ rResId.SetRT( RSC_PATTERNBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+
+ SetField( this );
+ ComboBox::ImplLoadRes( rResId );
+ PatternFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+PatternBox::~PatternBox()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long PatternBox::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
+ IsStrictFormat(), GetFormatFlags(),
+ ImplIsSameMask(), ImplGetInPattKeyInput() ) )
+ return 1;
+ }
+
+ return ComboBox::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long PatternBox::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return ComboBox::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void PatternBox::Modify()
+{
+ if ( !ImplGetInPattKeyInput() )
+ {
+ if ( IsStrictFormat() )
+ ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
+ else
+ MarkToBeReformatted( TRUE );
+ }
+
+ ComboBox::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void PatternBox::ReformatAll()
+{
+ XubString aStr;
+ SetUpdateMode( FALSE );
+ USHORT nEntryCount = GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ aStr = ImplPatternReformat( GetEntry( i ), GetEditMask(), GetLiteralMask(), GetFormatFlags() );
+ RemoveEntry( i );
+ InsertEntry( aStr, i );
+ }
+ PatternFormatter::Reformat();
+ SetUpdateMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void PatternBox::InsertString( const XubString& rStr, USHORT nPos )
+{
+ ComboBox::InsertEntry( ImplPatternReformat( rStr, GetEditMask(), GetLiteralMask(), GetFormatFlags() ), nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void PatternBox::RemoveString( const XubString& rStr )
+{
+ ComboBox::RemoveEntry( ImplPatternReformat( rStr, GetEditMask(), GetLiteralMask(), GetFormatFlags() ) );
+}
+
+// -----------------------------------------------------------------------
+
+XubString PatternBox::GetString( USHORT nPos ) const
+{
+ return ImplPatternReformat( ComboBox::GetEntry( nPos ), GetEditMask(), GetLiteralMask(), GetFormatFlags() );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT PatternBox::GetStringPos( const XubString& rStr ) const
+{
+ return ComboBox::GetEntryPos( ImplPatternReformat( rStr, GetEditMask(), GetLiteralMask(), GetFormatFlags() ) );
+}
+
+// =======================================================================
+
+static ExtDateFieldFormat ImplGetExtFormat( DateFormat eOld )
+{
+ switch( eOld )
+ {
+ case DMY: return XTDATEF_SHORT_DDMMYY;
+ case MDY: return XTDATEF_SHORT_MMDDYY;
+ default: return XTDATEF_SHORT_YYMMDD;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplCutNumberFromString( XubString& rStr )
+{
+ // Nach Zahl suchen
+ while ( rStr.Len() && !(rStr.GetChar( 0 ) >= '0' && rStr.GetChar( 0 ) <= '9') )
+ rStr.Erase( 0, 1 );
+ if ( !rStr.Len() )
+ return 0;
+ XubString aNumStr;
+ while ( rStr.Len() && (rStr.GetChar( 0 ) >= '0' && rStr.GetChar( 0 ) <= '9') )
+ {
+ aNumStr.Insert( rStr.GetChar( 0 ) );
+ rStr.Erase( 0, 1 );
+ }
+ return (USHORT)aNumStr.ToInt32();
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplCutMonthName( XubString& rStr, const XubString& _rLookupMonthName )
+{
+ USHORT nPos = rStr.Search( _rLookupMonthName );
+ if ( nPos != STRING_NOTFOUND )
+ {
+ rStr.Erase( 0, nPos + _rLookupMonthName.Len() );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplCutMonthFromString( XubString& rStr, const CalendarWrapper& rCalendarWrapper )
+{
+ // search for a month' name
+ for ( USHORT i=1; i <= 12; i++ )
+ {
+ String aMonthName = rCalendarWrapper.getMonths()[i-1].FullName;
+ // long month name?
+ if ( ImplCutMonthName( rStr, aMonthName ) )
+ return i;
+
+ // short month name?
+ String aAbbrevMonthName = rCalendarWrapper.getMonths()[i-1].AbbrevName;
+ if ( ImplCutMonthName( rStr, aAbbrevMonthName ) )
+ return i;
+ }
+
+ return ImplCutNumberFromString( rStr );
+}
+
+// -----------------------------------------------------------------------
+
+static String ImplGetDateSep( const LocaleDataWrapper& rLocaleDataWrapper, ExtDateFieldFormat eFormat )
+{
+ String aDateSep = rLocaleDataWrapper.getDateSep();
+
+ if ( ( eFormat == XTDATEF_SHORT_YYMMDD_DIN5008 ) || ( eFormat == XTDATEF_SHORT_YYYYMMDD_DIN5008 ) )
+ aDateSep = String( RTL_CONSTASCII_USTRINGPARAM( "-" ) );
+
+ return aDateSep;
+}
+
+static BOOL ImplDateProcessKeyInput( Edit*, const KeyEvent& rKEvt, ExtDateFieldFormat eFormat,
+ const LocaleDataWrapper& rLocaleDataWrapper )
+{
+ xub_Unicode cChar = rKEvt.GetCharCode();
+ USHORT nGroup = rKEvt.GetKeyCode().GetGroup();
+ if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
+ (nGroup == KEYGROUP_MISC)||
+ ((cChar >= '0') && (cChar <= '9')) ||
+ (cChar == ImplGetDateSep( rLocaleDataWrapper, eFormat ).GetChar(0) ) )
+ return FALSE;
+ else
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplDateGetValue( const XubString& rStr, Date& rDate, ExtDateFieldFormat eDateFormat,
+ const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper,
+ const AllSettings& )
+{
+ USHORT nDay = 0;
+ USHORT nMonth = 0;
+ USHORT nYear = 0;
+ BOOL bYear = TRUE;
+ BOOL bError = FALSE;
+ String aStr( rStr );
+
+ if ( eDateFormat == XTDATEF_SYSTEM_LONG )
+ {
+ DateFormat eFormat = rLocaleDataWrapper.getLongDateFormat();
+ switch( eFormat )
+ {
+ case MDY:
+ nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
+ nDay = ImplCutNumberFromString( aStr );
+ nYear = ImplCutNumberFromString( aStr );
+ break;
+ case DMY:
+ nDay = ImplCutNumberFromString( aStr );
+ nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
+ nYear = ImplCutNumberFromString( aStr );
+ break;
+ case YMD:
+ default:
+ nYear = ImplCutNumberFromString( aStr );
+ nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
+ nDay = ImplCutNumberFromString( aStr );
+ break;
+ }
+ }
+ else
+ {
+ // Check if year is present:
+ String aDateSep = ImplGetDateSep( rLocaleDataWrapper, eDateFormat );
+ USHORT nSepPos = aStr.Search( aDateSep );
+ if ( nSepPos == STRING_NOTFOUND )
+ return FALSE;
+ nSepPos = aStr.Search( aDateSep, nSepPos+1 );
+ if ( ( nSepPos == STRING_NOTFOUND ) || ( nSepPos == (aStr.Len()-1) ) )
+ {
+ bYear = FALSE;
+ nYear = Date().GetYear();
+ }
+
+ const sal_Unicode* pBuf = aStr.GetBuffer();
+ ImplSkipDelimiters( pBuf );
+
+ switch ( eDateFormat )
+ {
+ case XTDATEF_SHORT_DDMMYY:
+ case XTDATEF_SHORT_DDMMYYYY:
+ {
+ nDay = ImplGetNum( pBuf, bError );
+ ImplSkipDelimiters( pBuf );
+ nMonth = ImplGetNum( pBuf, bError );
+ ImplSkipDelimiters( pBuf );
+ if ( bYear )
+ nYear = ImplGetNum( pBuf, bError );
+ }
+ break;
+ case XTDATEF_SHORT_MMDDYY:
+ case XTDATEF_SHORT_MMDDYYYY:
+ {
+ nMonth = ImplGetNum( pBuf, bError );
+ ImplSkipDelimiters( pBuf );
+ nDay = ImplGetNum( pBuf, bError );
+ ImplSkipDelimiters( pBuf );
+ if ( bYear )
+ nYear = ImplGetNum( pBuf, bError );
+ }
+ break;
+ case XTDATEF_SHORT_YYMMDD:
+ case XTDATEF_SHORT_YYYYMMDD:
+ case XTDATEF_SHORT_YYMMDD_DIN5008:
+ case XTDATEF_SHORT_YYYYMMDD_DIN5008:
+ {
+ if ( bYear )
+ nYear = ImplGetNum( pBuf, bError );
+ ImplSkipDelimiters( pBuf );
+ nMonth = ImplGetNum( pBuf, bError );
+ ImplSkipDelimiters( pBuf );
+ nDay = ImplGetNum( pBuf, bError );
+ }
+ break;
+
+ default:
+ {
+ DBG_ERROR( "DateFormat???" );
+ }
+ }
+ }
+
+ if ( bError || !nDay || !nMonth )
+ return FALSE;
+
+ Date aNewDate( nDay, nMonth, nYear );
+ DateFormatter::ExpandCentury( aNewDate, utl::MiscCfg().GetYear2000() );
+ if ( aNewDate.IsValid() )
+ {
+ rDate = aNewDate;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DateFormatter::ImplDateReformat( const XubString& rStr, XubString& rOutStr, const AllSettings& rSettings )
+{
+ Date aDate( 0, 0, 0 );
+ if ( !ImplDateGetValue( rStr, aDate, GetExtDateFormat(TRUE), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
+ return TRUE;
+
+ Date aTempDate = aDate;
+ if ( aTempDate > GetMax() )
+ aTempDate = GetMax();
+ else if ( aTempDate < GetMin() )
+ aTempDate = GetMin();
+
+ if ( GetErrorHdl().IsSet() && (aDate != aTempDate) )
+ {
+ maCorrectedDate = aTempDate;
+ if( !GetErrorHdl().Call( this ) )
+ {
+ maCorrectedDate = Date();
+ return FALSE;
+ }
+ else
+ maCorrectedDate = Date();
+ }
+
+ rOutStr = ImplGetDateAsText( aTempDate, rSettings );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+XubString DateFormatter::ImplGetDateAsText( const Date& rDate,
+ const AllSettings& ) const
+{
+ BOOL bShowCentury = FALSE;
+ switch ( GetExtDateFormat() )
+ {
+ case XTDATEF_SYSTEM_SHORT_YYYY:
+ case XTDATEF_SYSTEM_LONG:
+ case XTDATEF_SHORT_DDMMYYYY:
+ case XTDATEF_SHORT_MMDDYYYY:
+ case XTDATEF_SHORT_YYYYMMDD:
+ case XTDATEF_SHORT_YYYYMMDD_DIN5008:
+ {
+ bShowCentury = TRUE;
+ }
+ break;
+ default:
+ {
+ bShowCentury = FALSE;
+ }
+ }
+
+ if ( !bShowCentury )
+ {
+ // Check if I have to use force showing the century
+ USHORT nTwoDigitYearStart = utl::MiscCfg().GetYear2000();
+ USHORT nYear = rDate.GetYear();
+
+ // Wenn Jahr nicht im 2stelligen Grenzbereich liegt,
+ if ( (nYear < nTwoDigitYearStart) || (nYear >= nTwoDigitYearStart+100) )
+ bShowCentury = TRUE;
+ }
+
+ sal_Unicode aBuf[128];
+ sal_Unicode* pBuf = aBuf;
+
+ String aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), GetExtDateFormat( TRUE ) );
+ USHORT nDay = rDate.GetDay();
+ USHORT nMonth = rDate.GetMonth();
+ USHORT nYear = rDate.GetYear();
+ USHORT nYearLen = bShowCentury ? 4 : 2;
+
+ if ( !bShowCentury )
+ nYear %= 100;
+
+ switch ( GetExtDateFormat( TRUE ) )
+ {
+ case XTDATEF_SYSTEM_LONG:
+ {
+ return ImplGetLocaleDataWrapper().getLongDate( rDate, GetCalendarWrapper(), 1, FALSE, 1, !bShowCentury );
+ }
+ case XTDATEF_SHORT_DDMMYY:
+ case XTDATEF_SHORT_DDMMYYYY:
+ {
+ pBuf = ImplAddNum( pBuf, nDay, 2 );
+ pBuf = ImplAddString( pBuf, aDateSep );
+ pBuf = ImplAddNum( pBuf, nMonth, 2 );
+ pBuf = ImplAddString( pBuf, aDateSep );
+ pBuf = ImplAddNum( pBuf, nYear, nYearLen );
+ }
+ break;
+ case XTDATEF_SHORT_MMDDYY:
+ case XTDATEF_SHORT_MMDDYYYY:
+ {
+ pBuf = ImplAddNum( pBuf, nMonth, 2 );
+ pBuf = ImplAddString( pBuf, aDateSep );
+ pBuf = ImplAddNum( pBuf, nDay, 2 );
+ pBuf = ImplAddString( pBuf, aDateSep );
+ pBuf = ImplAddNum( pBuf, nYear, nYearLen );
+ }
+ break;
+ case XTDATEF_SHORT_YYMMDD:
+ case XTDATEF_SHORT_YYYYMMDD:
+ case XTDATEF_SHORT_YYMMDD_DIN5008:
+ case XTDATEF_SHORT_YYYYMMDD_DIN5008:
+ {
+ pBuf = ImplAddNum( pBuf, nYear, nYearLen );
+ pBuf = ImplAddString( pBuf, aDateSep );
+ pBuf = ImplAddNum( pBuf, nMonth, 2 );
+ pBuf = ImplAddString( pBuf, aDateSep );
+ pBuf = ImplAddNum( pBuf, nDay, 2 );
+ }
+ break;
+ default:
+ {
+ DBG_ERROR( "DateFormat???" );
+ }
+ }
+
+ return String( aBuf, (xub_StrLen)(ULONG)(pBuf-aBuf) );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDateIncrementDay( Date& rDate, BOOL bUp )
+{
+ DateFormatter::ExpandCentury( rDate );
+
+ if ( bUp )
+ {
+ if ( (rDate.GetDay() != 31) || (rDate.GetMonth() != 12) || (rDate.GetYear() != 9999) )
+ rDate++;
+ }
+ else
+ {
+ if ( (rDate.GetDay() != 1 ) || (rDate.GetMonth() != 1) || (rDate.GetYear() != 0) )
+ rDate--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDateIncrementMonth( Date& rDate, BOOL bUp )
+{
+ DateFormatter::ExpandCentury( rDate );
+
+ USHORT nMonth = rDate.GetMonth();
+ USHORT nYear = rDate.GetYear();
+ if ( bUp )
+ {
+ if ( (nMonth == 12) && (nYear < 9999) )
+ {
+ rDate.SetMonth( 1 );
+ rDate.SetYear( nYear + 1 );
+ }
+ else
+ {
+ if ( nMonth < 12 )
+ rDate.SetMonth( nMonth + 1 );
+ }
+ }
+ else
+ {
+ if ( (nMonth == 1) && (nYear > 0) )
+ {
+ rDate.SetMonth( 12 );
+ rDate.SetYear( nYear - 1 );
+ }
+ else
+ {
+ if ( nMonth > 1 )
+ rDate.SetMonth( nMonth - 1 );
+ }
+ }
+
+ USHORT nDaysInMonth = rDate.GetDaysInMonth();
+ if ( rDate.GetDay() > nDaysInMonth )
+ rDate.SetDay( nDaysInMonth );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDateIncrementYear( Date& rDate, BOOL bUp )
+{
+ DateFormatter::ExpandCentury( rDate );
+
+ USHORT nYear = rDate.GetYear();
+ if ( bUp )
+ {
+ if ( nYear < 9999 )
+ rDate.SetYear( nYear + 1 );
+ }
+ else
+ {
+ if ( nYear > 0 )
+ rDate.SetYear( nYear - 1 );
+ }
+}
+
+// -----------------------------------------------------------------------
+BOOL DateFormatter::ImplAllowMalformedInput() const
+{
+ return !IsEnforceValidValue();
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::ImplDateSpinArea( BOOL bUp )
+{
+ // Wenn alles selektiert ist, Tage hochzaehlen
+ if ( GetField() )
+ {
+ Date aDate( GetDate() );
+ Selection aSelection = GetField()->GetSelection();
+ aSelection.Justify();
+ XubString aText( GetText() );
+ if ( (xub_StrLen)aSelection.Len() == aText.Len() )
+ ImplDateIncrementDay( aDate, bUp );
+ else
+ {
+ xub_StrLen nDateArea = 0;
+
+ ExtDateFieldFormat eFormat = GetExtDateFormat( TRUE );
+ if ( eFormat == XTDATEF_SYSTEM_LONG )
+ {
+ eFormat = ImplGetExtFormat( ImplGetLocaleDataWrapper().getLongDateFormat() );
+ nDateArea = 1;
+ }
+ else
+ {
+ // Area suchen
+ xub_StrLen nPos = 0;
+ String aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), eFormat );
+ for ( xub_StrLen i = 1; i <= 3; i++ )
+ {
+ nPos = aText.Search( aDateSep, nPos );
+ if ( nPos >= (USHORT)aSelection.Max() )
+ {
+ nDateArea = i;
+ break;
+ }
+ else
+ nPos++;
+ }
+ }
+
+
+ switch( eFormat )
+ {
+ case XTDATEF_SHORT_MMDDYY:
+ case XTDATEF_SHORT_MMDDYYYY:
+ switch( nDateArea )
+ {
+ case 1: ImplDateIncrementMonth( aDate, bUp );
+ break;
+ case 2: ImplDateIncrementDay( aDate, bUp );
+ break;
+ case 3: ImplDateIncrementYear( aDate, bUp );
+ break;
+ }
+ break;
+ case XTDATEF_SHORT_DDMMYY:
+ case XTDATEF_SHORT_DDMMYYYY:
+ switch( nDateArea )
+ {
+ case 1: ImplDateIncrementDay( aDate, bUp );
+ break;
+ case 2: ImplDateIncrementMonth( aDate, bUp );
+ break;
+ case 3: ImplDateIncrementYear( aDate, bUp );
+ break;
+ }
+ break;
+ case XTDATEF_SHORT_YYMMDD:
+ case XTDATEF_SHORT_YYYYMMDD:
+ case XTDATEF_SHORT_YYMMDD_DIN5008:
+ case XTDATEF_SHORT_YYYYMMDD_DIN5008:
+ switch( nDateArea )
+ {
+ case 1: ImplDateIncrementYear( aDate, bUp );
+ break;
+ case 2: ImplDateIncrementMonth( aDate, bUp );
+ break;
+ case 3: ImplDateIncrementDay( aDate, bUp );
+ break;
+ }
+ break;
+ default:
+ DBG_ERROR( "invalid conversion" );
+ break;
+ }
+ }
+
+ ImplNewFieldValue( aDate );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::ImplInit()
+{
+ mbLongFormat = FALSE;
+ mbShowDateCentury = TRUE;
+ mpCalendarWrapper = NULL;
+ mnDateFormat = 0xFFFF;
+ mnExtDateFormat = XTDATEF_SYSTEM_SHORT;
+}
+
+// -----------------------------------------------------------------------
+
+DateFormatter::DateFormatter() :
+ maFieldDate( 0 ),
+ maLastDate( 0 ),
+ maMin( 1, 1, 1900 ),
+ maMax( 31, 12, 2200 ),
+ mbEnforceValidValue( TRUE )
+{
+ ImplInit();
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::ImplLoadRes( const ResId& rResId )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ {
+ ULONG nMask = pMgr->ReadLong();
+
+ if ( DATEFORMATTER_MIN & nMask )
+ {
+ maMin = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
+ pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
+ }
+ if ( DATEFORMATTER_MAX & nMask )
+ {
+ maMax = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
+ pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
+ }
+ if ( DATEFORMATTER_LONGFORMAT & nMask )
+ mbLongFormat = (BOOL)pMgr->ReadShort();
+
+ if ( DATEFORMATTER_STRICTFORMAT & nMask )
+ SetStrictFormat( (BOOL)pMgr->ReadShort() );
+
+ if ( DATEFORMATTER_VALUE & nMask )
+ {
+ maFieldDate = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
+ pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
+ if ( maFieldDate > maMax )
+ maFieldDate = maMax;
+ if ( maFieldDate < maMin )
+ maFieldDate = maMin;
+ maLastDate = maFieldDate;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+DateFormatter::~DateFormatter()
+{
+ delete mpCalendarWrapper;
+ mpCalendarWrapper = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetLocale( const ::com::sun::star::lang::Locale& rLocale )
+{
+ delete mpCalendarWrapper;
+ mpCalendarWrapper = NULL;
+ FormatterBase::SetLocale( rLocale );
+}
+
+
+// -----------------------------------------------------------------------
+
+CalendarWrapper& DateFormatter::GetCalendarWrapper() const
+{
+ if ( !mpCalendarWrapper )
+ {
+ ((DateFormatter*)this)->mpCalendarWrapper = new CalendarWrapper( vcl::unohelper::GetMultiServiceFactory() );
+ mpCalendarWrapper->loadDefaultCalendar( GetLocale() );
+ }
+
+ return *mpCalendarWrapper;
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetExtDateFormat( ExtDateFieldFormat eFormat )
+{
+ mnExtDateFormat = eFormat;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+ExtDateFieldFormat DateFormatter::GetExtDateFormat( BOOL bResolveSystemFormat ) const
+{
+ ExtDateFieldFormat eDateFormat = (ExtDateFieldFormat)mnExtDateFormat;
+
+ if ( bResolveSystemFormat && ( eDateFormat <= XTDATEF_SYSTEM_SHORT_YYYY ) )
+ {
+ BOOL bShowCentury = (eDateFormat == XTDATEF_SYSTEM_SHORT_YYYY);
+ switch ( ImplGetLocaleDataWrapper().getDateFormat() )
+ {
+ case DMY: eDateFormat = bShowCentury ? XTDATEF_SHORT_DDMMYYYY : XTDATEF_SHORT_DDMMYY;
+ break;
+ case MDY: eDateFormat = bShowCentury ? XTDATEF_SHORT_MMDDYYYY : XTDATEF_SHORT_MMDDYY;
+ break;
+ default: eDateFormat = bShowCentury ? XTDATEF_SHORT_YYYYMMDD : XTDATEF_SHORT_YYMMDD;
+
+ }
+ }
+
+ return eDateFormat;
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::ReformatAll()
+{
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetMin( const Date& rNewMin )
+{
+ maMin = rNewMin;
+ if ( !IsEmptyFieldValue() )
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetMax( const Date& rNewMax )
+{
+ maMax = rNewMax;
+ if ( !IsEmptyFieldValue() )
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetLongFormat( BOOL bLong )
+{
+ mbLongFormat = bLong;
+
+ // #91913# Remove LongFormat and DateShowCentury - redundant
+ if ( bLong )
+ {
+ SetExtDateFormat( XTDATEF_SYSTEM_LONG );
+ }
+ else
+ {
+ if( mnExtDateFormat == XTDATEF_SYSTEM_LONG )
+ SetExtDateFormat( XTDATEF_SYSTEM_SHORT );
+ }
+
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetShowDateCentury( BOOL bShowDateCentury )
+{
+ mbShowDateCentury = bShowDateCentury;
+
+ // #91913# Remove LongFormat and DateShowCentury - redundant
+ if ( bShowDateCentury )
+ {
+ switch ( GetExtDateFormat() )
+ {
+ case XTDATEF_SYSTEM_SHORT:
+ case XTDATEF_SYSTEM_SHORT_YY:
+ SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YYYY ); break;
+ case XTDATEF_SHORT_DDMMYY:
+ SetExtDateFormat( XTDATEF_SHORT_DDMMYYYY ); break;
+ case XTDATEF_SHORT_MMDDYY:
+ SetExtDateFormat( XTDATEF_SHORT_MMDDYYYY ); break;
+ case XTDATEF_SHORT_YYMMDD:
+ SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD ); break;
+ case XTDATEF_SHORT_YYMMDD_DIN5008:
+ SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD_DIN5008 ); break;
+ default:
+ ;
+ }
+ }
+ else
+ {
+ switch ( GetExtDateFormat() )
+ {
+ case XTDATEF_SYSTEM_SHORT:
+ case XTDATEF_SYSTEM_SHORT_YYYY:
+ SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YY ); break;
+ case XTDATEF_SHORT_DDMMYYYY:
+ SetExtDateFormat( XTDATEF_SHORT_DDMMYY ); break;
+ case XTDATEF_SHORT_MMDDYYYY:
+ SetExtDateFormat( XTDATEF_SHORT_MMDDYY ); break;
+ case XTDATEF_SHORT_YYYYMMDD:
+ SetExtDateFormat( XTDATEF_SHORT_YYMMDD ); break;
+ case XTDATEF_SHORT_YYYYMMDD_DIN5008:
+ SetExtDateFormat( XTDATEF_SHORT_YYMMDD_DIN5008 ); break;
+ default:
+ ;
+ }
+ }
+
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetDate( const Date& rNewDate )
+{
+ SetUserDate( rNewDate );
+ maFieldDate = maLastDate;
+ maLastDate = GetDate();
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetUserDate( const Date& rNewDate )
+{
+ ImplSetUserDate( rNewDate );
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::ImplSetUserDate( const Date& rNewDate, Selection* pNewSelection )
+{
+ Date aNewDate = rNewDate;
+ if ( aNewDate > maMax )
+ aNewDate = maMax;
+ else if ( aNewDate < maMin )
+ aNewDate = maMin;
+ maLastDate = aNewDate;
+
+ if ( GetField() )
+ ImplSetText( ImplGetDateAsText( aNewDate, GetFieldSettings() ), pNewSelection );
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::ImplNewFieldValue( const Date& rDate )
+{
+ if ( GetField() )
+ {
+ Selection aSelection = GetField()->GetSelection();
+ aSelection.Justify();
+ XubString aText = GetField()->GetText();
+ // Wenn bis ans Ende selektiert war, soll das auch so bleiben...
+ if ( (xub_StrLen)aSelection.Max() == aText.Len() )
+ {
+ if ( !aSelection.Len() )
+ aSelection.Min() = SELECTION_MAX;
+ aSelection.Max() = SELECTION_MAX;
+ }
+
+ Date aOldLastDate = maLastDate;
+ ImplSetUserDate( rDate, &aSelection );
+ maLastDate = aOldLastDate;
+
+ // Modify am Edit wird nur bei KeyInput gesetzt...
+ if ( GetField()->GetText() != aText )
+ {
+ GetField()->SetModifyFlag();
+ GetField()->Modify();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Date DateFormatter::GetDate() const
+{
+ Date aDate( 0, 0, 0 );
+
+ if ( GetField() )
+ {
+ if ( ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(TRUE), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
+ {
+ if ( aDate > maMax )
+ aDate = maMax;
+ else if ( aDate < maMin )
+ aDate = maMin;
+ }
+ else
+ {
+ // !!! TH-18.2.99: Wenn wir Zeit haben sollte einmal
+ // !!! geklaert werden, warum dieses beim Datum gegenueber
+ // !!! allen anderen Feldern anders behandelt wird.
+ // !!! Siehe dazu Bug: 52304
+
+ if ( !ImplAllowMalformedInput() )
+ {
+ if ( maLastDate.GetDate() )
+ aDate = maLastDate;
+ else if ( !IsEmptyFieldValueEnabled() )
+ aDate = Date();
+ }
+ else
+ aDate = GetInvalidDate();
+ }
+ }
+
+ return aDate;
+}
+
+// -----------------------------------------------------------------------
+
+Date DateFormatter::GetRealDate() const
+{
+ // !!! TH-18.2.99: Wenn wir Zeit haben sollte dieses auch einmal
+ // !!! fuer die Numeric-Klassen eingebaut werden.
+
+ Date aDate( 0, 0, 0 );
+
+ if ( GetField() )
+ {
+ if ( !ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(TRUE), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
+ if ( ImplAllowMalformedInput() )
+ aDate = GetInvalidDate();
+ }
+
+ return aDate;
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::SetEmptyDate()
+{
+ FormatterBase::SetEmptyFieldValue();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DateFormatter::IsEmptyDate() const
+{
+ BOOL bEmpty = FormatterBase::IsEmptyFieldValue();
+
+ if ( GetField() && MustBeReformatted() && IsEmptyFieldValueEnabled() )
+ {
+ if ( !GetField()->GetText().Len() )
+ {
+ bEmpty = TRUE;
+ }
+ else if ( !maLastDate.GetDate() )
+ {
+ Date aDate;
+ bEmpty = !ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(TRUE), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
+ }
+ }
+ return bEmpty;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DateFormatter::IsDateModified() const
+{
+ if ( ImplGetEmptyFieldValue() )
+ return !IsEmptyDate();
+ else if ( GetDate() != maFieldDate )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::Reformat()
+{
+ if ( !GetField() )
+ return;
+
+ if ( !GetField()->GetText().Len() && ImplGetEmptyFieldValue() )
+ return;
+
+ XubString aStr;
+ BOOL bOK = ImplDateReformat( GetField()->GetText(), aStr, GetFieldSettings() );
+ if( !bOK )
+ return;
+
+ if ( aStr.Len() )
+ {
+ ImplSetText( aStr );
+ ImplDateGetValue( aStr, maLastDate, GetExtDateFormat(TRUE), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
+ }
+ else
+ {
+ if ( maLastDate.GetDate() )
+ SetDate( maLastDate );
+ else if ( !IsEmptyFieldValueEnabled() )
+ SetDate( Date() );
+ else
+ {
+ ImplSetText( ImplGetSVEmptyStr() );
+ SetEmptyFieldValueData( TRUE );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::ExpandCentury( Date& rDate )
+{
+ ExpandCentury( rDate, utl::MiscCfg().GetYear2000() );
+}
+
+// -----------------------------------------------------------------------
+
+void DateFormatter::ExpandCentury( Date& rDate, USHORT nTwoDigitYearStart )
+{
+ USHORT nDateYear = rDate.GetYear();
+ if ( nDateYear < 100 )
+ {
+ USHORT nCentury = nTwoDigitYearStart / 100;
+ if ( nDateYear < (nTwoDigitYearStart % 100) )
+ nCentury++;
+ rDate.SetYear( nDateYear + (nCentury*100) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+DateField::DateField( Window* pParent, WinBits nWinStyle ) :
+ SpinField( pParent, nWinStyle ),
+ maFirst( GetMin() ),
+ maLast( GetMax() )
+{
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
+ Reformat();
+ ResetLastDate();
+}
+
+// -----------------------------------------------------------------------
+
+DateField::DateField( Window* pParent, const ResId& rResId ) :
+ SpinField( WINDOW_DATEFIELD ),
+ maFirst( GetMin() ),
+ maLast( GetMax() )
+{
+ rResId.SetRT( RSC_DATEFIELD );
+ WinBits nStyle = ImplInitRes( rResId );
+ SpinField::ImplInit( pParent, nStyle );
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+
+ ResetLastDate();
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::ImplLoadRes( const ResId& rResId )
+{
+ SpinField::ImplLoadRes( rResId );
+
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ {
+ DateFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+
+ ULONG nMask = ReadLongRes();
+ if ( DATEFIELD_FIRST & nMask )
+ {
+ maFirst = Date( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+ if ( DATEFIELD_LAST & nMask )
+ {
+ maLast = Date( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+ }
+
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+DateField::~DateField()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long DateField::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && IsStrictFormat() &&
+ ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
+ !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( TRUE ), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return SpinField::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long DateField::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() )
+ {
+ // !!! TH-18.2.99: Wenn wir Zeit haben sollte einmal
+ // !!! geklaert werden, warum dieses beim Datum gegenueber
+ // !!! allen anderen Feldern anders behandelt wird.
+ // !!! Siehe dazu Bug: 52304
+
+ BOOL bTextLen = GetText().Len() != 0;
+ if ( bTextLen || !IsEmptyFieldValueEnabled() )
+ {
+ if ( !ImplAllowMalformedInput() )
+ Reformat();
+ else
+ {
+ Date aDate( 0, 0, 0 );
+ if ( ImplDateGetValue( GetText(), aDate, GetExtDateFormat(TRUE), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
+ // even with strict text analysis, our text is a valid date -> do a complete
+ // reformat
+ Reformat();
+ }
+ }
+ else if ( !bTextLen && IsEmptyFieldValueEnabled() )
+ {
+ ResetLastDate();
+ SetEmptyFieldValueData( TRUE );
+ }
+ }
+ }
+
+ return SpinField::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SpinField::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & (SETTINGS_LOCALE|SETTINGS_MISC)) )
+ {
+ if ( IsDefaultLocale() && ( rDCEvt.GetFlags() & SETTINGS_LOCALE ) )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ SpinField::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::Up()
+{
+ ImplDateSpinArea( TRUE );
+ SpinField::Up();
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::Down()
+{
+ ImplDateSpinArea( FALSE );
+ SpinField::Down();
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::First()
+{
+ ImplNewFieldValue( maFirst );
+ SpinField::First();
+}
+
+// -----------------------------------------------------------------------
+
+void DateField::Last()
+{
+ ImplNewFieldValue( maLast );
+ SpinField::Last();
+}
+
+// -----------------------------------------------------------------------
+
+DateBox::DateBox( Window* pParent, WinBits nWinStyle ) :
+ ComboBox( pParent, nWinStyle )
+{
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+DateBox::DateBox( Window* pParent, const ResId& rResId ) :
+ ComboBox( WINDOW_DATEBOX )
+{
+ rResId.SetRT( RSC_DATEBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ComboBox::ImplInit( pParent, nStyle );
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
+ ComboBox::ImplLoadRes( rResId );
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ DateFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+ Reformat();
+
+ if ( !( nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+DateBox::~DateBox()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long DateBox::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && IsStrictFormat() &&
+ ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
+ !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( TRUE ), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return ComboBox::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void DateBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ ComboBox::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long DateBox::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() )
+ {
+ BOOL bTextLen = GetText().Len() != 0;
+ if ( bTextLen || !IsEmptyFieldValueEnabled() )
+ Reformat();
+ else if ( !bTextLen && IsEmptyFieldValueEnabled() )
+ {
+ ResetLastDate();
+ SetEmptyFieldValueData( TRUE );
+ }
+ }
+ }
+
+ return ComboBox::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void DateBox::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ ComboBox::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void DateBox::ReformatAll()
+{
+ XubString aStr;
+ SetUpdateMode( FALSE );
+ USHORT nEntryCount = GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ ImplDateReformat( GetEntry( i ), aStr, GetFieldSettings() );
+ RemoveEntry( i );
+ InsertEntry( aStr, i );
+ }
+ DateFormatter::Reformat();
+ SetUpdateMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void DateBox::InsertDate( const Date& rDate, USHORT nPos )
+{
+ Date aDate = rDate;
+ if ( aDate > GetMax() )
+ aDate = GetMax();
+ else if ( aDate < GetMin() )
+ aDate = GetMin();
+
+ ComboBox::InsertEntry( ImplGetDateAsText( aDate, GetFieldSettings() ), nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void DateBox::RemoveDate( const Date& rDate )
+{
+ ComboBox::RemoveEntry( ImplGetDateAsText( rDate, GetFieldSettings() ) );
+}
+
+// -----------------------------------------------------------------------
+
+Date DateBox::GetDate( USHORT nPos ) const
+{
+ Date aDate( 0, 0, 0 );
+ ImplDateGetValue( ComboBox::GetEntry( nPos ), aDate, GetExtDateFormat(TRUE), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetSettings() );
+ return aDate;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT DateBox::GetDatePos( const Date& rDate ) const
+{
+ XubString aStr;
+ if ( IsLongFormat() )
+ aStr = ImplGetLocaleDataWrapper().getLongDate( rDate, GetCalendarWrapper(), 1, FALSE, 1, !IsShowDateCentury() );
+ else
+ aStr = ImplGetLocaleDataWrapper().getDate( rDate );
+ return ComboBox::GetEntryPos( aStr );
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplTimeProcessKeyInput( Edit*, const KeyEvent& rKEvt,
+ BOOL bStrictFormat, BOOL bDuration,
+ TimeFieldFormat eFormat,
+ const LocaleDataWrapper& rLocaleDataWrapper )
+{
+ xub_Unicode cChar = rKEvt.GetCharCode();
+
+ if ( !bStrictFormat )
+ return FALSE;
+ else
+ {
+ USHORT nGroup = rKEvt.GetKeyCode().GetGroup();
+ if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
+ (nGroup == KEYGROUP_MISC) ||
+ ((cChar >= '0') && (cChar <= '9')) ||
+ (cChar == rLocaleDataWrapper.getTimeSep()) ||
+ ( ( rLocaleDataWrapper.getTimeAM().Search( cChar ) != STRING_NOTFOUND ) ) ||
+ ( ( rLocaleDataWrapper.getTimePM().Search( cChar ) != STRING_NOTFOUND ) ) ||
+ // Accept AM/PM:
+ (cChar == 'a') || (cChar == 'A') || (cChar == 'm') || (cChar == 'M') || (cChar == 'p') || (cChar == 'P') ||
+ ((eFormat == TIMEF_100TH_SEC) && (cChar == rLocaleDataWrapper.getTime100SecSep())) ||
+ ((eFormat == TIMEF_SEC_CS) && (cChar == rLocaleDataWrapper.getTime100SecSep())) ||
+ (bDuration && (cChar == '-')) )
+ return FALSE;
+ else
+ return TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplIsOnlyDigits( const String& _rStr )
+{
+ const sal_Unicode* _pChr = _rStr.GetBuffer();
+ for ( xub_StrLen i = 0; i < _rStr.Len(); ++i, ++_pChr )
+ {
+ if ( *_pChr < '0' || *_pChr > '9' )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplIsValidTimePortion( BOOL _bSkipInvalidCharacters, const String& _rStr )
+{
+ if ( !_bSkipInvalidCharacters )
+ {
+ if ( ( _rStr.Len() > 2 ) || ( _rStr.Len() < 1 ) || !ImplIsOnlyDigits( _rStr ) )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplCutTimePortion( String& _rStr, xub_StrLen _nSepPos, BOOL _bSkipInvalidCharacters, short* _pPortion )
+{
+ String sPortion = _rStr.Copy( 0, _nSepPos );
+ _rStr.Erase( 0, _nSepPos + 1 );
+
+ if ( !ImplIsValidTimePortion( _bSkipInvalidCharacters, sPortion ) )
+ return FALSE;
+ *_pPortion = (short)sPortion.ToInt32();
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplTimeGetValue( const XubString& rStr, Time& rTime,
+ TimeFieldFormat eFormat, BOOL bDuration,
+ const LocaleDataWrapper& rLocaleDataWrapper, BOOL _bSkipInvalidCharacters = TRUE )
+{
+ XubString aStr = rStr;
+ short nHour = 0;
+ short nMinute = 0;
+ short nSecond = 0;
+ short n100Sec = 0;
+ Time aTime( 0, 0, 0 );
+
+ if ( !rStr.Len() )
+ return FALSE;
+
+ // Nach Separatoren suchen
+ if ( rLocaleDataWrapper.getTimeSep().Len() )
+ {
+ XubString aSepStr( RTL_CONSTASCII_USTRINGPARAM( ",.;:/" ) );
+ if ( !bDuration )
+ aSepStr.Append( '-' );
+
+ // Die obigen Zeichen durch das Separatorzeichen ersetzen
+ for ( xub_StrLen i = 0; i < aSepStr.Len(); i++ )
+ {
+ if ( aSepStr.GetChar( i ) == rLocaleDataWrapper.getTimeSep() )
+ continue;
+ for ( xub_StrLen j = 0; j < aStr.Len(); j++ )
+ {
+ if ( aStr.GetChar( j ) == aSepStr.GetChar( i ) )
+ aStr.SetChar( j, rLocaleDataWrapper.getTimeSep().GetChar(0) );
+ }
+ }
+ }
+
+ BOOL bNegative = FALSE;
+ xub_StrLen nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
+ if ( aStr.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ if ( eFormat != TIMEF_SEC_CS )
+ {
+ if ( nSepPos == STRING_NOTFOUND )
+ nSepPos = aStr.Len();
+ if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nHour ) )
+ return FALSE;
+
+ nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
+ if ( aStr.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ if ( nSepPos != STRING_NOTFOUND )
+ {
+ if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nMinute ) )
+ return FALSE;
+
+ nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
+ if ( aStr.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ if ( nSepPos != STRING_NOTFOUND )
+ {
+ if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nSecond ) )
+ return FALSE;
+ if ( aStr.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ n100Sec = (short)aStr.ToInt32();
+ }
+ else
+ nSecond = (short)aStr.ToInt32();
+ }
+ else
+ nMinute = (short)aStr.ToInt32();
+ }
+ else if ( nSepPos == STRING_NOTFOUND )
+ {
+ nSecond = (short)aStr.ToInt32();
+ nMinute += nSecond / 60;
+ nSecond %= 60;
+ nHour += nMinute / 60;
+ nMinute %= 60;
+ }
+ else
+ {
+ nSecond = (short)aStr.Copy( 0, nSepPos ).ToInt32();
+ aStr.Erase( 0, nSepPos+1 );
+
+ nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
+ if ( aStr.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ if ( nSepPos != STRING_NOTFOUND )
+ {
+ nMinute = nSecond;
+ nSecond = (short)aStr.Copy( 0, nSepPos ).ToInt32();
+ aStr.Erase( 0, nSepPos+1 );
+
+ nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
+ if ( aStr.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ if ( nSepPos != STRING_NOTFOUND )
+ {
+ nHour = nMinute;
+ nMinute = nSecond;
+ nSecond = (short)aStr.Copy( 0, nSepPos ).ToInt32();
+ aStr.Erase( 0, nSepPos+1 );
+ }
+ else
+ {
+ nHour += nMinute / 60;
+ nMinute %= 60;
+ }
+ }
+ else
+ {
+ nMinute += nSecond / 60;
+ nSecond %= 60;
+ nHour += nMinute / 60;
+ nMinute %= 60;
+ }
+ n100Sec = (short)aStr.ToInt32();
+
+ if ( n100Sec )
+ {
+ xub_StrLen nLen = 1; // mindestens eine Ziffer, weil sonst n100Sec==0
+
+ while ( aStr.GetChar(nLen) >= '0' && aStr.GetChar(nLen) <= '9' )
+ nLen++;
+
+ if ( nLen > 2 )
+ {
+ while( nLen > 3 )
+ {
+ n100Sec = n100Sec / 10;
+ nLen--;
+ }
+ // Rundung bei negativen Zahlen???
+ n100Sec = (n100Sec + 5) / 10;
+ }
+ else
+ {
+ while( nLen < 2 )
+ {
+ n100Sec = n100Sec * 10;
+ nLen++;
+ }
+ }
+ }
+ }
+
+ if ( (nMinute > 59) || (nSecond > 59) || (n100Sec > 100) )
+ return FALSE;
+
+ if ( eFormat == TIMEF_NONE )
+ nSecond = n100Sec = 0;
+ else if ( eFormat == TIMEF_SEC )
+ n100Sec = 0;
+
+ if ( !bDuration )
+ {
+ if ( bNegative || (nHour < 0) || (nMinute < 0) ||
+ (nSecond < 0) || (n100Sec < 0) )
+ return FALSE;
+
+ aStr.ToUpperAscii();
+ XubString aAM( rLocaleDataWrapper.getTimeAM() );
+ XubString aPM( rLocaleDataWrapper.getTimePM() );
+ aAM.ToUpperAscii();
+ aPM.ToUpperAscii();
+ XubString aAM2( RTL_CONSTASCII_USTRINGPARAM( "AM" ) ); // aAM is localized
+ XubString aPM2( RTL_CONSTASCII_USTRINGPARAM( "PM" ) ); // aPM is localized
+
+ if ( (nHour < 12) && ( ( aStr.Search( aPM ) != STRING_NOTFOUND ) || ( aStr.Search( aPM2 ) != STRING_NOTFOUND ) ) )
+ nHour += 12;
+
+ if ( (nHour == 12) && ( ( aStr.Search( aAM ) != STRING_NOTFOUND ) || ( aStr.Search( aAM2 ) != STRING_NOTFOUND ) ) )
+ nHour = 0;
+
+ aTime = Time( (USHORT)nHour, (USHORT)nMinute, (USHORT)nSecond,
+ (USHORT)n100Sec );
+ }
+ else
+ {
+ if ( bNegative || (nHour < 0) || (nMinute < 0) ||
+ (nSecond < 0) || (n100Sec < 0) )
+ {
+ bNegative = TRUE;
+ nHour = nHour < 0 ? -nHour : nHour;
+ nMinute = nMinute < 0 ? -nMinute : nMinute;
+ nSecond = nSecond < 0 ? -nSecond : nSecond;
+ n100Sec = n100Sec < 0 ? -n100Sec : n100Sec;
+ }
+
+ aTime = Time( (USHORT)nHour, (USHORT)nMinute, (USHORT)nSecond,
+ (USHORT)n100Sec );
+ if ( bNegative )
+ aTime = -aTime;
+ }
+
+ rTime = aTime;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL TimeFormatter::ImplTimeReformat( const XubString& rStr, XubString& rOutStr )
+{
+ Time aTime( 0, 0, 0 );
+ if ( !ImplTimeGetValue( rStr, aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) )
+ return TRUE;
+
+ Time aTempTime = aTime;
+ if ( aTempTime > GetMax() )
+ aTempTime = GetMax() ;
+ else if ( aTempTime < GetMin() )
+ aTempTime = GetMin();
+
+ if ( GetErrorHdl().IsSet() && (aTime != aTempTime) )
+ {
+ maCorrectedTime = aTempTime;
+ if ( !GetErrorHdl().Call( this ) )
+ {
+ maCorrectedTime = Time();
+ return FALSE;
+ }
+ else
+ maCorrectedTime = Time();
+ }
+
+ BOOL bSecond = FALSE;
+ BOOL b100Sec = FALSE;
+ if ( meFormat != TIMEF_NONE )
+ bSecond = TRUE;
+ if ( meFormat == TIMEF_100TH_SEC )
+ b100Sec = TRUE;
+
+ if ( meFormat == TIMEF_SEC_CS )
+ {
+ ULONG n = aTempTime.GetHour() * 3600L;
+ n += aTempTime.GetMin() * 60L;
+ n += aTempTime.GetSec();
+ rOutStr = String::CreateFromInt32( n );
+ rOutStr += ImplGetLocaleDataWrapper().getTime100SecSep();
+ if ( aTempTime.Get100Sec() < 10 )
+ rOutStr += '0';
+ rOutStr += String::CreateFromInt32( aTempTime.Get100Sec() );
+ }
+ else if ( mbDuration )
+ rOutStr = ImplGetLocaleDataWrapper().getDuration( aTempTime, bSecond, b100Sec );
+ else
+ {
+ rOutStr = ImplGetLocaleDataWrapper().getTime( aTempTime, bSecond, b100Sec );
+ if ( GetTimeFormat() == HOUR_12 )
+ {
+ if ( aTempTime.GetHour() > 12 )
+ {
+ Time aT( aTempTime );
+ aT.SetHour( aT.GetHour() % 12 );
+ rOutStr = ImplGetLocaleDataWrapper().getTime( aT, bSecond, b100Sec );
+ }
+ // Don't use LocaleDataWrapper, we want AM/PM
+ if ( aTempTime.GetHour() < 12 )
+ rOutStr += String( RTL_CONSTASCII_USTRINGPARAM( "AM" ) ); // ImplGetLocaleDataWrapper().getTimeAM();
+ else
+ rOutStr += String( RTL_CONSTASCII_USTRINGPARAM( "PM" ) ); // ImplGetLocaleDataWrapper().getTimePM();
+ }
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+BOOL TimeFormatter::ImplAllowMalformedInput() const
+{
+ return !IsEnforceValidValue();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::ImplTimeSpinArea( BOOL bUp )
+{
+ if ( GetField() )
+ {
+ xub_StrLen nTimeArea = 0;
+ Time aTime( GetTime() );
+ XubString aText( GetText() );
+ Selection aSelection( GetField()->GetSelection() );
+
+ // Area suchen
+ if ( GetFormat() != TIMEF_SEC_CS )
+ {
+ for ( xub_StrLen i = 1, nPos = 0; i <= 4; i++ )
+ {
+ xub_StrLen nPos1 = aText.Search( ImplGetLocaleDataWrapper().getTimeSep(), nPos );
+ xub_StrLen nPos2 = aText.Search( ImplGetLocaleDataWrapper().getTime100SecSep(), nPos );
+ nPos = nPos1 < nPos2 ? nPos1 : nPos2;
+ if ( nPos >= (xub_StrLen)aSelection.Max() )
+ {
+ nTimeArea = i;
+ break;
+ }
+ else
+ nPos++;
+ }
+ }
+ else
+ {
+ xub_StrLen nPos = aText.Search( ImplGetLocaleDataWrapper().getTime100SecSep() );
+ if ( nPos == STRING_NOTFOUND || nPos >= (xub_StrLen)aSelection.Max() )
+ nTimeArea = 3;
+ else
+ nTimeArea = 4;
+ }
+
+ if ( nTimeArea )
+ {
+ Time aAddTime( 0, 0, 0 );
+ if ( nTimeArea == 1 )
+ aAddTime = Time( 1, 0 );
+ else if ( nTimeArea == 2 )
+ aAddTime = Time( 0, 1 );
+ else if ( nTimeArea == 3 )
+ aAddTime = Time( 0, 0, 1 );
+ else if ( nTimeArea == 4 )
+ aAddTime = Time( 0, 0, 0, 1 );
+
+ if ( !bUp )
+ aAddTime = -aAddTime;
+
+ aTime += aAddTime;
+ if ( !IsDuration() )
+ {
+ Time aAbsMaxTime( 23, 59, 59, 99 );
+ if ( aTime > aAbsMaxTime )
+ aTime = aAbsMaxTime;
+ Time aAbsMinTime( 0, 0 );
+ if ( aTime < aAbsMinTime )
+ aTime = aAbsMinTime;
+ }
+ ImplNewFieldValue( aTime );
+ }
+
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::ImplInit()
+{
+ meFormat = TIMEF_NONE;
+ mbDuration = FALSE;
+ mnTimeFormat = HOUR_24; // Should become a ExtTimeFieldFormat in next implementation, merge with mbDuration and meFormat
+}
+
+// -----------------------------------------------------------------------
+
+TimeFormatter::TimeFormatter() :
+ maLastTime( 0, 0 ),
+ maMin( 0, 0 ),
+ maMax( 23, 59, 59, 99 ),
+ mbEnforceValidValue( TRUE ),
+ maFieldTime( 0, 0 )
+{
+ ImplInit();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::ImplLoadRes( const ResId& rResId )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ {
+ ULONG nMask = pMgr->ReadLong();
+
+ if ( TIMEFORMATTER_MIN & nMask )
+ {
+ SetMin( Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) ) );
+ pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
+ }
+
+ if ( TIMEFORMATTER_MAX & nMask )
+ {
+ SetMax( Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) ) );
+ pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
+ }
+
+ if ( TIMEFORMATTER_TIMEFIELDFORMAT & nMask )
+ meFormat = (TimeFieldFormat)pMgr->ReadLong();
+
+ if ( TIMEFORMATTER_DURATION & nMask )
+ mbDuration = (BOOL)pMgr->ReadShort();
+
+ if ( TIMEFORMATTER_STRICTFORMAT & nMask )
+ SetStrictFormat( (BOOL)pMgr->ReadShort() );
+
+ if ( TIMEFORMATTER_VALUE & nMask )
+ {
+ maFieldTime = Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
+ if ( maFieldTime > GetMax() )
+ maFieldTime = GetMax();
+ if ( maFieldTime < GetMin() )
+ maFieldTime = GetMin();
+ maLastTime = maFieldTime;
+
+ pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TimeFormatter::~TimeFormatter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::ReformatAll()
+{
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::SetMin( const Time& rNewMin )
+{
+ maMin = rNewMin;
+ if ( !IsEmptyFieldValue() )
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::SetMax( const Time& rNewMax )
+{
+ maMax = rNewMax;
+ if ( !IsEmptyFieldValue() )
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::SetTimeFormat( TimeFormatter::TimeFormat eNewFormat )
+{
+ mnTimeFormat = sal::static_int_cast<USHORT>(eNewFormat);
+}
+
+// -----------------------------------------------------------------------
+
+TimeFormatter::TimeFormat TimeFormatter::GetTimeFormat() const
+{
+ return (TimeFormat)mnTimeFormat;
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::SetFormat( TimeFieldFormat eNewFormat )
+{
+ meFormat = eNewFormat;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::SetDuration( BOOL bNewDuration )
+{
+ mbDuration = bNewDuration;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::SetTime( const Time& rNewTime )
+{
+ SetUserTime( rNewTime );
+ maFieldTime = maLastTime;
+ SetEmptyFieldValueData( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::ImplNewFieldValue( const Time& rTime )
+{
+ if ( GetField() )
+ {
+ Selection aSelection = GetField()->GetSelection();
+ aSelection.Justify();
+ XubString aText = GetField()->GetText();
+ // Wenn bis ans Ende selektiert war, soll das auch so bleiben...
+ if ( (xub_StrLen)aSelection.Max() == aText.Len() )
+ {
+ if ( !aSelection.Len() )
+ aSelection.Min() = SELECTION_MAX;
+ aSelection.Max() = SELECTION_MAX;
+ }
+
+ Time aOldLastTime = maLastTime;
+ ImplSetUserTime( rTime, &aSelection );
+ maLastTime = aOldLastTime;
+
+ // Modify am Edit wird nur bei KeyInput gesetzt...
+ if ( GetField()->GetText() != aText )
+ {
+ GetField()->SetModifyFlag();
+ GetField()->Modify();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::ImplSetUserTime( const Time& rNewTime, Selection* pNewSelection )
+{
+ Time aNewTime = rNewTime;
+ if ( aNewTime > GetMax() )
+ aNewTime = GetMax();
+ else if ( aNewTime < GetMin() )
+ aNewTime = GetMin();
+ maLastTime = aNewTime;
+
+ if ( GetField() )
+ {
+ XubString aStr;
+ BOOL bSec = FALSE;
+ BOOL b100Sec = FALSE;
+ if ( meFormat != TIMEF_NONE )
+ bSec = TRUE;
+ if ( meFormat == TIMEF_100TH_SEC || meFormat == TIMEF_SEC_CS )
+ b100Sec = TRUE;
+ if ( meFormat == TIMEF_SEC_CS )
+ {
+ ULONG n = aNewTime.GetHour() * 3600L;
+ n += aNewTime.GetMin() * 60L;
+ n += aNewTime.GetSec();
+ aStr = String::CreateFromInt32( n );
+ aStr += ImplGetLocaleDataWrapper().getTime100SecSep();
+ if ( aNewTime.Get100Sec() < 10 )
+ aStr += '0';
+ aStr += String::CreateFromInt32( aNewTime.Get100Sec() );
+ }
+ else if ( mbDuration )
+ {
+ aStr = ImplGetLocaleDataWrapper().getDuration( aNewTime, bSec, b100Sec );
+ }
+ else
+ {
+ aStr = ImplGetLocaleDataWrapper().getTime( aNewTime, bSec, b100Sec );
+ if ( GetTimeFormat() == HOUR_12 )
+ {
+ if ( aNewTime.GetHour() > 12 )
+ {
+ Time aT( aNewTime );
+ aT.SetHour( aT.GetHour() % 12 );
+ aStr = ImplGetLocaleDataWrapper().getTime( aT, bSec, b100Sec );
+ }
+ // Don't use LocaleDataWrapper, we want AM/PM
+ if ( aNewTime.GetHour() < 12 )
+ aStr += String( RTL_CONSTASCII_USTRINGPARAM( "AM" ) ); // ImplGetLocaleDataWrapper().getTimeAM();
+ else
+ aStr += String( RTL_CONSTASCII_USTRINGPARAM( "PM" ) ); // ImplGetLocaleDataWrapper().getTimePM();
+ }
+ }
+
+ ImplSetText( aStr, pNewSelection );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::SetUserTime( const Time& rNewTime )
+{
+ ImplSetUserTime( rNewTime );
+}
+
+// -----------------------------------------------------------------------
+
+Time TimeFormatter::GetTime() const
+{
+ Time aTime( 0, 0, 0 );
+
+ if ( GetField() )
+ {
+ BOOL bAllowMailformed = ImplAllowMalformedInput();
+ if ( ImplTimeGetValue( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) )
+ {
+ if ( aTime > GetMax() )
+ aTime = GetMax();
+ else if ( aTime < GetMin() )
+ aTime = GetMin();
+ }
+ else
+ {
+ if ( bAllowMailformed )
+ aTime = GetInvalidTime();
+ else
+ aTime = maLastTime;
+ }
+ }
+
+ return aTime;
+}
+
+// -----------------------------------------------------------------------
+
+Time TimeFormatter::GetRealTime() const
+{
+ Time aTime( 0, 0, 0 );
+
+ if ( GetField() )
+ {
+ BOOL bAllowMailformed = ImplAllowMalformedInput();
+ if ( !ImplTimeGetValue( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) )
+ if ( bAllowMailformed )
+ aTime = GetInvalidTime();
+ }
+
+ return aTime;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL TimeFormatter::IsTimeModified() const
+{
+ if ( ImplGetEmptyFieldValue() )
+ return !IsEmptyTime();
+ else if ( GetTime() != maFieldTime )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void TimeFormatter::Reformat()
+{
+ if ( !GetField() )
+ return;
+
+ if ( !GetField()->GetText().Len() && ImplGetEmptyFieldValue() )
+ return;
+
+ XubString aStr;
+ BOOL bOK = ImplTimeReformat( GetField()->GetText(), aStr );
+ if ( !bOK )
+ return;
+
+ if ( aStr.Len() )
+ {
+ ImplSetText( aStr );
+ ImplTimeGetValue( aStr, maLastTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() );
+ }
+ else
+ SetTime( maLastTime );
+}
+
+// -----------------------------------------------------------------------
+
+TimeField::TimeField( Window* pParent, WinBits nWinStyle ) :
+ SpinField( pParent, nWinStyle ),
+ maFirst( GetMin() ),
+ maLast( GetMax() )
+{
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, FALSE, FALSE ) );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+TimeField::TimeField( Window* pParent, const ResId& rResId ) :
+ SpinField( WINDOW_TIMEFIELD ),
+ maFirst( GetMin() ),
+ maLast( GetMax() )
+{
+ rResId.SetRT( RSC_TIMEFIELD );
+ WinBits nStyle = ImplInitRes( rResId );
+ SpinField::ImplInit( pParent, nStyle );
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, FALSE, FALSE ) );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::ImplLoadRes( const ResId& rResId )
+{
+ SpinField::ImplLoadRes( rResId );
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ {
+ TimeFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+
+ ULONG nMask = ReadLongRes();
+
+ if ( TIMEFIELD_FIRST & nMask )
+ {
+ maFirst = Time( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+ if ( TIMEFIELD_LAST & nMask )
+ {
+ maLast = Time( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+ }
+
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+TimeField::~TimeField()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long TimeField::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return SpinField::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long TimeField::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ {
+ if ( !ImplAllowMalformedInput() )
+ Reformat();
+ else
+ {
+ Time aTime( 0, 0, 0 );
+ if ( ImplTimeGetValue( GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), FALSE ) )
+ // even with strict text analysis, our text is a valid time -> do a complete
+ // reformat
+ Reformat();
+ }
+ }
+ }
+
+ return SpinField::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SpinField::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ SpinField::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::Up()
+{
+ ImplTimeSpinArea( TRUE );
+ SpinField::Up();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::Down()
+{
+ ImplTimeSpinArea( FALSE );
+ SpinField::Down();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::First()
+{
+ ImplNewFieldValue( maFirst );
+ SpinField::First();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::Last()
+{
+ ImplNewFieldValue( maLast );
+ SpinField::Last();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeField::SetExtFormat( ExtTimeFieldFormat eFormat )
+{
+ switch ( eFormat )
+ {
+ case EXTTIMEF_24H_SHORT:
+ {
+ SetTimeFormat( HOUR_24 );
+ SetDuration( FALSE );
+ SetFormat( TIMEF_NONE );
+ }
+ break;
+ case EXTTIMEF_24H_LONG:
+ {
+ SetTimeFormat( HOUR_24 );
+ SetDuration( FALSE );
+ SetFormat( TIMEF_SEC );
+ }
+ break;
+ case EXTTIMEF_12H_SHORT:
+ {
+ SetTimeFormat( HOUR_12 );
+ SetDuration( FALSE );
+ SetFormat( TIMEF_NONE );
+ }
+ break;
+ case EXTTIMEF_12H_LONG:
+ {
+ SetTimeFormat( HOUR_12 );
+ SetDuration( FALSE );
+ SetFormat( TIMEF_SEC );
+ }
+ break;
+ case EXTTIMEF_DURATION_SHORT:
+ {
+ SetDuration( TRUE );
+ SetFormat( TIMEF_NONE );
+ }
+ break;
+ case EXTTIMEF_DURATION_LONG:
+ {
+ SetDuration( TRUE );
+ SetFormat( TIMEF_SEC );
+ }
+ break;
+ default: DBG_ERROR( "ExtTimeFieldFormat unknown!" );
+ }
+
+ if ( GetField() && GetField()->GetText().Len() )
+ SetUserTime( GetTime() );
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+TimeBox::TimeBox( Window* pParent, WinBits nWinStyle ) :
+ ComboBox( pParent, nWinStyle )
+{
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, FALSE, FALSE ) );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+TimeBox::TimeBox( Window* pParent, const ResId& rResId ) :
+ ComboBox( WINDOW_TIMEBOX )
+{
+ rResId.SetRT( RSC_TIMEBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ComboBox::ImplInit( pParent, nStyle );
+ SetField( this );
+ SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, FALSE, FALSE ) );
+ ComboBox::ImplLoadRes( rResId );
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ TimeFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+TimeBox::~TimeBox()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long TimeBox::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
+ {
+ if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
+ return 1;
+ }
+
+ return ComboBox::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long TimeBox::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ MarkToBeReformatted( FALSE );
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
+ Reformat();
+ }
+
+ return ComboBox::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TimeBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ ComboBox::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
+ {
+ if ( IsDefaultLocale() )
+ ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
+ ReformatAll();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TimeBox::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ ComboBox::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void TimeBox::ReformatAll()
+{
+ XubString aStr;
+ SetUpdateMode( FALSE );
+ USHORT nEntryCount = GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ ImplTimeReformat( GetEntry( i ), aStr );
+ RemoveEntry( i );
+ InsertEntry( aStr, i );
+ }
+ TimeFormatter::Reformat();
+ SetUpdateMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void TimeBox::InsertTime( const Time& rTime, USHORT nPos )
+{
+ Time aTime = rTime;
+ if ( aTime > GetMax() )
+ aTime = GetMax();
+ else if ( aTime < GetMin() )
+ aTime = GetMin();
+
+ BOOL bSec = FALSE;
+ BOOL b100Sec = FALSE;
+ if ( GetFormat() == TIMEF_SEC )
+ bSec = TRUE;
+ if ( GetFormat() == TIMEF_100TH_SEC || GetFormat() == TIMEF_SEC_CS )
+ bSec = b100Sec = TRUE;
+ ComboBox::InsertEntry( ImplGetLocaleDataWrapper().getTime( aTime, bSec, b100Sec ), nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void TimeBox::RemoveTime( const Time& rTime )
+{
+ BOOL bSec = FALSE;
+ BOOL b100Sec = FALSE;
+ if ( GetFormat() == TIMEF_SEC )
+ bSec = TRUE;
+ if ( GetFormat() == TIMEF_100TH_SEC || TIMEF_SEC_CS )
+ bSec = b100Sec = TRUE;
+ ComboBox::RemoveEntry( ImplGetLocaleDataWrapper().getTime( rTime, bSec, b100Sec ) );
+}
+
+// -----------------------------------------------------------------------
+
+Time TimeBox::GetTime( USHORT nPos ) const
+{
+ Time aTime( 0, 0, 0 );
+ ImplTimeGetValue( ComboBox::GetEntry( nPos ), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() );
+ return aTime;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TimeBox::GetTimePos( const Time& rTime ) const
+{
+ BOOL bSec = FALSE;
+ BOOL b100Sec = FALSE;
+ if ( GetFormat() == TIMEF_SEC )
+ bSec = TRUE;
+ if ( GetFormat() == TIMEF_100TH_SEC || TIMEF_SEC_CS )
+ bSec = b100Sec = TRUE;
+ return ComboBox::GetEntryPos( ImplGetLocaleDataWrapper().getTime( rTime, bSec, b100Sec ) );
+}
diff --git a/vcl/source/control/fixbrd.cxx b/vcl/source/control/fixbrd.cxx
new file mode 100644
index 000000000000..b519174f95d1
--- /dev/null
+++ b/vcl/source/control/fixbrd.cxx
@@ -0,0 +1,236 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/event.hxx>
+#include <vcl/fixbrd.hxx>
+
+
+
+// =======================================================================
+
+void FixedBorder::ImplInit( Window* pParent, WinBits nStyle )
+{
+ mnType = FIXEDBORDER_TYPE_DOUBLEOUT;
+ mbTransparent = TRUE;
+
+ nStyle = ImplInitStyle( nStyle );
+ Control::ImplInit( pParent, nStyle, NULL );
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+WinBits FixedBorder::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::ImplInitSettings()
+{
+ Window* pParent = GetParent();
+ if ( (pParent->IsChildTransparentModeEnabled() ||
+ !(pParent->GetStyle() & WB_CLIPCHILDREN) ) &&
+ !IsControlBackground() && mbTransparent )
+ {
+ SetMouseTransparent( TRUE );
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ SetMouseTransparent( FALSE );
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FixedBorder::FixedBorder( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_FIXEDBORDER )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+FixedBorder::FixedBorder( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_FIXEDBORDER )
+{
+ rResId.SetRT( RSC_CONTROL );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+FixedBorder::~FixedBorder()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Rectangle aRect( rPos, rSize );
+ USHORT nBorderStyle = mnType;
+
+ if ( (nDrawFlags & WINDOW_DRAW_MONO) ||
+ (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ nBorderStyle |= FRAME_DRAW_MONO;
+
+ /*
+ // seems only to be used in tools->options around a tabpage (ie, no tabcontrol!)
+ // as tabpages that are not embedded in a tabcontrol should not be drawn natively
+ // the fixedborder must also not be drawn (reason was, that it looks too ugly, dialogs must be redesigned)
+ Window *pWin = pDev->GetOutDevType() == OUTDEV_WINDOW ? (Window*) pDev : NULL;
+ if( !(nBorderStyle & FRAME_DRAW_MONO) && pWin && pWin->IsNativeControlSupported( CTRL_FIXEDBORDER, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aControlValue;
+ Point aPt;
+ Region aCtrlRegion( Rectangle( aPt, GetOutputSizePixel() ) );
+ ControlState nState = IsEnabled() ? CTRL_STATE_ENABLED : 0;
+ pWin->DrawNativeControl( CTRL_FIXEDBORDER, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() );
+ }
+ else
+ */
+ {
+ DecorationView aDecoView( pDev );
+ aDecoView.DrawFrame( aRect, nBorderStyle );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::Paint( const Rectangle& )
+{
+ ImplDraw( this, 0, Point(), GetOutputSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+
+ pDev->Push();
+ pDev->SetMapMode();
+ ImplDraw( pDev, nFlags, aPos, aSize );
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::Resize()
+{
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( (nType == STATE_CHANGE_DATA) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::SetTransparent( BOOL bTransparent )
+{
+ if ( mbTransparent != bTransparent )
+ {
+ mbTransparent = bTransparent;
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBorder::SetBorderType( USHORT nType )
+{
+ if ( mnType != nType )
+ {
+ mnType = nType;
+ Invalidate();
+ }
+}
diff --git a/vcl/source/control/fixed.cxx b/vcl/source/control/fixed.cxx
new file mode 100644
index 000000000000..37406293d7cf
--- /dev/null
+++ b/vcl/source/control/fixed.cxx
@@ -0,0 +1,1174 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/decoview.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/controldata.hxx>
+#include <vcl/window.h>
+
+#include <tools/rc.h>
+
+// =======================================================================
+
+#define FIXEDLINE_TEXT_BORDER 4
+
+#define FIXEDTEXT_VIEW_STYLE (WB_3DLOOK | \
+ WB_LEFT | WB_CENTER | WB_RIGHT | \
+ WB_TOP | WB_VCENTER | WB_BOTTOM | \
+ WB_WORDBREAK | WB_NOLABEL | \
+ WB_INFO | WB_PATHELLIPSIS)
+#define FIXEDLINE_VIEW_STYLE (WB_3DLOOK | WB_NOLABEL)
+#define FIXEDBITMAP_VIEW_STYLE (WB_3DLOOK | \
+ WB_LEFT | WB_CENTER | WB_RIGHT | \
+ WB_TOP | WB_VCENTER | WB_BOTTOM | \
+ WB_SCALE)
+#define FIXEDIMAGE_VIEW_STYLE (WB_3DLOOK | \
+ WB_LEFT | WB_CENTER | WB_RIGHT | \
+ WB_TOP | WB_VCENTER | WB_BOTTOM | \
+ WB_SCALE)
+
+// =======================================================================
+
+static Point ImplCalcPos( WinBits nStyle, const Point& rPos,
+ const Size& rObjSize, const Size& rWinSize )
+{
+ long nX;
+ long nY;
+
+ if ( nStyle & WB_LEFT )
+ nX = 0;
+ else if ( nStyle & WB_RIGHT )
+ nX = rWinSize.Width()-rObjSize.Width();
+ else
+ nX = (rWinSize.Width()-rObjSize.Width())/2;
+
+ if ( nStyle & WB_TOP )
+ nY = 0;
+ else if ( nStyle & WB_BOTTOM )
+ nY = rWinSize.Height()-rObjSize.Height();
+ else
+ nY = (rWinSize.Height()-rObjSize.Height())/2;
+
+ if ( nStyle & WB_TOPLEFTVISIBLE )
+ {
+ if ( nX < 0 )
+ nX = 0;
+ if ( nY < 0 )
+ nY = 0;
+ }
+
+ Point aPos( nX+rPos.X(), nY+rPos.Y() );
+ return aPos;
+}
+
+// =======================================================================
+
+void FixedText::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( nStyle );
+ Control::ImplInit( pParent, nStyle, NULL );
+ ImplInitSettings( TRUE, TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits FixedText::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------
+
+const Font& FixedText::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return ( GetStyle() & WB_INFO ) ? _rStyle.GetInfoFont() : _rStyle.GetLabelFont();
+}
+
+// -----------------------------------------------------------------
+const Color& FixedText::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return ( GetStyle() & WB_INFO ) ? _rStyle.GetInfoTextColor() : _rStyle.GetLabelTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Control::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ Window* pParent = GetParent();
+ if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FixedText::FixedText( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_FIXEDTEXT )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+FixedText::FixedText( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_FIXEDTEXT )
+{
+ rResId.SetRT( RSC_TEXT );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+FixedText::FixedText( Window* pParent, const ResId& rResId, bool bDisableAccessibleLabelForRelation ) :
+ Control( WINDOW_FIXEDTEXT )
+{
+ rResId.SetRT( RSC_TEXT );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+ if ( bDisableAccessibleLabelForRelation )
+ ImplGetWindowImpl()->mbDisableAccessibleLabelForRelation = TRUE;
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT FixedText::ImplGetTextStyle( WinBits nWinStyle )
+{
+ USHORT nTextStyle = TEXT_DRAW_MNEMONIC | TEXT_DRAW_ENDELLIPSIS;
+
+ if( ! (nWinStyle & WB_NOMULTILINE) )
+ nTextStyle |= TEXT_DRAW_MULTILINE;
+
+ if ( nWinStyle & WB_RIGHT )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else if ( nWinStyle & WB_CENTER )
+ nTextStyle |= TEXT_DRAW_CENTER;
+ else
+ nTextStyle |= TEXT_DRAW_LEFT;
+ if ( nWinStyle & WB_BOTTOM )
+ nTextStyle |= TEXT_DRAW_BOTTOM;
+ else if ( nWinStyle & WB_VCENTER )
+ nTextStyle |= TEXT_DRAW_VCENTER;
+ else
+ nTextStyle |= TEXT_DRAW_TOP;
+ if ( nWinStyle & WB_WORDBREAK )
+ {
+ nTextStyle |= TEXT_DRAW_WORDBREAK;
+ if ( (nWinStyle & WB_HYPHENATION ) == WB_HYPHENATION )
+ nTextStyle |= TEXT_DRAW_WORDBREAK_HYPHENATION;
+ }
+ if ( nWinStyle & WB_NOLABEL )
+ nTextStyle &= ~TEXT_DRAW_MNEMONIC;
+
+ return nTextStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize,
+ bool bFillLayout
+ ) const
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ WinBits nWinStyle = GetStyle();
+ XubString aText( GetText() );
+ USHORT nTextStyle = FixedText::ImplGetTextStyle( nWinStyle );
+ Point aPos = rPos;
+
+ if ( nWinStyle & WB_EXTRAOFFSET )
+ aPos.X() += 2;
+
+ if ( nWinStyle & WB_PATHELLIPSIS )
+ {
+ nTextStyle &= ~(TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK);
+ nTextStyle |= TEXT_DRAW_PATHELLIPSIS;
+ }
+ if ( nDrawFlags & WINDOW_DRAW_NOMNEMONIC )
+ {
+ if ( nTextStyle & TEXT_DRAW_MNEMONIC )
+ {
+ aText = GetNonMnemonicString( aText );
+ nTextStyle &= ~TEXT_DRAW_MNEMONIC;
+ }
+ }
+ if ( !(nDrawFlags & WINDOW_DRAW_NODISABLE) )
+ {
+ if ( !IsEnabled() )
+ nTextStyle |= TEXT_DRAW_DISABLE;
+ }
+ if ( (nDrawFlags & WINDOW_DRAW_MONO) ||
+ (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ nTextStyle |= TEXT_DRAW_MONO;
+
+ if( bFillLayout )
+ mpControlData->mpLayoutData->m_aDisplayText = String();
+
+ Rectangle aRect( Rectangle( aPos, rSize ) );
+ DrawControlText( *pDev, aRect, aText, nTextStyle,
+ bFillLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL,
+ bFillLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL
+ );
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::Paint( const Rectangle& )
+{
+ ImplDraw( this, 0, Point(), GetOutputSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ ImplInitSettings( TRUE, TRUE, TRUE );
+
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Font aFont = GetDrawPixelFont( pDev );
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ if ( nFlags & WINDOW_DRAW_MONO )
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ else
+ pDev->SetTextColor( GetTextColor() );
+ pDev->SetTextFillColor();
+
+ BOOL bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
+ BOOL bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
+ if ( bBorder || bBackground )
+ {
+ Rectangle aRect( aPos, aSize );
+ if ( bBorder )
+ {
+ ImplDrawFrame( pDev, aRect );
+ }
+ if ( bBackground )
+ {
+ pDev->SetFillColor( GetControlBackground() );
+ pDev->DrawRect( aRect );
+ }
+ }
+
+ ImplDraw( pDev, nFlags, aPos, aSize );
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( (nType == STATE_CHANGE_ENABLE) ||
+ (nType == STATE_CHANGE_TEXT) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ if ( (GetPrevStyle() & FIXEDTEXT_VIEW_STYLE) !=
+ (GetStyle() & FIXEDTEXT_VIEW_STYLE) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size FixedText::CalcMinimumTextSize( Control const *pControl, long nMaxWidth )
+{
+ USHORT nStyle = ImplGetTextStyle( pControl->GetStyle() );
+ if ( !( pControl->GetStyle() & WB_NOLABEL ) )
+ nStyle |= TEXT_DRAW_MNEMONIC;
+
+ Size aSize = pControl->GetTextRect( Rectangle( Point(), Size( (nMaxWidth ? nMaxWidth : 0x7fffffff), 0x7fffffff ) ),
+ pControl->GetText(), nStyle ).GetSize();
+
+ if ( pControl->GetStyle() & WB_EXTRAOFFSET )
+ aSize.Width() += 2;
+
+ // GetTextRect verkraftet keinen leeren String:
+ if ( aSize.Width() < 0 )
+ aSize.Width() = 0;
+ if ( aSize.Height() <= 0 )
+ aSize.Height() = pControl->GetTextHeight();
+
+ return aSize;
+}
+
+Size FixedText::CalcMinimumSize( long nMaxWidth ) const
+{
+ return CalcWindowSize( CalcMinimumTextSize ( this, nMaxWidth ) );
+}
+// -----------------------------------------------------------------------
+
+Size FixedText::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Control::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedText::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ ImplDraw( const_cast<FixedText*>(this), 0, Point(), GetOutputSizePixel(), true );
+}
+
+// =======================================================================
+
+void FixedLine::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( nStyle );
+ Control::ImplInit( pParent, nStyle, NULL );
+ ImplInitSettings( TRUE, TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits FixedLine::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------
+
+const Font& FixedLine::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetGroupFont();
+}
+
+// -----------------------------------------------------------------
+const Color& FixedLine::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetGroupTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedLine::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Control::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ Window* pParent = GetParent();
+ if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedLine::ImplDraw( bool bLayout )
+{
+ Size aOutSize = GetOutputSizePixel();
+ String aText = GetText();
+ WinBits nWinStyle = GetStyle();
+ MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+
+ DecorationView aDecoView( this );
+ if ( !aText.Len() || (nWinStyle & WB_VERT) )
+ {
+ if( !pVector )
+ {
+ long nX = 0;
+ long nY = 0;
+
+ if ( nWinStyle & WB_VERT )
+ {
+ nX = (aOutSize.Width()-1)/2;
+ aDecoView.DrawSeparator( Point( nX, 0 ), Point( nX, aOutSize.Height()-1 ) );
+ }
+ else
+ {
+ nY = (aOutSize.Height()-1)/2;
+ aDecoView.DrawSeparator( Point( 0, nY ), Point( aOutSize.Width()-1, nY ), false );
+ }
+ }
+ }
+ else
+ {
+ USHORT nStyle = TEXT_DRAW_MNEMONIC | TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER | TEXT_DRAW_ENDELLIPSIS;
+ Rectangle aRect( 0, 0, aOutSize.Width(), aOutSize.Height() );
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if ( !IsEnabled() )
+ nStyle |= TEXT_DRAW_DISABLE;
+ if ( GetStyle() & WB_NOLABEL )
+ nStyle &= ~TEXT_DRAW_MNEMONIC;
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO )
+ nStyle |= TEXT_DRAW_MONO;
+
+ DrawControlText( *this, aRect, aText, nStyle, pVector, pDisplayText );
+
+ if( !pVector )
+ {
+ long nTop = aRect.Top() + ((aRect.GetHeight()-1)/2);
+ aDecoView.DrawSeparator( Point( aRect.Right()+FIXEDLINE_TEXT_BORDER, nTop ), Point( aOutSize.Width()-1, nTop ), false );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FixedLine::FixedLine( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_FIXEDLINE )
+{
+ ImplInit( pParent, nStyle );
+ SetSizePixel( Size( 2, 2 ) );
+}
+
+// -----------------------------------------------------------------------
+
+FixedLine::FixedLine( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_FIXEDLINE )
+{
+ rResId.SetRT( RSC_FIXEDLINE );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedLine::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<FixedLine*>(this)->ImplDraw( true );
+}
+
+
+// -----------------------------------------------------------------------
+
+void FixedLine::Paint( const Rectangle& )
+{
+ ImplDraw();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedLine::Draw( OutputDevice*, const Point&, const Size&, ULONG )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void FixedLine::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedLine::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( (nType == STATE_CHANGE_ENABLE) ||
+ (nType == STATE_CHANGE_TEXT) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ if ( (GetPrevStyle() & FIXEDLINE_VIEW_STYLE) !=
+ (GetStyle() & FIXEDLINE_VIEW_STYLE) )
+ Invalidate();
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_STYLE) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedLine::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size FixedLine::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcWindowSize( FixedText::CalcMinimumTextSize ( this ) );
+ default:
+ return Control::GetOptimalSize( eType );
+ }
+}
+
+// =======================================================================
+
+void FixedBitmap::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( nStyle );
+ Control::ImplInit( pParent, nStyle, NULL );
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+WinBits FixedBitmap::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::ImplInitSettings()
+{
+ Window* pParent = GetParent();
+ if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if ( RSC_FIXEDBITMAP_BITMAP & nObjMask )
+ {
+ maBitmap = Bitmap( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FixedBitmap::FixedBitmap( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_FIXEDBITMAP )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+FixedBitmap::FixedBitmap( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_FIXEDBITMAP )
+{
+ rResId.SetRT( RSC_FIXEDBITMAP );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+FixedBitmap::~FixedBitmap()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::ImplDraw( OutputDevice* pDev, ULONG /* nDrawFlags */,
+ const Point& rPos, const Size& rSize )
+{
+ USHORT nStyle = 0;
+ Bitmap* pBitmap = &maBitmap;
+ Color aCol;
+ if( !!maBitmapHC )
+ {
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ pBitmap = &maBitmapHC;
+ }
+
+ if( nStyle & IMAGE_DRAW_COLORTRANSFORM )
+ {
+ // only images support IMAGE_DRAW_COLORTRANSFORM
+ Image aImage( maBitmap );
+ if ( !(!aImage) )
+ {
+ if ( GetStyle() & WB_SCALE )
+ pDev->DrawImage( rPos, rSize, aImage, nStyle );
+ else
+ {
+ Point aPos = ImplCalcPos( GetStyle(), rPos, aImage.GetSizePixel(), rSize );
+ pDev->DrawImage( aPos, aImage, nStyle );
+ }
+ }
+ }
+ else
+ {
+ // Haben wir ueberhaupt eine Bitmap
+ if ( !(!(*pBitmap)) )
+ {
+ if ( GetStyle() & WB_SCALE )
+ pDev->DrawBitmap( rPos, rSize, *pBitmap );
+ else
+ {
+ Point aPos = ImplCalcPos( GetStyle(), rPos, pBitmap->GetSizePixel(), rSize );
+ pDev->DrawBitmap( aPos, *pBitmap );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::Paint( const Rectangle& )
+{
+ ImplDraw( this, 0, Point(), GetOutputSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Rectangle aRect( aPos, aSize );
+
+ pDev->Push();
+ pDev->SetMapMode();
+
+ // Border
+ if ( !(nFlags & WINDOW_DRAW_NOBORDER) && (GetStyle() & WB_BORDER) )
+ {
+ DecorationView aDecoView( pDev );
+ aRect = aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN );
+ }
+ pDev->IntersectClipRegion( aRect );
+ ImplDraw( pDev, nFlags, aRect.TopLeft(), aRect.GetSize() );
+
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( (nType == STATE_CHANGE_DATA) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ if ( (GetPrevStyle() & FIXEDBITMAP_VIEW_STYLE) !=
+ (GetStyle() & FIXEDBITMAP_VIEW_STYLE) )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedBitmap::SetBitmap( const Bitmap& rBitmap )
+{
+ maBitmap = rBitmap;
+ StateChanged( STATE_CHANGE_DATA );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FixedBitmap::SetModeBitmap( const Bitmap& rBitmap, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ SetBitmap( rBitmap );
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ maBitmapHC = rBitmap;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+ else
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+const Bitmap& FixedBitmap::GetModeBitmap( BmpColorMode eMode) const
+{
+ if( eMode == BMP_COLOR_HIGHCONTRAST )
+ return maBitmapHC;
+ else
+ return maBitmap;
+}
+
+// =======================================================================
+
+void FixedImage::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( nStyle );
+ mbInUserDraw = FALSE;
+ Control::ImplInit( pParent, nStyle, NULL );
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+WinBits FixedImage::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::ImplInitSettings()
+{
+ Window* pParent = GetParent();
+ if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if ( RSC_FIXEDIMAGE_IMAGE & nObjMask )
+ {
+ maImage = Image( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FixedImage::FixedImage( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_FIXEDIMAGE )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+FixedImage::FixedImage( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_FIXEDIMAGE )
+{
+ rResId.SetRT( RSC_FIXEDIMAGE );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+FixedImage::~FixedImage()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize )
+{
+ USHORT nStyle = 0;
+ if ( !(nDrawFlags & WINDOW_DRAW_NODISABLE) )
+ {
+ if ( !IsEnabled() )
+ nStyle |= IMAGE_DRAW_DISABLE;
+ }
+
+ Image *pImage = &maImage;
+ Color aCol;
+ if( !!maImageHC )
+ {
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ pImage = &maImageHC;
+ }
+
+ // Haben wir ueberhaupt ein Image
+ if ( !(!(*pImage)) )
+ {
+ if ( GetStyle() & WB_SCALE )
+ pDev->DrawImage( rPos, rSize, *pImage, nStyle );
+ else
+ {
+ Point aPos = ImplCalcPos( GetStyle(), rPos, pImage->GetSizePixel(), rSize );
+ pDev->DrawImage( aPos, *pImage, nStyle );
+ }
+ }
+
+ mbInUserDraw = TRUE;
+ UserDrawEvent aUDEvt( pDev, Rectangle( rPos, rSize ), 0, nStyle );
+ UserDraw( aUDEvt );
+ mbInUserDraw = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::Paint( const Rectangle& )
+{
+ ImplDraw( this, 0, Point(), GetOutputSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+Size FixedImage::GetOptimalSize( WindowSizeType ) const
+{
+ const Image* pImage = GetSettings().GetStyleSettings().GetHighContrastMode() ? &maImageHC : &maImage;
+ return pImage->GetSizePixel();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::UserDraw( const UserDrawEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Rectangle aRect( aPos, aSize );
+
+ pDev->Push();
+ pDev->SetMapMode();
+
+ // Border
+ if ( !(nFlags & WINDOW_DRAW_NOBORDER) && (GetStyle() & WB_BORDER) )
+ {
+ ImplDrawFrame( pDev, aRect );
+ }
+ pDev->IntersectClipRegion( aRect );
+ ImplDraw( pDev, nFlags, aRect.TopLeft(), aRect.GetSize() );
+
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( (nType == STATE_CHANGE_ENABLE) ||
+ (nType == STATE_CHANGE_DATA) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ if ( (GetPrevStyle() & FIXEDIMAGE_VIEW_STYLE) !=
+ (GetStyle() & FIXEDIMAGE_VIEW_STYLE) )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FixedImage::SetImage( const Image& rImage )
+{
+ if ( rImage != maImage )
+ {
+ maImage = rImage;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FixedImage::SetModeImage( const Image& rImage, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ SetImage( rImage );
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ if( maImageHC != rImage )
+ {
+ maImageHC = rImage;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+ }
+ else
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+const Image& FixedImage::GetModeImage( BmpColorMode eMode ) const
+{
+ if( eMode == BMP_COLOR_HIGHCONTRAST )
+ return maImageHC;
+ else
+ return maImage;
+}
+
+// -----------------------------------------------------------------------
+
+Point FixedImage::CalcImagePos( const Point& rPos,
+ const Size& rObjSize, const Size& rWinSize )
+{
+ return ImplCalcPos( GetStyle(), rPos, rObjSize, rWinSize );
+}
diff --git a/vcl/source/control/group.cxx b/vcl/source/control/group.cxx
new file mode 100644
index 000000000000..ecf00568e11f
--- /dev/null
+++ b/vcl/source/control/group.cxx
@@ -0,0 +1,324 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/event.hxx>
+#include <vcl/group.hxx>
+#include <vcl/controldata.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+
+
+
+// =======================================================================
+
+#define GROUP_BORDER 12
+#define GROUP_TEXT_BORDER 2
+
+#define GROUP_VIEW_STYLE (WB_3DLOOK | WB_NOLABEL)
+
+// =======================================================================
+
+void GroupBox::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( nStyle );
+ Control::ImplInit( pParent, nStyle, NULL );
+ SetMouseTransparent( TRUE );
+ ImplInitSettings( TRUE, TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits GroupBox::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------
+
+const Font& GroupBox::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetGroupFont();
+}
+
+// -----------------------------------------------------------------
+const Color& GroupBox::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetGroupTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Control::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ Window* pParent = GetParent();
+ if ( (pParent->IsChildTransparentModeEnabled() ||
+ !(pParent->GetStyle() & WB_CLIPCHILDREN) ) &&
+ !IsControlBackground() )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+GroupBox::GroupBox( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_GROUPBOX )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+GroupBox::GroupBox( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_GROUPBOX )
+{
+ rResId.SetRT( RSC_GROUPBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize, bool bLayout )
+{
+ long nTop;
+ long nTextOff;
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ XubString aText( GetText() );
+ Rectangle aRect( rPos, rSize );
+ USHORT nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_TOP | TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_MNEMONIC;
+
+ if ( GetStyle() & WB_NOLABEL )
+ nTextStyle &= ~TEXT_DRAW_MNEMONIC;
+ if ( nDrawFlags & WINDOW_DRAW_NOMNEMONIC )
+ {
+ if ( nTextStyle & TEXT_DRAW_MNEMONIC )
+ {
+ aText = GetNonMnemonicString( aText );
+ nTextStyle &= ~TEXT_DRAW_MNEMONIC;
+ }
+ }
+ if ( !(nDrawFlags & WINDOW_DRAW_NODISABLE) )
+ {
+ if ( !IsEnabled() )
+ nTextStyle |= TEXT_DRAW_DISABLE;
+ }
+ if ( (nDrawFlags & WINDOW_DRAW_MONO) ||
+ (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ {
+ nTextStyle |= TEXT_DRAW_MONO;
+ nDrawFlags |= WINDOW_DRAW_MONO;
+ }
+
+ if ( !aText.Len() )
+ {
+ nTop = rPos.Y();
+ nTextOff = 0;
+ }
+ else
+ {
+ aRect.Left() += GROUP_BORDER;
+ aRect.Right() -= GROUP_BORDER;
+ aRect = pDev->GetTextRect( aRect, aText, nTextStyle );
+ nTop = rPos.Y();
+ nTop += aRect.GetHeight() / 2;
+ nTextOff = GROUP_TEXT_BORDER;
+ }
+
+ if( ! bLayout )
+ {
+ if ( nDrawFlags & WINDOW_DRAW_MONO )
+ pDev->SetLineColor( Color( COL_BLACK ) );
+ else
+ pDev->SetLineColor( rStyleSettings.GetShadowColor() );
+
+ if ( !aText.Len() )
+ pDev->DrawLine( Point( rPos.X(), nTop ), Point( rPos.X()+rSize.Width()-2, nTop ) );
+ else
+ {
+ pDev->DrawLine( Point( rPos.X(), nTop ), Point( aRect.Left()-nTextOff, nTop ) );
+ pDev->DrawLine( Point( aRect.Right()+nTextOff, nTop ), Point( rPos.X()+rSize.Width()-2, nTop ) );
+ }
+ pDev->DrawLine( Point( rPos.X(), nTop ), Point( rPos.X(), rPos.Y()+rSize.Height()-2 ) );
+ pDev->DrawLine( Point( rPos.X(), rPos.Y()+rSize.Height()-2 ), Point( rPos.X()+rSize.Width()-2, rPos.Y()+rSize.Height()-2 ) );
+ pDev->DrawLine( Point( rPos.X()+rSize.Width()-2, rPos.Y()+rSize.Height()-2 ), Point( rPos.X()+rSize.Width()-2, nTop ) );
+
+ bool bIsPrinter = OUTDEV_PRINTER == pDev->GetOutDevType();
+ // if we're drawing onto a printer, spare the 3D effect
+ // #i46986# / 2005-04-13 / frank.schoenheit@sun.com
+
+ if ( !bIsPrinter && !(nDrawFlags & WINDOW_DRAW_MONO) )
+ {
+ pDev->SetLineColor( rStyleSettings.GetLightColor() );
+ if ( !aText.Len() )
+ pDev->DrawLine( Point( rPos.X()+1, nTop+1 ), Point( rPos.X()+rSize.Width()-3, nTop+1 ) );
+ else
+ {
+ pDev->DrawLine( Point( rPos.X()+1, nTop+1 ), Point( aRect.Left()-nTextOff, nTop+1 ) );
+ pDev->DrawLine( Point( aRect.Right()+nTextOff, nTop+1 ), Point( rPos.X()+rSize.Width()-3, nTop+1 ) );
+ }
+ pDev->DrawLine( Point( rPos.X()+1, nTop+1 ), Point( rPos.X()+1, rPos.Y()+rSize.Height()-3 ) );
+ pDev->DrawLine( Point( rPos.X(), rPos.Y()+rSize.Height()-1 ), Point( rPos.X()+rSize.Width()-1, rPos.Y()+rSize.Height()-1 ) );
+ pDev->DrawLine( Point( rPos.X()+rSize.Width()-1, rPos.Y()+rSize.Height()-1 ), Point( rPos.X()+rSize.Width()-1, nTop ) );
+ }
+ }
+
+ MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+ DrawControlText( *pDev, aRect, aText, nTextStyle, pVector, pDisplayText );
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<GroupBox*>(this)-> ImplDraw( const_cast<GroupBox*>(this), 0, Point(), GetOutputSizePixel(), true );
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::Paint( const Rectangle& )
+{
+ ImplDraw( this, 0, Point(), GetOutputSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
+ ULONG nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Font aFont = GetDrawPixelFont( pDev );
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ if ( nFlags & WINDOW_DRAW_MONO )
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ else
+ pDev->SetTextColor( GetTextColor() );
+ pDev->SetTextFillColor();
+
+ ImplDraw( pDev, nFlags, aPos, aSize );
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::Resize()
+{
+ Control::Resize();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( (nType == STATE_CHANGE_ENABLE) ||
+ (nType == STATE_CHANGE_TEXT) ||
+ (nType == STATE_CHANGE_UPDATEMODE) )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ if ( (GetPrevStyle() & GROUP_VIEW_STYLE) !=
+ (GetStyle() & GROUP_VIEW_STYLE) )
+ Invalidate();
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void GroupBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
diff --git a/vcl/source/control/ilstbox.cxx b/vcl/source/control/ilstbox.cxx
new file mode 100644
index 000000000000..02c8d2b5fcb3
--- /dev/null
+++ b/vcl/source/control/ilstbox.cxx
@@ -0,0 +1,3233 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/event.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/help.hxx>
+#include <vcl/lstbox.h>
+#include <vcl/ilstbox.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/controldata.hxx>
+#include <vcl/unohelp.hxx>
+#ifndef _COM_SUN_STAR_UTIL_XCOLLATOR_HPP_
+#include <com/sun/star/i18n/XCollator.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HDL_
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#endif
+
+#define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
+
+using namespace ::com::sun::star;
+
+// =======================================================================
+
+void ImplInitFieldSettings( Window* pWin, BOOL bFont, BOOL bForeground, BOOL bBackground )
+{
+ const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
+
+ if ( bFont )
+ {
+ Font aFont = rStyleSettings.GetFieldFont();
+ if ( pWin->IsControlFont() )
+ aFont.Merge( pWin->GetControlFont() );
+ pWin->SetZoomedPointFont( aFont );
+ }
+
+ if ( bFont || bForeground )
+ {
+ Color aTextColor = rStyleSettings.GetFieldTextColor();
+ if ( pWin->IsControlForeground() )
+ aTextColor = pWin->GetControlForeground();
+ pWin->SetTextColor( aTextColor );
+ }
+
+ if ( bBackground )
+ {
+ if( pWin->IsControlBackground() )
+ pWin->SetBackground( pWin->GetControlBackground() );
+ else
+ pWin->SetBackground( rStyleSettings.GetFieldColor() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplInitDropDownButton( PushButton* pButton )
+{
+ if ( pButton->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
+ pButton->SetSymbol( SYMBOL_SPIN_UPDOWN );
+ else
+ pButton->SetSymbol( SYMBOL_SPIN_DOWN );
+
+ if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
+ pButton->SetBackground();
+}
+
+// =======================================================================
+
+ImplEntryList::ImplEntryList( Window* pWindow )
+{
+ mpWindow = pWindow;
+ mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
+ mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
+ mnImages = 0;
+ mbCallSelectionChangedHdl = TRUE;
+
+ mnMRUCount = 0;
+ mnMaxMRUCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplEntryList::~ImplEntryList()
+{
+ Clear();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::Clear()
+{
+ mnImages = 0;
+ for ( USHORT n = GetEntryCount(); n; )
+ {
+ ImplEntryType* pImplEntry = GetEntry( --n );
+ delete pImplEntry;
+ }
+ List::Clear();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::SelectEntry( USHORT nPos, BOOL bSelect )
+{
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ if ( pImplEntry &&
+ ( pImplEntry->mbIsSelected != bSelect ) &&
+ ( (pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0 ) )
+ {
+ pImplEntry->mbIsSelected = bSelect;
+ if ( mbCallSelectionChangedHdl )
+ maSelectionChangedHdl.Call( (void*)sal_IntPtr(nPos) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+uno::Reference< i18n::XCollator > ImplGetCollator (lang::Locale &rLocale)
+{
+ static uno::Reference< i18n::XCollator > xCollator;
+ if ( !xCollator.is() )
+ xCollator = vcl::unohelper::CreateCollator();
+ if( xCollator.is() )
+ xCollator->loadDefaultCollator (rLocale, 0);
+
+ return xCollator;
+}
+
+USHORT ImplEntryList::InsertEntry( USHORT nPos, ImplEntryType* pNewEntry, BOOL bSort )
+{
+ if ( !!pNewEntry->maImage )
+ mnImages++;
+
+ if ( !bSort || !Count() )
+ {
+ Insert( pNewEntry, nPos );
+ }
+ else
+ {
+ lang::Locale aLocale = Application::GetSettings().GetLocale();
+ uno::Reference< i18n::XCollator > xCollator = ImplGetCollator(aLocale);
+
+ const XubString& rStr = pNewEntry->maStr;
+ ULONG nLow, nHigh, nMid;
+
+ nHigh = Count();
+
+ ImplEntryType* pTemp = GetEntry( (USHORT)(nHigh-1) );
+
+ try
+ {
+ // XXX even though XCollator::compareString returns a sal_Int32 the only
+ // defined values are {-1, 0, 1} which is compatible with StringCompare
+ StringCompare eComp = xCollator.is() ?
+ (StringCompare)xCollator->compareString (rStr, pTemp->maStr)
+ : COMPARE_EQUAL;
+
+ // Schnelles Einfuegen bei sortierten Daten
+ if ( eComp != COMPARE_LESS )
+ {
+ Insert( pNewEntry, LIST_APPEND );
+ }
+ else
+ {
+ nLow = mnMRUCount;
+ pTemp = (ImplEntryType*)GetEntry( (USHORT)nLow );
+
+ eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
+ if ( eComp != COMPARE_GREATER )
+ {
+ Insert( pNewEntry, (ULONG)0 );
+ }
+ else
+ {
+ // Binaeres Suchen
+ nHigh--;
+ do
+ {
+ nMid = (nLow + nHigh) / 2;
+ pTemp = (ImplEntryType*)GetObject( nMid );
+
+ eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
+
+ if ( eComp == COMPARE_LESS )
+ nHigh = nMid-1;
+ else
+ {
+ if ( eComp == COMPARE_GREATER )
+ nLow = nMid + 1;
+ else
+ break;
+ }
+ }
+ while ( nLow <= nHigh );
+
+ if ( eComp != COMPARE_LESS )
+ nMid++;
+
+ Insert( pNewEntry, nMid );
+ }
+ }
+ }
+ catch (uno::RuntimeException& )
+ {
+ // XXX this is arguable, if the exception occured because pNewEntry is
+ // garbage you wouldn't insert it. If the exception occured because the
+ // Collator implementation is garbage then give the user a chance to see
+ // his stuff
+ Insert( pNewEntry, (ULONG)0 );
+ }
+
+ }
+
+ return (USHORT)GetPos( pNewEntry );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::RemoveEntry( USHORT nPos )
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::Remove( nPos );
+ if ( pImplEntry )
+ {
+ if ( !!pImplEntry->maImage )
+ mnImages--;
+
+ delete pImplEntry;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindEntry( const XubString& rString, BOOL bSearchMRUArea ) const
+{
+ USHORT nEntries = GetEntryCount();
+ for ( USHORT n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
+ {
+ ImplEntryType* pImplEntry = GetEntry( n );
+ String aComp( vcl::I18nHelper::filterFormattingChars( pImplEntry->maStr ) );
+ if ( aComp == rString )
+ return n;
+ }
+ return LISTBOX_ENTRY_NOTFOUND;
+}
+
+ // -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindMatchingEntry( const XubString& rStr, USHORT nStart, BOOL bForward, BOOL bLazy ) const
+{
+ USHORT nPos = LISTBOX_ENTRY_NOTFOUND;
+ USHORT nEntryCount = GetEntryCount();
+ if ( !bForward )
+ nStart++; // wird sofort dekrementiert
+
+ const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
+ for ( USHORT n = nStart; bForward ? ( n < nEntryCount ) : n; )
+ {
+ if ( !bForward )
+ n--;
+
+ ImplEntryType* pImplEntry = GetEntry( n );
+ BOOL bMatch = bLazy ? rI18nHelper.MatchString( rStr, pImplEntry->maStr ) != 0 : ( rStr.Match( pImplEntry->maStr ) == STRING_MATCH );
+ if ( bMatch )
+ {
+ nPos = n;
+ break;
+ }
+
+ if ( bForward )
+ n++;
+ }
+
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindEntry( const void* pData ) const
+{
+ USHORT nPos = LISTBOX_ENTRY_NOTFOUND;
+ for ( USHORT n = GetEntryCount(); n; )
+ {
+ ImplEntryType* pImplEntry = GetEntry( --n );
+ if ( pImplEntry->mpUserData == pData )
+ {
+ nPos = n;
+ break;
+ }
+ }
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplEntryList::GetAddedHeight( USHORT i_nEndIndex, USHORT i_nBeginIndex, long i_nBeginHeight ) const
+{
+ long nHeight = i_nBeginHeight;
+ USHORT nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
+ USHORT nStop = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
+ USHORT nEntryCount = GetEntryCount();
+ if( nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
+ {
+ // sanity check
+ if( nStop > nEntryCount-1 )
+ nStop = nEntryCount-1;
+ if( nStart > nEntryCount-1 )
+ nStart = nEntryCount-1;
+
+ USHORT nIndex = nStart;
+ while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
+ {
+ nHeight += GetEntryPtr( nIndex )-> mnHeight;
+ nIndex++;
+ }
+ }
+ else
+ nHeight = 0;
+ return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplEntryList::GetEntryHeight( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ return pImplEntry ? pImplEntry->mnHeight : 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString ImplEntryList::GetEntryText( USHORT nPos ) const
+{
+ XubString aEntryText;
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ if ( pImplEntry )
+ aEntryText = pImplEntry->maStr;
+ return aEntryText;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplEntryList::HasEntryImage( USHORT nPos ) const
+{
+ BOOL bImage = FALSE;
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ bImage = !!pImplEntry->maImage;
+ return bImage;
+}
+
+// -----------------------------------------------------------------------
+
+Image ImplEntryList::GetEntryImage( USHORT nPos ) const
+{
+ Image aImage;
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ aImage = pImplEntry->maImage;
+ return aImage;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::SetEntryData( USHORT nPos, void* pNewData )
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ pImplEntry->mpUserData = pNewData;
+}
+
+// -----------------------------------------------------------------------
+
+void* ImplEntryList::GetEntryData( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ return pImplEntry ? pImplEntry->mpUserData : NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::SetEntryFlags( USHORT nPos, long nFlags )
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ pImplEntry->mnFlags = nFlags;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplEntryList::GetEntryFlags( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ return pImplEntry ? pImplEntry->mnFlags : 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::GetSelectEntryCount() const
+{
+ USHORT nSelCount = 0;
+ for ( USHORT n = GetEntryCount(); n; )
+ {
+ ImplEntryType* pImplEntry = GetEntry( --n );
+ if ( pImplEntry->mbIsSelected )
+ nSelCount++;
+ }
+ return nSelCount;
+}
+
+// -----------------------------------------------------------------------
+
+XubString ImplEntryList::GetSelectEntry( USHORT nIndex ) const
+{
+ return GetEntryText( GetSelectEntryPos( nIndex ) );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::GetSelectEntryPos( USHORT nIndex ) const
+{
+ USHORT nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
+ USHORT nSel = 0;
+ USHORT nEntryCount = GetEntryCount();
+
+ for ( USHORT n = 0; n < nEntryCount; n++ )
+ {
+ ImplEntryType* pImplEntry = GetEntry( n );
+ if ( pImplEntry->mbIsSelected )
+ {
+ if ( nSel == nIndex )
+ {
+ nSelEntryPos = n;
+ break;
+ }
+ nSel++;
+ }
+ }
+
+ return nSelEntryPos;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplEntryList::IsEntrySelected( const XubString& rStr ) const
+{
+ return IsEntryPosSelected( FindEntry( rStr ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplEntryList::IsEntryPosSelected( USHORT nIndex ) const
+{
+ ImplEntryType* pImplEntry = GetEntry( nIndex );
+ return pImplEntry ? pImplEntry->mbIsSelected : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplEntryList::IsEntrySelectable( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ return pImplEntry ? ((pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0) : true;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindFirstSelectable( USHORT nPos, bool bForward /* = true */ )
+{
+ if( IsEntrySelectable( nPos ) )
+ return nPos;
+
+ if( bForward )
+ {
+ for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
+ {
+ if( IsEntrySelectable( nPos ) )
+ return nPos;
+ }
+ }
+ else
+ {
+ while( nPos )
+ {
+ nPos--;
+ if( IsEntrySelectable( nPos ) )
+ return nPos;
+ }
+ }
+
+ return LISTBOX_ENTRY_NOTFOUND;
+}
+
+// =======================================================================
+
+ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) :
+ Control( pParent, 0 )
+{
+ mpEntryList = new ImplEntryList( this );
+
+ mnTop = 0;
+ mnLeft = 0;
+ mnBorder = 1;
+ mnSelectModifier = 0;
+ mnUserDrawEntry = LISTBOX_ENTRY_NOTFOUND;
+ mbTrack = FALSE;
+ mbImgsDiffSz = FALSE;
+ mbTravelSelect = FALSE;
+ mbTrackingSelect = FALSE;
+ mbSelectionChanged = FALSE;
+ mbMouseMoveSelect = FALSE;
+ mbMulti = FALSE;
+ mbStackMode = FALSE;
+ mbGrabFocus = FALSE;
+ mbUserDrawEnabled = FALSE;
+ mbInUserDraw = FALSE;
+ mbReadOnly = FALSE;
+ mbHasFocusRect = FALSE;
+ mbRight = ( nWinStyle & WB_RIGHT ) ? TRUE : FALSE;
+ mbCenter = ( nWinStyle & WB_CENTER ) ? TRUE : FALSE;
+ mbSimpleMode = ( nWinStyle & WB_SIMPLEMODE ) ? TRUE : FALSE;
+ mbSort = ( nWinStyle & WB_SORT ) ? TRUE : FALSE;
+
+ // pb: #106948# explicit mirroring for calc
+ mbMirroring = FALSE;
+
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+ mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+ mnSeparatorPos = LISTBOX_ENTRY_NOTFOUND;
+ meProminentType = PROMINENT_TOP;
+
+ SetLineColor();
+ SetTextFillColor();
+ SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
+
+ maSearchTimeout.SetTimeout( 2500 );
+ maSearchTimeout.SetTimeoutHdl( LINK( this, ImplListBoxWindow, SearchStringTimeout ) );
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ ImplCalcMetrics();
+}
+
+// -----------------------------------------------------------------------
+
+ImplListBoxWindow::~ImplListBoxWindow()
+{
+ maSearchTimeout.Stop();
+ delete mpEntryList;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground )
+{
+ ImplInitFieldSettings( this, bFont, bForeground, bBackground );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplCalcMetrics()
+{
+ mnMaxWidth = 0;
+ mnMaxTxtWidth = 0;
+ mnMaxImgWidth = 0;
+ mnMaxImgTxtWidth= 0;
+ mnMaxImgHeight = 0;
+
+ mnTextHeight = (USHORT)GetTextHeight();
+ mnMaxTxtHeight = mnTextHeight + mnBorder;
+ mnMaxHeight = mnMaxTxtHeight;
+
+ if ( maUserItemSize.Height() > mnMaxHeight )
+ mnMaxHeight = (USHORT) maUserItemSize.Height();
+ if ( maUserItemSize.Width() > mnMaxWidth )
+ mnMaxWidth= (USHORT) maUserItemSize.Width();
+
+ for ( USHORT n = mpEntryList->GetEntryCount(); n; )
+ {
+ ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
+ ImplUpdateEntryMetrics( *pEntry );
+ }
+
+ if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
+ maFocusRect.SetSize( aSz );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBoxWindow, SearchStringTimeout, Timer*, EMPTYARG )
+{
+ maSearchStr.Erase();
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Clear()
+{
+ mpEntryList->Clear();
+
+ mnMaxHeight = mnMaxTxtHeight;
+ mnMaxWidth = 0;
+ mnMaxTxtWidth = 0;
+ mnMaxImgTxtWidth= 0;
+ mnMaxImgWidth = 0;
+ mnMaxImgHeight = 0;
+ mnTop = 0;
+ mnLeft = 0;
+ mbImgsDiffSz = FALSE;
+ ImplClearLayoutData();
+
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+
+ Invalidate();
+}
+
+void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
+{
+ ImplClearLayoutData();
+ maUserItemSize = rSz;
+ ImplCalcMetrics();
+}
+
+// -----------------------------------------------------------------------
+
+struct ImplEntryMetrics
+{
+ BOOL bText;
+ BOOL bImage;
+ long nEntryWidth;
+ long nEntryHeight;
+ long nTextWidth;
+ long nImgWidth;
+ long nImgHeight;
+};
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
+{
+ ImplEntryMetrics aMetrics;
+ aMetrics.bText = rEntry.maStr.Len() ? TRUE : FALSE;
+ aMetrics.bImage = !!rEntry.maImage;
+ aMetrics.nEntryWidth = 0;
+ aMetrics.nEntryHeight = 0;
+ aMetrics.nTextWidth = 0;
+ aMetrics.nImgWidth = 0;
+ aMetrics.nImgHeight = 0;
+
+ if ( aMetrics.bText )
+ {
+ if( (rEntry.mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
+ {
+ // multiline case
+ Size aCurSize( PixelToLogic( GetSizePixel() ) );
+ // set the current size to a large number
+ // GetTextRect should shrink it to the actual size
+ aCurSize.Height() = 0x7fffff;
+ Rectangle aTextRect( Point( 0, 0 ), aCurSize );
+ aTextRect = GetTextRect( aTextRect, rEntry.maStr, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
+ aMetrics.nTextWidth = aTextRect.GetWidth();
+ if( aMetrics.nTextWidth > mnMaxTxtWidth )
+ mnMaxTxtWidth = aMetrics.nTextWidth;
+ aMetrics.nEntryWidth = mnMaxTxtWidth;
+ aMetrics.nEntryHeight = aTextRect.GetHeight() + mnBorder;
+ }
+ else
+ {
+ // normal single line case
+ aMetrics.nTextWidth = (USHORT)GetTextWidth( rEntry.maStr );
+ if( aMetrics.nTextWidth > mnMaxTxtWidth )
+ mnMaxTxtWidth = aMetrics.nTextWidth;
+ aMetrics.nEntryWidth = mnMaxTxtWidth;
+ aMetrics.nEntryHeight = mnTextHeight + mnBorder;
+ }
+ }
+ if ( aMetrics.bImage )
+ {
+ Size aImgSz = rEntry.maImage.GetSizePixel();
+ aMetrics.nImgWidth = (USHORT) CalcZoom( aImgSz.Width() );
+ aMetrics.nImgHeight = (USHORT) CalcZoom( aImgSz.Height() );
+
+ if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
+ mbImgsDiffSz = TRUE;
+ else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
+ mbImgsDiffSz = TRUE;
+
+ if( aMetrics.nImgWidth > mnMaxImgWidth )
+ mnMaxImgWidth = aMetrics.nImgWidth;
+ if( aMetrics.nImgHeight > mnMaxImgHeight )
+ mnMaxImgHeight = aMetrics.nImgHeight;
+
+ mnMaxImgTxtWidth = Max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
+ aMetrics.nEntryHeight = Max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
+
+ }
+ if ( IsUserDrawEnabled() || aMetrics.bImage )
+ {
+ aMetrics.nEntryWidth = Max( aMetrics.nImgWidth, maUserItemSize.Width() );
+ if ( aMetrics.bText )
+ aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
+ aMetrics.nEntryHeight = Max( Max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
+ aMetrics.nEntryHeight );
+ }
+
+ if ( !aMetrics.bText && !aMetrics.bImage && !IsUserDrawEnabled() )
+ {
+ // entries which have no (aka an empty) text, and no image, and are not user-drawn, should be
+ // shown nonetheless
+ aMetrics.nEntryHeight = mnTextHeight + mnBorder;
+ }
+
+ if ( aMetrics.nEntryWidth > mnMaxWidth )
+ mnMaxWidth = aMetrics.nEntryWidth;
+ if ( aMetrics.nEntryHeight > mnMaxHeight )
+ mnMaxHeight = aMetrics.nEntryHeight;
+
+ rEntry.mnHeight = aMetrics.nEntryHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplCallSelect()
+{
+ if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
+ {
+ // Insert the selected entry as MRU, if not allready first MRU
+ USHORT nSelected = GetEntryList()->GetSelectEntryPos( 0 );
+ USHORT nMRUCount = GetEntryList()->GetMRUCount();
+ String aSelected = GetEntryList()->GetEntryText( nSelected );
+ USHORT nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, TRUE );
+ if ( nFirstMatchingEntryPos || !nMRUCount )
+ {
+ BOOL bSelectNewEntry = FALSE;
+ if ( nFirstMatchingEntryPos < nMRUCount )
+ {
+ RemoveEntry( nFirstMatchingEntryPos );
+ nMRUCount--;
+ if ( nFirstMatchingEntryPos == nSelected )
+ bSelectNewEntry = TRUE;
+ }
+ else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
+ {
+ RemoveEntry( nMRUCount - 1 );
+ nMRUCount--;
+ }
+
+ ImplClearLayoutData();
+
+ ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
+ pNewEntry->mbIsSelected = bSelectNewEntry;
+ GetEntryList()->InsertEntry( 0, pNewEntry, FALSE );
+ ImplUpdateEntryMetrics( *pNewEntry );
+ GetEntryList()->SetMRUCount( ++nMRUCount );
+ SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
+ maMRUChangedHdl.Call( NULL );
+ }
+ }
+
+ maSelectHdl.Call( NULL );
+ mbSelectionChanged = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::InsertEntry( USHORT nPos, ImplEntryType* pNewEntry )
+{
+ ImplClearLayoutData();
+ USHORT nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
+
+ if( (GetStyle() & WB_WORDBREAK) )
+ pNewEntry->mnFlags |= LISTBOX_ENTRY_FLAG_MULTILINE;
+
+ ImplUpdateEntryMetrics( *pNewEntry );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::RemoveEntry( USHORT nPos )
+{
+ ImplClearLayoutData();
+ mpEntryList->RemoveEntry( nPos );
+ if( mnCurrentPos >= mpEntryList->GetEntryCount() )
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+ ImplCalcMetrics();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SetEntryFlags( USHORT nPos, long nFlags )
+{
+ mpEntryList->SetEntryFlags( nPos, nFlags );
+ ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
+ if( pEntry )
+ ImplUpdateEntryMetrics( *pEntry );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplShowFocusRect()
+{
+ if ( mbHasFocusRect )
+ HideFocus();
+ ShowFocus( maFocusRect );
+ mbHasFocusRect = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplHideFocusRect()
+{
+ if ( mbHasFocusRect )
+ {
+ HideFocus();
+ mbHasFocusRect = FALSE;
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
+{
+ long nY = mnBorder;
+
+ USHORT nSelect = mnTop;
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
+ while( pEntry && rPoint.Y() > pEntry->mnHeight + nY )
+ {
+ nY += pEntry->mnHeight;
+ pEntry = mpEntryList->GetEntryPtr( ++nSelect );
+ }
+ if( pEntry == NULL )
+ nSelect = LISTBOX_ENTRY_NOTFOUND;
+
+ return nSelect;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplListBoxWindow::IsVisible( USHORT i_nEntry ) const
+{
+ BOOL bRet = FALSE;
+
+ if( i_nEntry >= mnTop )
+ {
+ if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
+ PixelToLogic( GetSizePixel() ).Height() )
+ {
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::GetLastVisibleEntry() const
+{
+ USHORT nPos = mnTop;
+ long nWindowHeight = GetSizePixel().Height();
+ USHORT nCount = mpEntryList->GetEntryCount();
+ long nDiff;
+ for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
+ nPos++;
+
+ if( nDiff > nWindowHeight && nPos > mnTop )
+ nPos--;
+
+ if( nPos >= nCount )
+ nPos = nCount-1;
+
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ mbMouseMoveSelect = FALSE; // Nur bis zum ersten MouseButtonDown
+ maSearchStr.Erase();
+
+ if ( !IsReadOnly() )
+ {
+ if( rMEvt.GetClicks() == 1 )
+ {
+ USHORT nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
+ if( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ {
+ if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
+ mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
+ else
+ mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+
+ mnCurrentPos = nSelect;
+ mbTrackingSelect = TRUE;
+ SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
+ mbTrackingSelect = FALSE;
+ if ( mbGrabFocus )
+ GrabFocus();
+
+ StartTracking( STARTTRACK_SCROLLREPEAT );
+ }
+ }
+ if( rMEvt.GetClicks() == 2 )
+ {
+ maDoubleClickHdl.Call( this );
+ }
+ }
+ else // if ( mbGrabFocus )
+ {
+ GrabFocus();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeaveWindow() )
+ {
+ if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
+ {
+ if ( rMEvt.GetPosPixel().Y() < 0 )
+ {
+ DeselectAll();
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+ SetTopEntry( 0 );
+ if ( mbStackMode ) // #87072#, #92323#
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rMEvt.GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+
+ }
+ }
+ }
+ else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
+ {
+ Point aPoint;
+ Rectangle aRect( aPoint, GetOutputSizePixel() );
+ if( aRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ if ( IsMouseMoveSelect() )
+ {
+ USHORT nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
+ if( nSelect == LISTBOX_ENTRY_NOTFOUND )
+ nSelect = mpEntryList->GetEntryCount() - 1;
+ nSelect = Min( nSelect, GetLastVisibleEntry() );
+ nSelect = Min( nSelect, (USHORT) ( mpEntryList->GetEntryCount() - 1 ) );
+ // Select only visible Entries with MouseMove, otherwise Tracking...
+ if ( IsVisible( nSelect ) &&
+ mpEntryList->IsEntrySelectable( nSelect ) &&
+ ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
+ {
+ mbTrackingSelect = TRUE;
+ if ( SelectEntries( nSelect, LET_TRACKING, FALSE, FALSE ) )
+ {
+ if ( mbStackMode ) // #87072#
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rMEvt.GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+ mbTrackingSelect = FALSE;
+ }
+ }
+
+ // Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
+ // Maustaste in die ListBox faehrt...
+ if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
+ {
+ if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
+ mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
+ else
+ mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+
+ if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
+ mpEntryList->SetSelectionAnchor( 0 );
+
+ StartTracking( STARTTRACK_SCROLLREPEAT );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::DeselectAll()
+{
+ while ( GetEntryList()->GetSelectEntryCount() )
+ {
+ USHORT nS = GetEntryList()->GetSelectEntryPos( 0 );
+ SelectEntry( nS, FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SelectEntry( USHORT nPos, BOOL bSelect )
+{
+ if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
+ {
+ ImplHideFocusRect();
+ if( bSelect )
+ {
+ if( !mbMulti )
+ {
+ // Selektierten Eintrag deselektieren
+ USHORT nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
+ if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
+ {
+ //SelectEntryPos( nDeselect, FALSE );
+ GetEntryList()->SelectEntry( nDeselect, FALSE );
+ if ( IsUpdateMode() && IsReallyVisible() )
+ ImplPaint( nDeselect, TRUE );
+ }
+ }
+ mpEntryList->SelectEntry( nPos, TRUE );
+ mnCurrentPos = nPos;
+ if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
+ {
+ ImplPaint( nPos );
+ if ( !IsVisible( nPos ) )
+ {
+ ImplClearLayoutData();
+ USHORT nVisibleEntries = GetLastVisibleEntry()-mnTop;
+ if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
+ {
+ Resize();
+ ShowProminentEntry( nPos );
+ }
+ else
+ {
+ ShowProminentEntry( nPos );
+ }
+ }
+ }
+ }
+ else
+ {
+ mpEntryList->SelectEntry( nPos, FALSE );
+ ImplPaint( nPos, TRUE );
+ }
+ mbSelectionChanged = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplListBoxWindow::SelectEntries( USHORT nSelect, LB_EVENT_TYPE eLET, BOOL bShift, BOOL bCtrl )
+{
+ BOOL bFocusChanged = FALSE;
+ BOOL bSelectionChanged = FALSE;
+
+ if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
+ {
+ // Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
+ if( !mbMulti )
+ {
+ USHORT nDeselect = mpEntryList->GetSelectEntryPos( 0 );
+ if( nSelect != nDeselect )
+ {
+ SelectEntry( nSelect, TRUE );
+ mpEntryList->SetLastSelected( nSelect );
+ bFocusChanged = TRUE;
+ bSelectionChanged = TRUE;
+ }
+ }
+ // MultiListBox ohne Modifier
+ else if( mbSimpleMode && !bCtrl && !bShift )
+ {
+ USHORT nEntryCount = mpEntryList->GetEntryCount();
+ for ( USHORT nPos = 0; nPos < nEntryCount; nPos++ )
+ {
+ BOOL bSelect = nPos == nSelect;
+ if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
+ {
+ SelectEntry( nPos, bSelect );
+ bFocusChanged = TRUE;
+ bSelectionChanged = TRUE;
+ }
+ }
+ mpEntryList->SetLastSelected( nSelect );
+ mpEntryList->SetSelectionAnchor( nSelect );
+ }
+ // MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
+ else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
+ {
+ // Space fuer Selektionswechsel
+ if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
+ {
+ BOOL bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? TRUE : !mpEntryList->IsEntryPosSelected( nSelect );
+ if ( mbStackMode )
+ {
+ USHORT n;
+ if ( bSelect )
+ {
+ // All entries before nSelect must be selected...
+ for ( n = 0; n < nSelect; n++ )
+ SelectEntry( n, TRUE );
+ }
+ if ( !bSelect )
+ {
+ for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
+ SelectEntry( n, FALSE );
+ }
+ }
+ SelectEntry( nSelect, bSelect );
+ mpEntryList->SetLastSelected( nSelect );
+ mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
+ if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
+ mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
+ bFocusChanged = TRUE;
+ bSelectionChanged = TRUE;
+ }
+ else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
+ ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
+ {
+ mnCurrentPos = nSelect;
+ bFocusChanged = TRUE;
+
+ USHORT nAnchor = mpEntryList->GetSelectionAnchor();
+ if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
+ {
+ nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
+ }
+ if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
+ {
+ // Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
+ USHORT nStart = Min( nSelect, nAnchor );
+ USHORT nEnd = Max( nSelect, nAnchor );
+ for ( USHORT n = nStart; n <= nEnd; n++ )
+ {
+ if ( !mpEntryList->IsEntryPosSelected( n ) )
+ {
+ SelectEntry( n, TRUE );
+ bSelectionChanged = TRUE;
+ }
+ }
+
+ // Ggf. muss noch was deselektiert werden...
+ USHORT nLast = mpEntryList->GetLastSelected();
+ if ( nLast != LISTBOX_ENTRY_NOTFOUND )
+ {
+ if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
+ {
+ for ( USHORT n = nSelect+1; n <= nLast; n++ )
+ {
+ if ( mpEntryList->IsEntryPosSelected( n ) )
+ {
+ SelectEntry( n, FALSE );
+ bSelectionChanged = TRUE;
+ }
+ }
+ }
+ else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
+ {
+ for ( USHORT n = nLast; n < nSelect; n++ )
+ {
+ if ( mpEntryList->IsEntryPosSelected( n ) )
+ {
+ SelectEntry( n, FALSE );
+ bSelectionChanged = TRUE;
+ }
+ }
+ }
+ }
+ mpEntryList->SetLastSelected( nSelect );
+ }
+ }
+ else if( eLET != LET_TRACKING )
+ {
+ ImplHideFocusRect();
+ ImplPaint( nSelect, TRUE );
+ bFocusChanged = TRUE;
+ }
+ }
+ else if( bShift )
+ {
+ bFocusChanged = TRUE;
+ }
+
+ if( bSelectionChanged )
+ mbSelectionChanged = TRUE;
+
+ if( bFocusChanged )
+ {
+ long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(),
+ mpEntryList->GetEntryHeight( nSelect ) );
+ maFocusRect.SetSize( aSz );
+ if( HasFocus() )
+ ImplShowFocusRect();
+ }
+ ImplClearLayoutData();
+ }
+ return bSelectionChanged;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
+{
+ Point aPoint;
+ Rectangle aRect( aPoint, GetOutputSizePixel() );
+ BOOL bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
+
+ if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
+ {
+ if ( bInside && !rTEvt.IsTrackingCanceled() )
+ {
+ mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
+ ImplCallSelect();
+ }
+ else
+ {
+ maCancelHdl.Call( NULL );
+ if ( !mbMulti )
+ {
+ mbTrackingSelect = TRUE;
+ SelectEntry( mnTrackingSaveSelection, TRUE );
+ mbTrackingSelect = FALSE;
+ if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
+ {
+ long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(),
+ mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ ImplShowFocusRect();
+ }
+ }
+ }
+
+ mbTrack = FALSE;
+ }
+ else
+ {
+ BOOL bTrackOrQuickClick = mbTrack;
+ if( !mbTrack )
+ {
+ if ( bInside )
+ {
+ mbTrack = TRUE;
+ }
+
+ // Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
+ if( rTEvt.IsTrackingEnded() && mbTrack )
+ {
+ bTrackOrQuickClick = TRUE;
+ mbTrack = FALSE;
+ }
+ }
+
+ if( bTrackOrQuickClick )
+ {
+ MouseEvent aMEvt = rTEvt.GetMouseEvent();
+ Point aPt( aMEvt.GetPosPixel() );
+ BOOL bShift = aMEvt.IsShift();
+ BOOL bCtrl = aMEvt.IsMod1();
+
+ USHORT nSelect = LISTBOX_ENTRY_NOTFOUND;
+ if( aPt.Y() < 0 )
+ {
+ if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
+ if( nSelect < mnTop )
+ SetTopEntry( mnTop-1 );
+ }
+ }
+ else if( aPt.Y() > GetOutputSizePixel().Height() )
+ {
+ if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = Min( (USHORT)(mnCurrentPos+1), (USHORT)(mpEntryList->GetEntryCount()-1) );
+ if( nSelect >= GetLastVisibleEntry() )
+ SetTopEntry( mnTop+1 );
+ }
+ }
+ else
+ {
+ nSelect = (USHORT) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (USHORT) mnTop;
+ nSelect = Min( nSelect, GetLastVisibleEntry() );
+ nSelect = Min( nSelect, (USHORT) ( mpEntryList->GetEntryCount() - 1 ) );
+ }
+
+ if ( bInside )
+ {
+ if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
+ {
+ mbTrackingSelect = TRUE;
+ if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
+ {
+ if ( mbStackMode ) // #87734# (#87072#)
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+ mbTrackingSelect = FALSE;
+ }
+ }
+ else
+ {
+ if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
+ {
+ mbTrackingSelect = TRUE;
+ SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), FALSE );
+ mbTrackingSelect = FALSE;
+ }
+ else if ( mbStackMode )
+ {
+ if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
+ {
+ if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
+ {
+ BOOL bSelectionChanged = FALSE;
+ if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
+ && !mnCurrentPos )
+ {
+ if ( mpEntryList->IsEntryPosSelected( 0 ) )
+ {
+ SelectEntry( 0, FALSE );
+ bSelectionChanged = TRUE;
+ nSelect = LISTBOX_ENTRY_NOTFOUND;
+
+ }
+ }
+ else
+ {
+ mbTrackingSelect = TRUE;
+ bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
+ mbTrackingSelect = FALSE;
+ }
+
+ if ( bSelectionChanged )
+ {
+ mbSelectionChanged = TRUE;
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+ }
+ }
+ }
+ mnCurrentPos = nSelect;
+ if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ ImplHideFocusRect();
+ }
+ else
+ {
+ long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ ImplShowFocusRect();
+ }
+ }
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ if( !ProcessKeyInput( rKEvt ) )
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+#define IMPL_SELECT_NODIRECTION 0
+#define IMPL_SELECT_UP 1
+#define IMPL_SELECT_DOWN 2
+
+BOOL ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
+{
+ // zu selektierender Eintrag
+ USHORT nSelect = LISTBOX_ENTRY_NOTFOUND;
+ LB_EVENT_TYPE eLET = LET_KEYMOVE;
+
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ BOOL bShift = aKeyCode.IsShift();
+ BOOL bCtrl = aKeyCode.IsMod1() || aKeyCode.IsMod3();
+ BOOL bMod2 = aKeyCode.IsMod2();
+ BOOL bDone = FALSE;
+
+ switch( aKeyCode.GetCode() )
+ {
+ case KEY_UP:
+ {
+ if ( IsReadOnly() )
+ {
+ if ( GetTopEntry() )
+ SetTopEntry( GetTopEntry()-1 );
+ }
+ else if ( !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( mnCurrentPos )
+ {
+ // search first selectable above the current position
+ nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
+ }
+
+ if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
+ SetTopEntry( mnTop-1 );
+
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_DOWN:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( GetTopEntry()+1 );
+ }
+ else if ( !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
+ {
+ // search first selectable below the current position
+ nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
+ }
+
+ if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
+ SetTopEntry( mnTop+1 );
+
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_PAGEUP:
+ {
+ if ( IsReadOnly() )
+ {
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop +1;
+ SetTopEntry( ( mnTop > nCurVis ) ?
+ (mnTop-nCurVis) : 0 );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( mnCurrentPos )
+ {
+ if( mnCurrentPos == mnTop )
+ {
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop +1;
+ SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
+ }
+
+ // find first selectable starting from mnTop looking foreward
+ nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_PAGEDOWN:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( GetLastVisibleEntry() );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
+ {
+ USHORT nCount = mpEntryList->GetEntryCount();
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop;
+ USHORT nTmp = Min( nCurVis, nCount );
+ nTmp += mnTop - 1;
+ if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
+ {
+ long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
+ nTmp2 = Max( (long)0 , nTmp2 );
+ nTmp = (USHORT)(nTmp2+(nCurVis-1) );
+ SetTopEntry( (USHORT)nTmp2 );
+ }
+ // find first selectable starting from nTmp looking backwards
+ nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_HOME:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( 0 );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if ( mnCurrentPos )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
+ if( mnTop != 0 )
+ SetTopEntry( 0 );
+
+ bDone = TRUE;
+ }
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_END:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( 0xFFFF );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
+ {
+ USHORT nCount = mpEntryList->GetEntryCount();
+ nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop + 1;
+ if( nCount > nCurVis )
+ SetTopEntry( nCount - nCurVis );
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_LEFT:
+ {
+ if ( !bCtrl && !bMod2 )
+ {
+ ScrollHorz( -HORZ_SCROLL );
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_RIGHT:
+ {
+ if ( !bCtrl && !bMod2 )
+ {
+ ScrollHorz( HORZ_SCROLL );
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_RETURN:
+ {
+ if ( !bMod2 && !IsReadOnly() )
+ {
+ mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
+ ImplCallSelect();
+ bDone = FALSE; // RETURN nicht abfangen.
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_SPACE:
+ {
+ if ( !bMod2 && !IsReadOnly() )
+ {
+ if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
+ {
+ nSelect = mnCurrentPos;
+ eLET = LET_KEYSPACE;
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_A:
+ {
+ if( bCtrl && mbMulti )
+ {
+ // paint only once
+ BOOL bUpdates = IsUpdateMode();
+ SetUpdateMode( FALSE );
+
+ USHORT nEntryCount = mpEntryList->GetEntryCount();
+ for( USHORT i = 0; i < nEntryCount; i++ )
+ SelectEntry( i, TRUE );
+
+ // restore update mode
+ SetUpdateMode( bUpdates );
+ Invalidate();
+
+ maSearchStr.Erase();
+
+ bDone = TRUE;
+ break;
+ }
+ }
+ // fall through intentional
+ default:
+ {
+ xub_Unicode c = rKEvt.GetCharCode();
+
+ if ( !IsReadOnly() && (c >= 32) && (c != 127) && !rKEvt.GetKeyCode().IsMod2() )
+ {
+ maSearchStr += c;
+ XubString aTmpSearch( maSearchStr );
+
+ nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, mnCurrentPos );
+ if ( (nSelect == LISTBOX_ENTRY_NOTFOUND) && (aTmpSearch.Len() > 1) )
+ {
+ // Wenn alles die gleichen Buchstaben, dann anderer Such-Modus
+ BOOL bAllEqual = TRUE;
+ for ( USHORT n = aTmpSearch.Len(); n && bAllEqual; )
+ bAllEqual = aTmpSearch.GetChar( --n ) == c;
+ if ( bAllEqual )
+ {
+ aTmpSearch = c;
+ nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, mnCurrentPos+1 );
+ }
+ }
+ if ( nSelect == LISTBOX_ENTRY_NOTFOUND )
+ nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, 0 );
+
+ if ( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ {
+ ShowProminentEntry( nSelect );
+
+ if ( mpEntryList->IsEntryPosSelected( nSelect ) )
+ nSelect = LISTBOX_ENTRY_NOTFOUND;
+
+ maSearchTimeout.Start();
+ }
+ else
+ maSearchStr.Erase();
+ bDone = TRUE;
+ }
+ }
+ }
+
+ if ( ( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ && ( ( !mpEntryList->IsEntryPosSelected( nSelect ) )
+ || ( eLET == LET_KEYSPACE )
+ )
+ )
+ {
+ DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
+ if( nSelect >= mpEntryList->GetEntryCount() )
+ nSelect = mpEntryList->GetEntryCount()-1;
+ mnCurrentPos = nSelect;
+ if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplPaint( USHORT nPos, BOOL bErase, bool bLayout )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
+ if( ! pEntry )
+ return;
+
+ long nWidth = GetOutputSizePixel().Width();
+ long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
+ Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
+
+ if( ! bLayout )
+ {
+ if( mpEntryList->IsEntryPosSelected( nPos ) )
+ {
+ SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
+ SetFillColor( rStyleSettings.GetHighlightColor() );
+ SetTextFillColor( rStyleSettings.GetHighlightColor() );
+ DrawRect( aRect );
+ }
+ else
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ if( !IsEnabled() )
+ SetTextColor( rStyleSettings.GetDisableColor() );
+ SetTextFillColor();
+ if( bErase )
+ Erase( aRect );
+ }
+ }
+
+ if ( IsUserDrawEnabled() )
+ {
+ mbInUserDraw = TRUE;
+ mnUserDrawEntry = nPos;
+ aRect.Left() -= mnLeft;
+ if ( nPos < GetEntryList()->GetMRUCount() )
+ nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
+ nPos = sal::static_int_cast<USHORT>(nPos - GetEntryList()->GetMRUCount());
+ UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
+ maUserDrawHdl.Call( &aUDEvt );
+ mbInUserDraw = FALSE;
+ }
+ else
+ {
+ DrawEntry( nPos, TRUE, TRUE, FALSE, bLayout );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::DrawEntry( USHORT nPos, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos, bool bLayout )
+{
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
+ if( ! pEntry )
+ return;
+
+ // Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
+
+ if ( mbInUserDraw )
+ nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
+
+ long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
+ Size aImgSz;
+
+ if( bDrawImage && mpEntryList->HasImages() && !bLayout )
+ {
+ Image aImage = mpEntryList->GetEntryImage( nPos );
+ if( !!aImage )
+ {
+ aImgSz = aImage.GetSizePixel();
+ Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
+
+ // pb: #106948# explicit mirroring for calc
+ if ( mbMirroring )
+ // right aligned
+ aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
+
+ if ( !IsZoom() )
+ {
+ DrawImage( aPtImg, aImage );
+ }
+ else
+ {
+ aImgSz.Width() = CalcZoom( aImgSz.Width() );
+ aImgSz.Height() = CalcZoom( aImgSz.Height() );
+ DrawImage( aPtImg, aImgSz, aImage );
+ }
+ }
+ }
+
+ if( bDrawText )
+ {
+ MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+ XubString aStr( mpEntryList->GetEntryText( nPos ) );
+ if ( aStr.Len() )
+ {
+ long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
+ GetOutputSizePixel().Width() - 2*mnBorder );
+ // a multiline entry should only be as wide a the window
+ if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
+ nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
+
+ Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
+ Size( nMaxWidth, pEntry->mnHeight ) );
+
+ if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
+ {
+ long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
+ aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
+ }
+
+ if( bLayout )
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
+
+ // pb: #106948# explicit mirroring for calc
+ if ( mbMirroring )
+ {
+ // right aligned
+ aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
+ if ( aImgSz.Width() > 0 )
+ aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
+ }
+
+ USHORT nDrawStyle = ImplGetTextStyle();
+ if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
+ nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
+ if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
+ nDrawStyle |= TEXT_DRAW_DISABLE;
+
+ DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
+ }
+ }
+
+ if( !bLayout )
+ {
+ if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
+ ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
+ {
+ Color aOldLineColor( GetLineColor() );
+ SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
+ Point aStartPos( 0, nY );
+ if ( nPos == mnSeparatorPos )
+ aStartPos.Y() += pEntry->mnHeight-1;
+ Point aEndPos( aStartPos );
+ aEndPos.X() = GetOutputSizePixel().Width();
+ DrawLine( aStartPos, aEndPos );
+ SetLineColor( aOldLineColor );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<ImplListBoxWindow*>(this)->
+ ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
+{
+ USHORT nCount = mpEntryList->GetEntryCount();
+
+ BOOL bShowFocusRect = mbHasFocusRect;
+ if ( mbHasFocusRect && ! bLayout )
+ ImplHideFocusRect();
+
+ long nY = 0; // + mnBorder;
+ long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
+
+ for( USHORT i = (USHORT)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
+ {
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
+ if( nY + pEntry->mnHeight >= rRect.Top() &&
+ nY <= rRect.Bottom() + mnMaxHeight )
+ {
+ ImplPaint( i, FALSE, bLayout );
+ }
+ nY += pEntry->mnHeight;
+ }
+
+ long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ if( HasFocus() && bShowFocusRect && !bLayout )
+ ImplShowFocusRect();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Paint( const Rectangle& rRect )
+{
+ ImplDoPaint( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::GetDisplayLineCount() const
+{
+ // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
+
+ USHORT nCount = mpEntryList->GetEntryCount();
+ long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
+ USHORT nEntries = static_cast< USHORT >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
+ if( nEntries > nCount-mnTop )
+ nEntries = nCount-mnTop;
+
+ return nEntries;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Resize()
+{
+ Control::Resize();
+
+ BOOL bShowFocusRect = mbHasFocusRect;
+ if ( bShowFocusRect )
+ ImplHideFocusRect();
+
+ if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ }
+
+ if ( bShowFocusRect )
+ ImplShowFocusRect();
+
+ ImplClearLayoutData();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::GetFocus()
+{
+ USHORT nPos = mnCurrentPos;
+ if ( nPos == LISTBOX_ENTRY_NOTFOUND )
+ nPos = 0;
+ long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
+ maFocusRect.SetSize( aSz );
+ ImplShowFocusRect();
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::LoseFocus()
+{
+ ImplHideFocusRect();
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+/*
+void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
+
+ Window::RequestHelp( rHEvt );
+}
+*/
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SetTopEntry( USHORT nTop )
+{
+ if( mpEntryList->GetEntryCount() == 0 )
+ return;
+
+ long nWHeight = PixelToLogic( GetSizePixel() ).Height();
+
+ USHORT nLastEntry = mpEntryList->GetEntryCount()-1;
+ if( nTop > nLastEntry )
+ nTop = nLastEntry;
+ const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
+ while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
+ nTop--;
+
+ if ( nTop != mnTop )
+ {
+ ImplClearLayoutData();
+ long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
+ Update();
+ ImplHideFocusRect();
+ mnTop = nTop;
+ Scroll( 0, nDiff );
+ Update();
+ maFocusRect.Top() += nDiff;
+ maFocusRect.Bottom() += nDiff;
+ if( HasFocus() )
+ ImplShowFocusRect();
+ maScrollHdl.Call( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ShowProminentEntry( USHORT nEntryPos )
+{
+ if( meProminentType == PROMINENT_MIDDLE )
+ {
+ USHORT nPos = nEntryPos;
+ long nWHeight = PixelToLogic( GetSizePixel() ).Height();
+ while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
+ nEntryPos--;
+ }
+ SetTopEntry( nEntryPos );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SetLeftIndent( long n )
+{
+ ScrollHorz( n - mnLeft );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ScrollHorz( long n )
+{
+ long nDiff = 0;
+ if ( n > 0 )
+ {
+ long nWidth = GetOutputSizePixel().Width();
+ if( ( mnMaxWidth - mnLeft + n ) > nWidth )
+ nDiff = n;
+ }
+ else if ( n < 0 )
+ {
+ if( mnLeft )
+ {
+ long nAbs = -n;
+ nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
+ }
+ }
+
+ if ( nDiff )
+ {
+ ImplClearLayoutData();
+ mnLeft = sal::static_int_cast<USHORT>(mnLeft + nDiff);
+ Update();
+ ImplHideFocusRect();
+ Scroll( -nDiff, 0 );
+ Update();
+ if( HasFocus() )
+ ImplShowFocusRect();
+ maScrollHdl.Call( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size ImplListBoxWindow::CalcSize( USHORT nMaxLines ) const
+{
+ // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
+
+ Size aSz;
+// USHORT nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
+ aSz.Height() = nMaxLines * mnMaxHeight;
+ aSz.Width() = mnMaxWidth + 2*mnBorder;
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ImplListBoxWindow::GetBoundingRectangle( USHORT nItem ) const
+{
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
+ Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
+ long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
+ Rectangle aRect( Point( 0, nY ), aSz );
+ return aRect;
+}
+
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_ZOOM )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ ImplCalcMetrics();
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsUpdateMode() && IsReallyVisible() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ ImplCalcMetrics();
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+ ImplClearLayoutData();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplClearLayoutData();
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ ImplCalcMetrics();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::ImplGetTextStyle() const
+{
+ USHORT nTextStyle = TEXT_DRAW_VCENTER;
+
+ if ( mpEntryList->HasImages() )
+ nTextStyle |= TEXT_DRAW_LEFT;
+ else if ( mbCenter )
+ nTextStyle |= TEXT_DRAW_CENTER;
+ else if ( mbRight )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else
+ nTextStyle |= TEXT_DRAW_LEFT;
+
+ return nTextStyle;
+}
+
+// =======================================================================
+
+ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
+ Control( pParent, nWinStyle ),
+ maLBWindow( this, nWinStyle&(~WB_BORDER) )
+{
+ // for native widget rendering we must be able to detect this window type
+ SetType( WINDOW_LISTBOXWINDOW );
+
+ mpVScrollBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
+ mpHScrollBar = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
+ mpScrollBarBox = new ScrollBarBox( this );
+
+ Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
+ mpVScrollBar->SetScrollHdl( aLink );
+ mpHScrollBar->SetScrollHdl( aLink );
+
+ mbVScroll = FALSE;
+ mbHScroll = FALSE;
+ mbAutoHScroll = ( nWinStyle & WB_AUTOHSCROLL ) ? TRUE : FALSE;
+
+ maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
+ maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
+ maLBWindow.Show();
+}
+
+// -----------------------------------------------------------------------
+
+ImplListBox::~ImplListBox()
+{
+ delete mpHScrollBar;
+ delete mpVScrollBar;
+ delete mpScrollBarBox;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::Clear()
+{
+ maLBWindow.Clear();
+ if ( GetEntryList()->GetMRUCount() )
+ {
+ maLBWindow.GetEntryList()->SetMRUCount( 0 );
+ maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
+ }
+ mpVScrollBar->SetThumbPos( 0 );
+ mpHScrollBar->SetThumbPos( 0 );
+ StateChanged( STATE_CHANGE_DATA );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBox::InsertEntry( USHORT nPos, const XubString& rStr )
+{
+ ImplEntryType* pNewEntry = new ImplEntryType( rStr );
+ USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
+ StateChanged( STATE_CHANGE_DATA );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBox::InsertEntry( USHORT nPos, const Image& rImage )
+{
+ ImplEntryType* pNewEntry = new ImplEntryType( rImage );
+ USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
+ StateChanged( STATE_CHANGE_DATA );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBox::InsertEntry( USHORT nPos, const XubString& rStr, const Image& rImage )
+{
+ ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
+ USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
+ StateChanged( STATE_CHANGE_DATA );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::RemoveEntry( USHORT nPos )
+{
+ maLBWindow.RemoveEntry( nPos );
+ StateChanged( STATE_CHANGE_DATA );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SetEntryFlags( USHORT nPos, long nFlags )
+{
+ maLBWindow.SetEntryFlags( nPos, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+long ImplListBox::GetEntryFlags( USHORT nPos ) const
+{
+ return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SelectEntry( USHORT nPos, BOOL bSelect )
+{
+ maLBWindow.SelectEntry( nPos, bSelect );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SetNoSelection()
+{
+ maLBWindow.DeselectAll();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::GetFocus()
+{
+ maLBWindow.GrabFocus();
+}
+
+// -----------------------------------------------------------------------
+
+Window* ImplListBox::GetPreferredKeyInputWindow()
+{
+ return &maLBWindow;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::Resize()
+{
+ Control::Resize();
+ ImplResizeControls();
+ ImplCheckScrollBars();
+}
+
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
+{
+ StateChanged( STATE_CHANGE_DATA );
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
+{
+ mpVScrollBar->SetThumbPos( GetTopEntry() );
+ mpHScrollBar->SetThumbPos( GetLeftIndent() );
+
+ maScrollHdl.Call( this );
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
+{
+ USHORT nPos = (USHORT) pSB->GetThumbPos();
+ if( pSB == mpVScrollBar )
+ SetTopEntry( nPos );
+ else if( pSB == mpHScrollBar )
+ SetLeftIndent( nPos );
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::ImplCheckScrollBars()
+{
+ BOOL bArrange = FALSE;
+
+ Size aOutSz = GetOutputSizePixel();
+ USHORT nEntries = GetEntryList()->GetEntryCount();
+ USHORT nMaxVisEntries = (USHORT) (aOutSz.Height() / GetEntryHeight());
+
+ // vert. ScrollBar
+ if( nEntries > nMaxVisEntries )
+ {
+ if( !mbVScroll )
+ bArrange = TRUE;
+ mbVScroll = TRUE;
+
+ // Ueberpruefung des rausgescrollten Bereichs
+ SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
+ }
+ else
+ {
+ if( mbVScroll )
+ bArrange = TRUE;
+ mbVScroll = FALSE;
+ SetTopEntry( 0 );
+ }
+
+ // horz. ScrollBar
+ if( mbAutoHScroll )
+ {
+ long nWidth = (USHORT) aOutSz.Width();
+ if ( mbVScroll )
+ nWidth -= mpVScrollBar->GetSizePixel().Width();
+
+ long nMaxWidth = GetMaxEntryWidth();
+ if( nWidth < nMaxWidth )
+ {
+ if( !mbHScroll )
+ bArrange = TRUE;
+ mbHScroll = TRUE;
+
+ if ( !mbVScroll ) // ggf. brauchen wir jetzt doch einen
+ {
+ nMaxVisEntries = (USHORT) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
+ if( nEntries > nMaxVisEntries )
+ {
+ bArrange = TRUE;
+ mbVScroll = TRUE;
+
+ // Ueberpruefung des rausgescrollten Bereichs
+ SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
+ }
+ }
+
+ // Ueberpruefung des rausgescrollten Bereichs
+ USHORT nMaxLI = (USHORT) (nMaxWidth - nWidth);
+ if ( nMaxLI < GetLeftIndent() )
+ SetLeftIndent( nMaxLI );
+ }
+ else
+ {
+ if( mbHScroll )
+ bArrange = TRUE;
+ mbHScroll = FALSE;
+ SetLeftIndent( 0 );
+ }
+ }
+
+ if( bArrange )
+ ImplResizeControls();
+
+ ImplInitScrollBars();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::ImplInitScrollBars()
+{
+ Size aOutSz = maLBWindow.GetOutputSizePixel();
+
+ if ( mbVScroll )
+ {
+ USHORT nEntries = GetEntryList()->GetEntryCount();
+ USHORT nVisEntries = (USHORT) (aOutSz.Height() / GetEntryHeight());
+ mpVScrollBar->SetRangeMax( nEntries );
+ mpVScrollBar->SetVisibleSize( nVisEntries );
+ mpVScrollBar->SetPageSize( nVisEntries - 1 );
+ }
+
+ if ( mbHScroll )
+ {
+ mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
+ mpHScrollBar->SetVisibleSize( (USHORT)aOutSz.Width() );
+ mpHScrollBar->SetLineSize( HORZ_SCROLL );
+ mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::ImplResizeControls()
+{
+ // Hier werden die Controls nur angeordnet, ob die Scrollbars
+ // sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
+
+ Size aOutSz = GetOutputSizePixel();
+ long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
+ nSBWidth = CalcZoom( nSBWidth );
+
+ Size aInnerSz( aOutSz );
+ if ( mbVScroll )
+ aInnerSz.Width() -= nSBWidth;
+ if ( mbHScroll )
+ aInnerSz.Height() -= nSBWidth;
+
+ // pb: #106948# explicit mirroring for calc
+ // Scrollbar on left or right side?
+ BOOL bMirroring = maLBWindow.IsMirroring();
+ Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
+ maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
+
+ // ScrollBarBox
+ if( mbVScroll && mbHScroll )
+ {
+ Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
+ mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
+ mpScrollBarBox->Show();
+ }
+ else
+ {
+ mpScrollBarBox->Hide();
+ }
+
+ // vert. ScrollBar
+ if( mbVScroll )
+ {
+ // Scrollbar on left or right side?
+ Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
+ mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
+ mpVScrollBar->Show();
+ }
+ else
+ {
+ mpVScrollBar->Hide();
+ // #107254# Don't reset top entry after resize, but check for max top entry
+ SetTopEntry( GetTopEntry() );
+ }
+
+ // horz. ScrollBar
+ if( mbHScroll )
+ {
+ Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
+ mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
+ mpHScrollBar->Show();
+ }
+ else
+ {
+ mpHScrollBar->Hide();
+ SetLeftIndent( 0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ ImplCheckScrollBars();
+ }
+ else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
+ {
+ BOOL bUpdate = IsUpdateMode();
+ maLBWindow.SetUpdateMode( bUpdate );
+// mpHScrollBar->SetUpdateMode( bUpdate );
+// mpVScrollBar->SetUpdateMode( bUpdate );
+ if ( bUpdate && IsReallyVisible() )
+ ImplCheckScrollBars();
+ }
+ else if( nType == STATE_CHANGE_ENABLE )
+ {
+ mpHScrollBar->Enable( IsEnabled() );
+ mpVScrollBar->Enable( IsEnabled() );
+ mpScrollBarBox->Enable( IsEnabled() );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ maLBWindow.SetZoom( GetZoom() );
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ maLBWindow.SetControlFont( GetControlFont() );
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ maLBWindow.SetControlForeground( GetControlForeground() );
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ maLBWindow.SetControlBackground( GetControlBackground() );
+ }
+ else if( nType == STATE_CHANGE_MIRRORING )
+ {
+ maLBWindow.EnableRTL( IsRTLEnabled() );
+ mpHScrollBar->EnableRTL( IsRTLEnabled() );
+ mpVScrollBar->EnableRTL( IsRTLEnabled() );
+ ImplResizeControls();
+ }
+
+ Control::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+// if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+// (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+// {
+// maLBWindow.SetSettings( GetSettings() );
+// Resize();
+// }
+// else
+ Control::DataChanged( rDCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long ImplListBox::Notify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ if ( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
+ if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
+ {
+ nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
+ }
+ }
+ }
+
+ return nDone ? nDone : Window::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+const Wallpaper& ImplListBox::GetDisplayBackground() const
+{
+ return maLBWindow.GetDisplayBackground();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
+{
+ BOOL bDone = FALSE;
+ if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
+ {
+ USHORT nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
+ KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
+ bDone = ProcessKeyInput( aKeyEvent );
+ }
+ }
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
+{
+ BOOL bChanges = GetEntryList()->GetMRUCount() ? TRUE : FALSE;
+
+ // Remove old MRU entries
+ for ( USHORT n = GetEntryList()->GetMRUCount();n; )
+ maLBWindow.RemoveEntry( --n );
+
+ USHORT nMRUCount = 0;
+ USHORT nEntries = rEntries.GetTokenCount( cSep );
+ for ( USHORT nEntry = 0; nEntry < nEntries; nEntry++ )
+ {
+ XubString aEntry = rEntries.GetToken( nEntry, cSep );
+ // Accept only existing entries
+ if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
+ {
+ ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
+ maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, FALSE );
+ bChanges = TRUE;
+ }
+ }
+
+ if ( bChanges )
+ {
+ maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
+ SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
+{
+ String aEntries;
+ for ( USHORT n = 0; n < GetEntryList()->GetMRUCount(); n++ )
+ {
+ aEntries += GetEntryList()->GetEntryText( n );
+ if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
+ aEntries += cSep;
+ }
+ return aEntries;
+}
+
+// =======================================================================
+
+ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
+ Control ( pParent, nWinStyle )
+{
+ if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
+ SetBackground();
+ else
+ SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
+
+ mbInUserDraw = FALSE;
+ mbUserDrawEnabled = FALSE;
+ mnItemPos = LISTBOX_ENTRY_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ SetImage( rImage );
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ maImageHC = rImage;
+ else
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
+{
+ if( eMode == BMP_COLOR_HIGHCONTRAST )
+ return maImageHC;
+ else
+ return maImage;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::MBDown()
+{
+ if( IsEnabled() )
+ maMBDownHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::MouseButtonDown( const MouseEvent& )
+{
+ if( IsEnabled() )
+ {
+// Control::MouseButtonDown( rMEvt );
+ MBDown();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<ImplWin*>(this)->ImplDraw( true );
+}
+
+// -----------------------------------------------------------------------
+
+long ImplWin::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
+ {
+ // trigger redraw as mouse over state has changed
+ if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
+ {
+ GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
+ GetParent()->GetWindow( WINDOW_BORDER )->Update();
+ }
+ }
+ }
+
+ return nDone ? nDone : Control::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::ImplDraw( bool bLayout )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ BOOL bNativeOK = FALSE;
+
+ if( ! bLayout )
+ {
+ ControlState nState = CTRL_STATE_ENABLED;
+ if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
+ {
+ // Repaint the (focused) area similarly to
+ // ImplSmallBorderWindowView::DrawWindow() in
+ // vcl/source/window/brdwin.cxx
+ Window *pWin = GetParent();
+
+ ImplControlValue aControlValue;
+ if ( !pWin->IsEnabled() )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( pWin->HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+
+ // The listbox is painted over the entire control including the
+ // border, but ImplWin does not contain the border => correction
+ // needed.
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ pWin->GetBorder( nLeft, nTop, nRight, nBottom );
+ Point aPoint( -nLeft, -nTop );
+ Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
+
+ BOOL bMouseOver = FALSE;
+ if( GetParent() )
+ {
+ Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
+ while( pChild && (bMouseOver = pChild->IsMouseOver()) == FALSE )
+ pChild = pChild->GetWindow( WINDOW_NEXT );
+ }
+
+ if( bMouseOver )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ // if parent has no border, then nobody has drawn the background
+ // since no border window exists. so draw it here.
+ WinBits nParentStyle = pWin->GetStyle();
+ if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
+ {
+ Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
+ pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
+ nState, aControlValue, rtl::OUString() );
+ }
+
+ bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() );
+ }
+
+ if( IsEnabled() )
+ {
+ if( HasFocus() )
+ {
+ SetTextColor( rStyleSettings.GetHighlightTextColor() );
+ SetFillColor( rStyleSettings.GetHighlightColor() );
+ DrawRect( maFocusRect );
+ }
+ else
+ {
+ Color aColor;
+ if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
+ aColor = rStyleSettings.GetFieldRolloverTextColor();
+ else
+ aColor = rStyleSettings.GetFieldTextColor();
+ if( IsControlForeground() )
+ aColor = GetControlForeground();
+ SetTextColor( aColor );
+ if ( !bNativeOK )
+ Erase( maFocusRect );
+ }
+ }
+ else // Disabled
+ {
+ SetTextColor( rStyleSettings.GetDisableColor() );
+ if ( !bNativeOK )
+ Erase( maFocusRect );
+ }
+ }
+
+ if ( IsUserDrawEnabled() )
+ {
+ mbInUserDraw = TRUE;
+ UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
+ maUserDrawHdl.Call( &aUDEvt );
+ mbInUserDraw = FALSE;
+ }
+ else
+ {
+ DrawEntry( TRUE, TRUE, FALSE, bLayout );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::Paint( const Rectangle& )
+{
+ ImplDraw();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::DrawEntry( BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos, bool bLayout )
+{
+ long nBorder = 1;
+ Size aOutSz = GetOutputSizePixel();
+
+ BOOL bImage = !!maImage;
+ if( bDrawImage && bImage && !bLayout )
+ {
+ USHORT nStyle = 0;
+ Size aImgSz = maImage.GetSizePixel();
+ Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
+
+ // check for HC mode
+ Image *pImage = &maImage;
+
+ if( !!maImageHC )
+ {
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ pImage = &maImageHC;
+ }
+
+ if ( !IsZoom() )
+ {
+ DrawImage( aPtImg, *pImage, nStyle );
+ }
+ else
+ {
+ aImgSz.Width() = CalcZoom( aImgSz.Width() );
+ aImgSz.Height() = CalcZoom( aImgSz.Height() );
+ DrawImage( aPtImg, aImgSz, *pImage, nStyle );
+ }
+ }
+
+ if( bDrawText && maString.Len() )
+ {
+ USHORT nTextStyle = TEXT_DRAW_VCENTER;
+
+ if ( bDrawImage && bImage && !bLayout )
+ nTextStyle |= TEXT_DRAW_LEFT;
+ else if ( GetStyle() & WB_CENTER )
+ nTextStyle |= TEXT_DRAW_CENTER;
+ else if ( GetStyle() & WB_RIGHT )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else
+ nTextStyle |= TEXT_DRAW_LEFT;
+
+ Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
+
+ if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
+ {
+ long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
+ aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
+ }
+
+ MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+ DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
+ }
+
+ if( HasFocus() && !bLayout )
+ ShowFocus( maFocusRect );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::Resize()
+{
+ Control::Resize();
+ maFocusRect.SetSize( GetOutputSizePixel() );
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::GetFocus()
+{
+ ShowFocus( maFocusRect );
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
+ {
+ Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
+ if( ! pWin )
+ pWin = GetParent();
+ pWin->Invalidate();
+ }
+ else
+ Invalidate();
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::LoseFocus()
+{
+ HideFocus();
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
+ {
+ Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
+ if( ! pWin )
+ pWin = GetParent();
+ pWin->Invalidate();
+ }
+ else
+ Invalidate();
+ Control::LoseFocus();
+}
+
+// =======================================================================
+
+ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
+ PushButton( pParent, nWinStyle ),
+ mbDown ( FALSE )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBtn::MBDown()
+{
+ if( IsEnabled() )
+ maMBDownHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBtn::MouseButtonDown( const MouseEvent& )
+{
+ //PushButton::MouseButtonDown( rMEvt );
+ if( IsEnabled() )
+ {
+ MBDown();
+ mbDown = TRUE;
+ }
+}
+
+// =======================================================================
+
+ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
+ FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) // no drop shadow for list boxes
+{
+ mpImplLB = NULL;
+ mnDDLineCount = 0;
+ mbAutoWidth = FALSE;
+
+ mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+
+ EnableSaveBackground();
+
+ Window * pBorderWindow = ImplGetBorderWindow();
+ if( pBorderWindow )
+ {
+ SetAccessibleRole(accessibility::AccessibleRole::PANEL);
+ pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
+ }
+ else
+ {
+ SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
+{
+ if( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if( !GetParent()->HasChildPathFocus( TRUE ) )
+ EndPopupMode();
+ }
+
+ return FloatingWindow::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
+{
+ FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+
+ // Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
+ // Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
+ if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
+ {
+ Point aPos = GetParent()->GetPosPixel();
+ aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
+
+ if ( nFlags & WINDOW_POSSIZE_X )
+ aPos.X() = nX;
+
+ if ( nFlags & WINDOW_POSSIZE_Y )
+ aPos.Y() = nY;
+
+ USHORT nIndex;
+ SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
+ }
+
+// if( !IsReallyVisible() )
+ {
+ // Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
+ // Die Fenster muessen aber ein Resize() erhalten, damit die
+ // Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
+ // Die Anzahl kann auch nicht von List/Combobox berechnet werden,
+ // weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
+ // beruecksichtigt werden muss.
+ mpImplLB->SetSizePixel( GetOutputSizePixel() );
+ ((Window*)mpImplLB)->Resize();
+ ((Window*)mpImplLB->GetMainWindow())->Resize();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxFloatingWindow::Resize()
+{
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+ FloatingWindow::Resize();
+}
+
+// -----------------------------------------------------------------------
+
+Size ImplListBoxFloatingWindow::CalcFloatSize()
+{
+ Size aFloatSz( maPrefSz );
+
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ GetBorder( nLeft, nTop, nRight, nBottom );
+
+ USHORT nLines = mpImplLB->GetEntryList()->GetEntryCount();
+ if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
+ nLines = mnDDLineCount;
+
+ Size aSz = mpImplLB->CalcSize( nLines );
+ long nMaxHeight = aSz.Height() + nTop + nBottom;
+
+ if ( mnDDLineCount )
+ aFloatSz.Height() = nMaxHeight;
+
+ if( mbAutoWidth )
+ {
+ // AutoSize erstmal nur fuer die Breite...
+
+ aFloatSz.Width() = aSz.Width() + nLeft + nRight;
+ aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
+
+ if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
+ {
+ // dann wird noch der vertikale Scrollbar benoetigt
+ long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
+ aFloatSz.Width() += nSBWidth;
+ }
+ }
+
+ if ( aFloatSz.Height() > nMaxHeight )
+ aFloatSz.Height() = nMaxHeight;
+
+ // Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
+ // Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
+ Size aParentSz = GetParent()->GetSizePixel();
+ if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
+ aFloatSz.Height() = aParentSz.Height();
+
+ // Nicht schmaler als der Parent werden...
+ if( aFloatSz.Width() < aParentSz.Width() )
+ aFloatSz.Width() = aParentSz.Width();
+
+ // Hoehe auf Entries alignen...
+ long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
+ long nEntryHeight = mpImplLB->GetEntryHeight();
+ if ( nInnerHeight % nEntryHeight )
+ {
+ nInnerHeight /= nEntryHeight;
+ nInnerHeight++;
+ nInnerHeight *= nEntryHeight;
+ aFloatSz.Height() = nInnerHeight + nTop + nBottom;
+ }
+
+ return aFloatSz;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxFloatingWindow::StartFloat( BOOL bStartTracking )
+{
+ if( !IsInPopupMode() )
+ {
+ Size aFloatSz = CalcFloatSize();
+
+ SetSizePixel( aFloatSz );
+ mpImplLB->SetSizePixel( GetOutputSizePixel() );
+
+ USHORT nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
+ mnPopupModeStartSaveSelection = nPos;
+
+ Size aSz = GetParent()->GetSizePixel();
+ Point aPos = GetParent()->GetPosPixel();
+ aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
+ // FIXME: this ugly hack is for Mac/Aqua
+ // should be replaced by a real mechanism to place the float rectangle
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ GetParent()->IsNativeWidgetEnabled() )
+ {
+ sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
+ aPos.X() += nLeft;
+ aPos.Y() += nTop;
+ aSz.Width() -= nLeft + nRight;
+ aSz.Height() -= nTop + nBottom;
+ }
+ Rectangle aRect( aPos, aSz );
+
+ // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
+ // where the document is unmirrored
+ // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
+ if( GetParent()->GetParent()->ImplIsAntiparallel() )
+ GetParent()->GetParent()->ImplReMirror( aRect );
+
+ StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
+
+ if( nPos != LISTBOX_ENTRY_NOTFOUND )
+ mpImplLB->ShowProminentEntry( nPos );
+
+ if( bStartTracking )
+ mpImplLB->GetMainWindow()->EnableMouseMoveSelect( TRUE );
+
+ if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
+ mpImplLB->GetMainWindow()->GrabFocus();
+
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+ }
+}
diff --git a/vcl/source/control/imgctrl.cxx b/vcl/source/control/imgctrl.cxx
new file mode 100644
index 000000000000..075a8b1b95e2
--- /dev/null
+++ b/vcl/source/control/imgctrl.cxx
@@ -0,0 +1,269 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/event.hxx>
+#include <vcl/imgctrl.hxx>
+
+#include <com/sun/star/awt/ImageScaleMode.hdl>
+
+namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode;
+
+// -----------------------------------------------------------------------
+
+ImageControl::ImageControl( Window* pParent, WinBits nStyle ) :
+ FixedImage( pParent, nStyle )
+{
+ mnScaleMode = ImageScaleMode::Anisotropic;
+}
+
+// -----------------------------------------------------------------------
+
+void ImageControl::SetScaleMode( const ::sal_Int16 _nMode )
+{
+ if ( _nMode != mnScaleMode )
+ {
+ mnScaleMode = _nMode;
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageControl::Resize()
+{
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+namespace
+{
+ static Size lcl_calcPaintSize( const Rectangle& _rPaintRect, const Size& _rBitmapSize )
+ {
+ const Size aPaintSize = _rPaintRect.GetSize();
+
+ const double nRatioX = 1.0 * aPaintSize.Width() / _rBitmapSize.Width();
+ const double nRatioY = 1.0 * aPaintSize.Height() / _rBitmapSize.Height();
+ const double nRatioMin = ::std::min( nRatioX, nRatioY );
+
+ return Size( long( _rBitmapSize.Width() * nRatioMin ), long( _rBitmapSize.Height() * nRatioMin ) );
+ }
+
+ static Point lcl_centerWithin( const Rectangle& _rArea, const Size& _rObjectSize )
+ {
+ Point aPos( _rArea.TopLeft() );
+ aPos.X() += ( _rArea.GetWidth() - _rObjectSize.Width() ) / 2;
+ aPos.Y() += ( _rArea.GetHeight() - _rObjectSize.Height() ) / 2;
+ return aPos;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageControl::UserDraw( const UserDrawEvent& rUDEvt )
+{
+ USHORT nStyle = 0;
+ BitmapEx* pBitmap = &maBmp;
+ if( !!maBmpHC )
+ {
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ pBitmap = &maBmpHC;
+ }
+
+ if ( !*pBitmap )
+ {
+ String sText( GetText() );
+ if ( !sText.Len() )
+ return;
+
+ WinBits nWinStyle = GetStyle();
+ USHORT nTextStyle = FixedText::ImplGetTextStyle( nWinStyle );
+ if ( !IsEnabled() )
+ nTextStyle |= TEXT_DRAW_DISABLE;
+
+ DrawText( rUDEvt.GetRect(), sText, nTextStyle );
+ return;
+ }
+
+ const Rectangle& rPaintRect = rUDEvt.GetRect();
+ const Size& rBitmapSize = maBmp.GetSizePixel();
+
+ if( nStyle & IMAGE_DRAW_COLORTRANSFORM )
+ {
+ // only images support IMAGE_DRAW_COLORTRANSFORM
+ Image aImage( *pBitmap );
+ if ( !!aImage )
+ {
+ switch ( mnScaleMode )
+ {
+ case ImageScaleMode::None:
+ {
+ rUDEvt.GetDevice()->DrawImage(
+ lcl_centerWithin( rPaintRect, rBitmapSize ), aImage, nStyle );
+ }
+ break;
+
+ case ImageScaleMode::Isotropic:
+ {
+ const Size aPaintSize = lcl_calcPaintSize( rPaintRect, rBitmapSize );
+ rUDEvt.GetDevice()->DrawImage(
+ lcl_centerWithin( rPaintRect, aPaintSize ),
+ aPaintSize,
+ aImage, nStyle );
+ }
+ break;
+
+ case ImageScaleMode::Anisotropic:
+ {
+ rUDEvt.GetDevice()->DrawImage(
+ rPaintRect.TopLeft(),
+ rPaintRect.GetSize(),
+ aImage, nStyle );
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false, "ImageControl::UserDraw: unhandled scale mode!" );
+ break;
+
+ } // switch ( mnScaleMode )
+ }
+ }
+ else
+ {
+ switch ( mnScaleMode )
+ {
+ case ImageScaleMode::None:
+ {
+ pBitmap->Draw( rUDEvt.GetDevice(), lcl_centerWithin( rPaintRect, rBitmapSize ) );
+ }
+ break;
+
+ case ImageScaleMode::Isotropic:
+ {
+ const Size aPaintSize = lcl_calcPaintSize( rPaintRect, rBitmapSize );
+ pBitmap->Draw( rUDEvt.GetDevice(),
+ lcl_centerWithin( rPaintRect, aPaintSize ),
+ aPaintSize );
+ }
+ break;
+
+ case ImageScaleMode::Anisotropic:
+ {
+ pBitmap->Draw( rUDEvt.GetDevice(),
+ rPaintRect.TopLeft(),
+ rPaintRect.GetSize() );
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false, "ImageControl::UserDraw: unhandled scale mode!" );
+ break;
+
+ } // switch ( mnScaleMode )
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageControl::SetBitmap( const BitmapEx& rBmp )
+{
+ maBmp = rBmp;
+ StateChanged( STATE_CHANGE_DATA );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImageControl::SetModeBitmap( const BitmapEx& rBitmap, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ SetBitmap( rBitmap );
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ {
+ maBmpHC = rBitmap;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+ else
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+const BitmapEx& ImageControl::GetModeBitmap( BmpColorMode eMode ) const
+{
+ if( eMode == BMP_COLOR_HIGHCONTRAST )
+ return maBmpHC;
+ else
+ return maBmp;
+}
+
+// -----------------------------------------------------------------------
+
+void ImageControl::Paint( const Rectangle& rRect )
+{
+ FixedImage::Paint( rRect );
+ if( HasFocus() )
+ {
+ Window *pWin = GetWindow( WINDOW_BORDER );
+
+ BOOL bFlat = (GetBorderStyle() == 2);
+ Rectangle aRect( Point(0,0), pWin->GetOutputSizePixel() );
+ Color oldLineCol = pWin->GetLineColor();
+ Color oldFillCol = pWin->GetFillColor();
+ pWin->SetFillColor();
+ pWin->SetLineColor( bFlat ? COL_WHITE : COL_BLACK );
+ pWin->DrawRect( aRect );
+ aRect.nLeft++;
+ aRect.nRight--;
+ aRect.nTop++;
+ aRect.nBottom--;
+ pWin->SetLineColor( bFlat ? COL_BLACK : COL_WHITE );
+ pWin->DrawRect( aRect );
+ pWin->SetLineColor( oldLineCol );
+ pWin->SetFillColor( oldFillCol );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageControl::GetFocus()
+{
+ FixedImage::GetFocus();
+ GetWindow( WINDOW_BORDER )->Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void ImageControl::LoseFocus()
+{
+ FixedImage::GetFocus();
+ GetWindow( WINDOW_BORDER )->Invalidate();
+}
+
diff --git a/vcl/source/control/longcurr.cxx b/vcl/source/control/longcurr.cxx
new file mode 100644
index 000000000000..65fe11929d1e
--- /dev/null
+++ b/vcl/source/control/longcurr.cxx
@@ -0,0 +1,859 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <sot/object.hxx>
+#define _TOOLS_BIGINT
+#include <sot/factory.hxx>
+#include <tools/debug.hxx>
+#include <tools/bigint.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/longcurr.hxx>
+
+
+#include <unotools/localedatawrapper.hxx>
+
+
+// =======================================================================
+
+#define FORMAT_LONGCURRENCY 4
+
+// =======================================================================
+
+static BigInt ImplPower10( USHORT n )
+{
+ USHORT i;
+ BigInt nValue = 1;
+
+ for ( i=0; i < n; i++ )
+ nValue *= 10;
+
+ return nValue;
+}
+
+// -----------------------------------------------------------------------
+
+static XubString ImplGetCurr( const LocaleDataWrapper& rLocaleDataWrapper, const BigInt &rNumber, USHORT nDigits, const String& rCurrSymbol, BOOL bShowThousandSep )
+{
+ DBG_ASSERT( nDigits < 10, "LongCurrency duerfen nur maximal 9 Nachkommastellen haben" );
+
+ if ( rNumber.IsZero() || (long)rNumber )
+ return rLocaleDataWrapper.getCurr( (long)rNumber, nDigits, rCurrSymbol, bShowThousandSep );
+
+ BigInt aTmp( ImplPower10( nDigits ) );
+ BigInt aInteger( rNumber );
+ aInteger.Abs();
+ aInteger /= aTmp;
+ BigInt aFraction( rNumber );
+ aFraction.Abs();
+ aFraction %= aTmp;
+ if ( !aInteger.IsZero() )
+ {
+ aFraction += aTmp;
+ aTmp = 1000000000L;
+ }
+ if ( rNumber.IsNeg() )
+ aFraction *= -1;
+
+ XubString aTemplate = rLocaleDataWrapper.getCurr( (long)aFraction, nDigits, rCurrSymbol, bShowThousandSep );
+ while( !aInteger.IsZero() )
+ {
+ aFraction = aInteger;
+ aFraction %= aTmp;
+ aInteger /= aTmp;
+ if( !aInteger.IsZero() )
+ aFraction += aTmp;
+
+ XubString aFractionStr = rLocaleDataWrapper.getNum( (long)aFraction, 0 );
+
+ xub_StrLen nSPos = aTemplate.Search( '1' );
+ if ( aFractionStr.Len() == 1 )
+ aTemplate.SetChar( nSPos, aFractionStr.GetChar( 0 ) );
+ else
+ {
+ aTemplate.Erase( nSPos, 1 );
+ aTemplate.Insert( aFractionStr, nSPos );
+ }
+ }
+
+ return aTemplate;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplNumericProcessKeyInput( Edit*, const KeyEvent& rKEvt,
+ BOOL bStrictFormat, BOOL bThousandSep,
+ const LocaleDataWrapper& rLocaleDataWrapper )
+{
+ if ( !bStrictFormat )
+ return FALSE;
+ else
+ {
+ sal_Unicode cChar = rKEvt.GetCharCode();
+ USHORT nGroup = rKEvt.GetKeyCode().GetGroup();
+
+ if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
+ (nGroup == KEYGROUP_MISC) ||
+ ((cChar >= '0') && (cChar <= '9')) ||
+ (bThousandSep && (cChar == rLocaleDataWrapper.getNumThousandSep())) ||
+ (cChar == rLocaleDataWrapper.getNumDecimalSep() ) ||
+ (cChar == '-') )
+ return FALSE;
+ else
+ return TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplNumericGetValue( const XubString& rStr, BigInt& rValue,
+ USHORT nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper,
+ BOOL bCurrency = FALSE )
+{
+ XubString aStr = rStr;
+ XubString aStr1;
+ XubString aStr2;
+ USHORT nDecPos;
+ BOOL bNegative = FALSE;
+ xub_StrLen i;
+
+ // Reaktion auf leeren String
+ if ( !rStr.Len() )
+ return FALSE;
+
+ // Fuehrende und nachfolgende Leerzeichen entfernen
+ aStr.EraseLeadingAndTrailingChars( ' ' );
+
+ // Position des Dezimalpunktes suchen
+ nDecPos = aStr.Search( rLocaleDataWrapper.getNumDecimalSep() );
+
+ if ( nDecPos != STRING_NOTFOUND )
+ {
+ aStr1 = aStr.Copy( 0, nDecPos );
+ aStr2 = aStr.Copy( nDecPos+1 );
+ }
+ else
+ aStr1 = aStr;
+
+ // Negativ ?
+ if ( bCurrency )
+ {
+ if ( (aStr.GetChar( 0 ) == '(') && (aStr.GetChar( aStr.Len()-1 ) == ')') )
+ bNegative = TRUE;
+ if ( !bNegative )
+ {
+ for ( i=0; i < aStr.Len(); i++ )
+ {
+ if ( (aStr.GetChar( i ) >= '0') && (aStr.GetChar( i ) <= '9') )
+ break;
+ else if ( aStr.GetChar( i ) == '-' )
+ {
+ bNegative = TRUE;
+ break;
+ }
+ }
+ }
+ if ( !bNegative && bCurrency && aStr.Len() )
+ {
+ USHORT nFormat = rLocaleDataWrapper.getCurrNegativeFormat();
+ if ( (nFormat == 3) || (nFormat == 6) ||
+ (nFormat == 7) || (nFormat == 10) )
+ {
+ for ( i = (USHORT)(aStr.Len()-1); i > 0; i++ )
+ {
+ if ( (aStr.GetChar( i ) >= '0') && (aStr.GetChar( i ) <= '9') )
+ break;
+ else if ( aStr.GetChar( i ) == '-' )
+ {
+ bNegative = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( aStr1.GetChar( 0 ) == '-' )
+ bNegative = TRUE;
+ }
+
+ // Alle unerwuenschten Zeichen rauswerfen
+ for ( i=0; i < aStr1.Len(); )
+ {
+ if ( (aStr1.GetChar( i ) >= '0') && (aStr1.GetChar( i ) <= '9') )
+ i++;
+ else
+ aStr1.Erase( i, 1 );
+ }
+ for ( i=0; i < aStr2.Len(); )
+ {
+ if ( (aStr2.GetChar( i ) >= '0') && (aStr2.GetChar( i ) <= '9') )
+ i++;
+ else
+ aStr2.Erase( i, 1 );
+ }
+
+ if ( !aStr1.Len() && !aStr2.Len() )
+ return FALSE;
+
+ if ( !aStr1.Len() )
+ aStr1.Insert( '0' );
+ if ( bNegative )
+ aStr1.Insert( '-', 0 );
+
+ // Nachkommateil zurechtstutzen und dabei runden
+ BOOL bRound = FALSE;
+ if ( aStr2.Len() > nDecDigits )
+ {
+ if ( aStr2.GetChar( nDecDigits ) >= '5' )
+ bRound = TRUE;
+ aStr2.Erase( nDecDigits );
+ }
+ if ( aStr2.Len() < nDecDigits )
+ aStr2.Expand( nDecDigits, '0' );
+
+ aStr = aStr1;
+ aStr += aStr2;
+
+ // Bereichsueberpruefung
+ BigInt nValue( aStr );
+ if ( bRound )
+ {
+ if ( !bNegative )
+ nValue+=1;
+ else
+ nValue-=1;
+ }
+
+ rValue = nValue;
+
+ return TRUE;
+}
+
+// =======================================================================
+
+static BOOL ImplLongCurrencyProcessKeyInput( Edit* pEdit, const KeyEvent& rKEvt,
+ BOOL, BOOL bUseThousandSep, const LocaleDataWrapper& rLocaleDataWrapper )
+{
+ // Es gibt hier kein sinnvolles StrictFormat, also alle
+ // Zeichen erlauben
+ return ImplNumericProcessKeyInput( pEdit, rKEvt, FALSE, bUseThousandSep, rLocaleDataWrapper );
+}
+
+// -----------------------------------------------------------------------
+
+inline BOOL ImplLongCurrencyGetValue( const XubString& rStr, BigInt& rValue,
+ USHORT nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper )
+{
+ // Zahlenwert holen
+ return ImplNumericGetValue( rStr, rValue, nDecDigits, rLocaleDataWrapper, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplLongCurrencyReformat( const XubString& rStr, BigInt nMin, BigInt nMax,
+ USHORT nDecDigits,
+ const LocaleDataWrapper& rLocaleDataWrapper, String& rOutStr,
+ LongCurrencyFormatter& rFormatter )
+{
+ BigInt nValue;
+ if ( !ImplNumericGetValue( rStr, nValue, nDecDigits, rLocaleDataWrapper, TRUE ) )
+ return TRUE;
+ else
+ {
+ BigInt nTempVal = nValue;
+ if ( nTempVal > nMax )
+ nTempVal = nMax;
+ else if ( nTempVal < nMin )
+ nTempVal = nMin;
+
+ if ( rFormatter.GetErrorHdl().IsSet() && (nValue != nTempVal) )
+ {
+ rFormatter.mnCorrectedValue = nTempVal;
+ if ( !rFormatter.GetErrorHdl().Call( &rFormatter ) )
+ {
+ rFormatter.mnCorrectedValue = 0;
+ return FALSE;
+ }
+ else
+ {
+ rFormatter.mnCorrectedValue = 0;
+ }
+ }
+
+ rOutStr = ImplGetCurr( rLocaleDataWrapper, nTempVal, nDecDigits, rFormatter.GetCurrencySymbol(), rFormatter.IsUseThousandSep() );
+ return TRUE;
+ }
+}
+
+
+// =======================================================================
+
+void LongCurrencyFormatter::ImpInit()
+{
+ mnFieldValue = 0;
+ mnLastValue = 0;
+ mnMin = 0;
+ mnMax = 0x7FFFFFFF;
+ mnMax *= 0x7FFFFFFF;
+ mnCorrectedValue = 0;
+ mnDecimalDigits = 0;
+ mnType = FORMAT_LONGCURRENCY;
+ mbThousandSep = TRUE;
+ SetDecimalDigits( 0 );
+}
+
+// -----------------------------------------------------------------------
+
+LongCurrencyFormatter::LongCurrencyFormatter()
+{
+ ImpInit();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::ImplLoadRes( const ResId& rResId )
+{
+ ImpInit();
+
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( pMgr )
+ {
+ ULONG nMask = pMgr->ReadLong();
+
+ if ( NUMERICFORMATTER_MIN & nMask )
+ mnMin = pMgr->ReadLong();
+
+ if ( NUMERICFORMATTER_MAX & nMask )
+ mnMax = pMgr->ReadLong();
+
+ if ( NUMERICFORMATTER_STRICTFORMAT & nMask )
+ SetStrictFormat( (BOOL)pMgr->ReadShort() );
+
+ if ( NUMERICFORMATTER_DECIMALDIGITS & nMask )
+ SetDecimalDigits( pMgr->ReadShort() );
+
+ if ( NUMERICFORMATTER_VALUE & nMask )
+ {
+ mnFieldValue = pMgr->ReadLong();
+ if ( mnFieldValue > mnMax )
+ mnFieldValue = mnMax;
+ else if ( mnFieldValue < mnMin )
+ mnFieldValue = mnMin;
+ mnLastValue = mnFieldValue;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+LongCurrencyFormatter::~LongCurrencyFormatter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetCurrencySymbol( const String& rStr )
+{
+ maCurrencySymbol= rStr;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+String LongCurrencyFormatter::GetCurrencySymbol() const
+{
+ return maCurrencySymbol.Len() ? maCurrencySymbol : GetLocaleDataWrapper().getCurrSymbol();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetValue( BigInt nNewValue )
+{
+ SetUserValue( nNewValue );
+ mnFieldValue = mnLastValue;
+ SetEmptyFieldValueData( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetUserValue( BigInt nNewValue )
+{
+ if ( nNewValue > mnMax )
+ nNewValue = mnMax;
+ else if ( nNewValue < mnMin )
+ nNewValue = mnMin;
+ mnLastValue = nNewValue;
+
+ if ( !GetField() )
+ return;
+
+ XubString aStr = ImplGetCurr( GetLocaleDataWrapper(), nNewValue, GetDecimalDigits(), GetCurrencySymbol(), IsUseThousandSep() );
+ if ( GetField()->HasFocus() )
+ {
+ Selection aSelection = GetField()->GetSelection();
+ GetField()->SetText( aStr );
+ GetField()->SetSelection( aSelection );
+ }
+ else
+ GetField()->SetText( aStr );
+ MarkToBeReformatted( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+BigInt LongCurrencyFormatter::GetValue() const
+{
+ if ( !GetField() )
+ return 0;
+
+ BigInt nTempValue;
+ if ( ImplLongCurrencyGetValue( GetField()->GetText(), nTempValue, GetDecimalDigits(), GetLocaleDataWrapper() ) )
+ {
+ if ( nTempValue > mnMax )
+ nTempValue = mnMax;
+ else if ( nTempValue < mnMin )
+ nTempValue = mnMin;
+ return nTempValue;
+ }
+ else
+ return mnLastValue;
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::Reformat()
+{
+ if ( !GetField() )
+ return;
+
+ if ( !GetField()->GetText().Len() && ImplGetEmptyFieldValue() )
+ return;
+
+ XubString aStr;
+ BOOL bOK = ImplLongCurrencyReformat( GetField()->GetText(), mnMin, mnMax,
+ GetDecimalDigits(), GetLocaleDataWrapper(), aStr, *this );
+ if ( !bOK )
+ return;
+
+ if ( aStr.Len() )
+ {
+ GetField()->SetText( aStr );
+ MarkToBeReformatted( FALSE );
+ ImplLongCurrencyGetValue( aStr, mnLastValue, GetDecimalDigits(), GetLocaleDataWrapper() );
+ }
+ else
+ SetValue( mnLastValue );
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::ReformatAll()
+{
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetMin( BigInt nNewMin )
+{
+ mnMin = nNewMin;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetMax( BigInt nNewMax )
+{
+ mnMax = nNewMax;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetUseThousandSep( BOOL b )
+{
+ mbThousandSep = b;
+ ReformatAll();
+}
+
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetDecimalDigits( USHORT nDigits )
+{
+// DBG_ASSERT( nDigits < 10, "LongCurrency duerfen nur maximal 9 Nachkommastellen haben" );
+
+ if ( nDigits > 9 )
+ nDigits = 9;
+
+ mnDecimalDigits = nDigits;
+ ReformatAll();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT LongCurrencyFormatter::GetDecimalDigits() const
+{
+ return mnDecimalDigits;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL LongCurrencyFormatter::IsValueModified() const
+{
+ if ( ImplGetEmptyFieldValue() )
+ return !IsEmptyValue();
+ else if ( GetValue() != mnFieldValue )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyFormatter::SetEmptyValue()
+{
+ GetField()->SetText( ImplGetSVEmptyStr() );
+ SetEmptyFieldValueData( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+BigInt LongCurrencyFormatter::Normalize( BigInt nValue ) const
+{
+ return (nValue * ImplPower10( GetDecimalDigits() ) );
+}
+
+// -----------------------------------------------------------------------
+
+BigInt LongCurrencyFormatter::Denormalize( BigInt nValue ) const
+{
+ BigInt nFactor = ImplPower10( GetDecimalDigits() );
+ BigInt nTmp = nFactor;
+ nTmp /= 2;
+ nTmp += nValue;
+ nTmp /= nFactor;
+ return nTmp;
+}
+
+// =======================================================================
+
+void ImplNewLongCurrencyFieldValue( LongCurrencyField* pField, BigInt nNewValue )
+{
+ Selection aSelect = pField->GetSelection();
+ aSelect.Justify();
+ XubString aText = pField->GetText();
+ BOOL bLastSelected = ((xub_StrLen)aSelect.Max() == aText.Len()) ? TRUE : FALSE;
+
+ BigInt nOldLastValue = pField->mnLastValue;
+ pField->SetUserValue( nNewValue );
+ pField->mnLastValue = nOldLastValue;
+
+ if ( bLastSelected )
+ {
+ if ( !aSelect.Len() )
+ aSelect.Min() = SELECTION_MAX;
+ aSelect.Max() = SELECTION_MAX;
+ }
+ pField->SetSelection( aSelect );
+ pField->SetModifyFlag();
+ pField->Modify();
+}
+
+// =======================================================================
+
+LongCurrencyField::LongCurrencyField( Window* pParent, WinBits nWinStyle ) :
+ SpinField( pParent, nWinStyle )
+{
+ SetField( this );
+ mnSpinSize = 1;
+ mnFirst = mnMin;
+ mnLast = mnMax;
+
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+LongCurrencyField::LongCurrencyField( Window* pParent, const ResId& rResId ) :
+ SpinField( WINDOW_NUMERICFIELD )
+{
+ rResId.SetRT( RSC_NUMERICFIELD );
+ WinBits nStyle = ImplInitRes( rResId ) ;
+ SpinField::ImplInit( pParent, nStyle );
+
+ SetField( this );
+ mnSpinSize = 1;
+ mnFirst = mnMin;
+ mnLast = mnMax;
+
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyField::ImplLoadRes( const ResId& rResId )
+{
+ SpinField::ImplLoadRes( rResId );
+ LongCurrencyFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+
+ ULONG nMask = ReadLongRes();
+ if ( CURRENCYFIELD_FIRST & nMask )
+ mnFirst = ReadLongRes();
+
+ if ( CURRENCYFIELD_LAST & nMask )
+ mnLast = ReadLongRes();
+
+ if ( CURRENCYFIELD_SPINSIZE & nMask )
+ mnSpinSize = ReadLongRes();
+}
+
+// -----------------------------------------------------------------------
+
+LongCurrencyField::~LongCurrencyField()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long LongCurrencyField::PreNotify( NotifyEvent& rNEvt )
+{
+ if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ if ( ImplLongCurrencyProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), GetLocaleDataWrapper() ) )
+ return 1;
+ }
+ return SpinField::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long LongCurrencyField::Notify( NotifyEvent& rNEvt )
+{
+ if( rNEvt.GetType() == EVENT_GETFOCUS )
+ {
+ MarkToBeReformatted( FALSE );
+ }
+ else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() )
+ {
+ Reformat();
+ SpinField::Modify();
+ }
+ }
+ return SpinField::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyField::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ SpinField::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyField::Up()
+{
+ BigInt nValue = GetValue();
+ nValue += mnSpinSize;
+ if ( nValue > mnMax )
+ nValue = mnMax;
+
+ ImplNewLongCurrencyFieldValue( this, nValue );
+ SpinField::Up();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyField::Down()
+{
+ BigInt nValue = GetValue();
+ nValue -= mnSpinSize;
+ if ( nValue < mnMin )
+ nValue = mnMin;
+
+ ImplNewLongCurrencyFieldValue( this, nValue );
+ SpinField::Down();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyField::First()
+{
+ ImplNewLongCurrencyFieldValue( this, mnFirst );
+ SpinField::First();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyField::Last()
+{
+ ImplNewLongCurrencyFieldValue( this, mnLast );
+ SpinField::Last();
+}
+
+// =======================================================================
+
+LongCurrencyBox::LongCurrencyBox( Window* pParent, WinBits nWinStyle ) :
+ ComboBox( pParent, nWinStyle )
+{
+ SetField( this );
+ Reformat();
+}
+
+// -----------------------------------------------------------------------
+
+LongCurrencyBox::LongCurrencyBox( Window* pParent, const ResId& rResId ) :
+ ComboBox( WINDOW_NUMERICFIELD )
+{
+ SetField( this );
+ WinBits nStyle = ImplInitRes( rResId ) ;
+ ComboBox::ImplLoadRes( rResId );
+ ImplInit( pParent, nStyle );
+ LongCurrencyFormatter::ImplLoadRes( rResId );
+ Reformat();
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+LongCurrencyBox::~LongCurrencyBox()
+{
+}
+
+// -----------------------------------------------------------------------
+
+long LongCurrencyBox::PreNotify( NotifyEvent& rNEvt )
+{
+ if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ if ( ImplLongCurrencyProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), GetLocaleDataWrapper() ) )
+ return 1;
+ }
+ return ComboBox::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long LongCurrencyBox::Notify( NotifyEvent& rNEvt )
+{
+ if( rNEvt.GetType() == EVENT_GETFOCUS )
+ {
+ MarkToBeReformatted( FALSE );
+ }
+ else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( MustBeReformatted() )
+ {
+ Reformat();
+ ComboBox::Modify();
+ }
+ }
+ return ComboBox::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyBox::Modify()
+{
+ MarkToBeReformatted( TRUE );
+ ComboBox::Modify();
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyBox::ReformatAll()
+{
+ XubString aStr;
+ SetUpdateMode( FALSE );
+ USHORT nEntryCount = GetEntryCount();
+ for ( USHORT i=0; i < nEntryCount; i++ )
+ {
+ ImplLongCurrencyReformat( GetEntry( i ), mnMin, mnMax,
+ GetDecimalDigits(), GetLocaleDataWrapper(),
+ aStr, *this );
+ RemoveEntry( i );
+ InsertEntry( aStr, i );
+ }
+ LongCurrencyFormatter::Reformat();
+ SetUpdateMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyBox::InsertValue( BigInt nValue, USHORT nPos )
+{
+ XubString aStr = ImplGetCurr( GetLocaleDataWrapper(), nValue, GetDecimalDigits(), GetCurrencySymbol(), IsUseThousandSep() );
+ ComboBox::InsertEntry( aStr, nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void LongCurrencyBox::RemoveValue( BigInt nValue )
+{
+ XubString aStr = ImplGetCurr( GetLocaleDataWrapper(), nValue, GetDecimalDigits(), GetCurrencySymbol(), IsUseThousandSep() );
+ ComboBox::RemoveEntry( aStr );
+}
+
+// -----------------------------------------------------------------------
+
+BigInt LongCurrencyBox::GetValue( USHORT nPos ) const
+{
+ BigInt nValue = 0;
+ ImplLongCurrencyGetValue( ComboBox::GetEntry( nPos ), nValue,
+ GetDecimalDigits(), GetLocaleDataWrapper() );
+ return nValue;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT LongCurrencyBox::GetValuePos( BigInt nValue ) const
+{
+ XubString aStr = ImplGetCurr( GetLocaleDataWrapper(), nValue, GetDecimalDigits(), GetCurrencySymbol(), IsUseThousandSep() );
+ return ComboBox::GetEntryPos( aStr );
+}
+
+// =======================================================================
diff --git a/vcl/source/control/lstbox.cxx b/vcl/source/control/lstbox.cxx
new file mode 100644
index 000000000000..03527bf083a7
--- /dev/null
+++ b/vcl/source/control/lstbox.cxx
@@ -0,0 +1,1644 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "tools/rc.h"
+
+#include "vcl/svdata.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/event.hxx"
+#include "vcl/scrbar.hxx"
+#include "vcl/button.hxx"
+#include "vcl/edit.hxx"
+#include "vcl/subedit.hxx"
+#include "vcl/ilstbox.hxx"
+#include "vcl/lstbox.hxx"
+#include "vcl/combobox.hxx"
+#include "vcl/controldata.hxx"
+
+#include "tools/debug.hxx"
+
+#include <vcl/dndevdis.hxx>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+
+// =======================================================================
+
+ListBox::ListBox( WindowType nType ) : Control( nType )
+{
+ ImplInitListBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+ListBox::ListBox( Window* pParent, WinBits nStyle ) : Control( WINDOW_LISTBOX )
+{
+ ImplInitListBoxData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ListBox::ListBox( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_LISTBOX )
+{
+ ImplInitListBoxData();
+ rResId.SetRT( RSC_LISTBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+ListBox::~ListBox()
+{
+ //#109201#
+ ImplCallEventListeners( VCLEVENT_OBJECT_DYING );
+
+ delete mpImplLB;
+
+ // Beim zerstoeren des FloatWins macht TH ein GrabFocus auf den Parent,
+ // also diese ListBox => PreNotify()...
+ mpImplLB = NULL;
+
+ delete mpFloatWin;
+ delete mpImplWin;
+ delete mpBtn;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::ImplInitListBoxData()
+{
+ mpFloatWin = NULL;
+ mpImplWin = NULL;
+ mpBtn = NULL;
+
+ mnDDHeight = 0;
+ mbDDAutoSize = TRUE;
+ mnSaveValue = LISTBOX_ENTRY_NOTFOUND;
+ mnLineCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::ImplInit( Window* pParent, WinBits nStyle )
+{
+ nStyle = ImplInitStyle( nStyle );
+ if ( !(nStyle & WB_NOBORDER) && ( nStyle & WB_DROPDOWN ) )
+ nStyle |= WB_BORDER;
+
+ Control::ImplInit( pParent, nStyle, NULL );
+ SetBackground();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener> xDrop = new DNDEventDispatcher(this);
+
+ if( nStyle & WB_DROPDOWN )
+ {
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ GetBorder( nLeft, nTop, nRight, nBottom );
+ mnDDHeight = (USHORT)(GetTextHeight() + nTop + nBottom + 4);
+
+ if( IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aControlValue;
+ Rectangle aCtrlRegion( Point( 0, 0 ), Size( 20, mnDDHeight ) );
+ Rectangle aBoundingRgn( aCtrlRegion );
+ Rectangle aContentRgn( aCtrlRegion );
+ if( GetNativeControlRegion( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ sal_Int32 nHeight = aBoundingRgn.GetHeight();
+ if( nHeight > mnDDHeight )
+ mnDDHeight = static_cast<USHORT>(nHeight);
+ }
+ }
+
+ mpFloatWin = new ImplListBoxFloatingWindow( this );
+ mpFloatWin->SetAutoWidth( TRUE );
+ mpFloatWin->SetPopupModeEndHdl( LINK( this, ListBox, ImplPopupModeEndHdl ) );
+ mpFloatWin->GetDropTarget()->addDropTargetListener(xDrop);
+
+ mpImplWin = new ImplWin( this, (nStyle & (WB_LEFT|WB_RIGHT|WB_CENTER))|WB_NOBORDER );
+ mpImplWin->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
+ mpImplWin->SetUserDrawHdl( LINK( this, ListBox, ImplUserDrawHdl ) );
+ mpImplWin->Show();
+ mpImplWin->GetDropTarget()->addDropTargetListener(xDrop);
+
+ mpBtn = new ImplBtn( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
+ ImplInitDropDownButton( mpBtn );
+ mpBtn->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
+ mpBtn->Show();
+ mpBtn->GetDropTarget()->addDropTargetListener(xDrop);
+
+ }
+
+ Window* pLBParent = this;
+ if ( mpFloatWin )
+ pLBParent = mpFloatWin;
+ mpImplLB = new ImplListBox( pLBParent, nStyle&(~WB_BORDER) );
+ mpImplLB->SetSelectHdl( LINK( this, ListBox, ImplSelectHdl ) );
+ mpImplLB->SetScrollHdl( LINK( this, ListBox, ImplScrollHdl ) );
+ mpImplLB->SetCancelHdl( LINK( this, ListBox, ImplCancelHdl ) );
+ mpImplLB->SetDoubleClickHdl( LINK( this, ListBox, ImplDoubleClickHdl ) );
+ mpImplLB->SetUserDrawHdl( LINK( this, ListBox, ImplUserDrawHdl ) );
+ mpImplLB->SetPosPixel( Point() );
+ mpImplLB->Show();
+
+ mpImplLB->GetDropTarget()->addDropTargetListener(xDrop);
+ mpImplLB->SetDropTraget(xDrop);
+
+ if ( mpFloatWin )
+ {
+ mpFloatWin->SetImplListBox( mpImplLB );
+ mpImplLB->SetSelectionChangedHdl( LINK( this, ListBox, ImplSelectionChangedHdl ) );
+ }
+ else
+ mpImplLB->GetMainWindow()->AllowGrabFocus( TRUE );
+
+ SetCompoundControl( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+WinBits ListBox::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ USHORT nSelPos = ReadShortRes();
+ USHORT nNumber = sal::static_int_cast<USHORT>(ReadLongRes());
+
+ for( USHORT i = 0; i < nNumber; i++ )
+ {
+ USHORT nPos = InsertEntry( ReadStringRes(), LISTBOX_APPEND );
+
+ long nId = ReadLongRes();
+ if( nId )
+ SetEntryData( nPos, (void *)nId ); // ID als UserData
+ }
+
+ if( nSelPos < nNumber )
+ SelectEntryPos( nSelPos );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplSelectHdl, void*, EMPTYARG )
+{
+ BOOL bPopup = IsInDropDown();
+ if( IsDropDownBox() )
+ {
+ if( !mpImplLB->IsTravelSelect() )
+ {
+ mpFloatWin->EndPopupMode();
+ mpImplWin->GrabFocus();
+ }
+
+ mpImplWin->SetItemPos( GetSelectEntryPos() );
+ mpImplWin->SetString( GetSelectEntry() );
+ if( mpImplLB->GetEntryList()->HasImages() )
+ {
+ Image aImage = mpImplLB->GetEntryList()->GetEntryImage( GetSelectEntryPos() );
+ mpImplWin->SetImage( aImage );
+ }
+ mpImplWin->Invalidate();
+ }
+
+ if ( ( !IsTravelSelect() || mpImplLB->IsSelectionChanged() ) || ( bPopup && !IsMultiSelectionEnabled() ) )
+ Select();
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplScrollHdl, void*, EMPTYARG )
+{
+ ImplCallEventListeners( VCLEVENT_LISTBOX_SCROLLED );
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplCancelHdl, void*, EMPTYARG )
+{
+ if( IsInDropDown() )
+ mpFloatWin->EndPopupMode();
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplSelectionChangedHdl, void*, n )
+{
+ if ( !mpImplLB->IsTrackingSelect() )
+ {
+ USHORT nChanged = (USHORT)(ULONG)n;
+ const ImplEntryList* pEntryList = mpImplLB->GetEntryList();
+ if ( pEntryList->IsEntryPosSelected( nChanged ) )
+ {
+ // Sollte mal ein ImplPaintEntry werden...
+ if ( nChanged < pEntryList->GetMRUCount() )
+ nChanged = pEntryList->FindEntry( pEntryList->GetEntryText( nChanged ) );
+ mpImplWin->SetItemPos( nChanged );
+ mpImplWin->SetString( mpImplLB->GetEntryList()->GetEntryText( nChanged ) );
+ if( mpImplLB->GetEntryList()->HasImages() )
+ {
+ Image aImage = mpImplLB->GetEntryList()->GetEntryImage( nChanged );
+ mpImplWin->SetImage( aImage );
+ }
+ mpImplWin->Invalidate();
+ }
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplDoubleClickHdl, void*, EMPTYARG )
+{
+ DoubleClick();
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplClickBtnHdl, void*, EMPTYARG )
+{
+ if( !mpFloatWin->IsInPopupMode() )
+ {
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
+ mpImplWin->GrabFocus();
+ mpBtn->SetPressed( TRUE );
+ mpFloatWin->StartFloat( TRUE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
+
+ ImplClearLayoutData();
+ if( mpImplLB )
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+ if( mpImplWin )
+ mpImplWin->ImplClearLayoutData();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplPopupModeEndHdl, void*, EMPTYARG )
+{
+ if( mpFloatWin->IsPopupModeCanceled() )
+ {
+ if ( ( mpFloatWin->GetPopupModeStartSaveSelection() != LISTBOX_ENTRY_NOTFOUND )
+ && !IsEntryPosSelected( mpFloatWin->GetPopupModeStartSaveSelection() ) )
+ {
+ mpImplLB->SelectEntry( mpFloatWin->GetPopupModeStartSaveSelection(), TRUE );
+ BOOL bTravelSelect = mpImplLB->IsTravelSelect();
+ mpImplLB->SetTravelSelect( TRUE );
+
+ ImplDelData aCheckDelete;
+ ImplAddDel( &aCheckDelete );
+ Select();
+ if ( aCheckDelete.IsDelete() )
+ return 0;
+ ImplRemoveDel( &aCheckDelete );
+
+ mpImplLB->SetTravelSelect( bTravelSelect );
+ }
+ }
+
+ ImplClearLayoutData();
+ if( mpImplLB )
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+ if( mpImplWin )
+ mpImplWin->ImplClearLayoutData();
+
+ mpBtn->SetPressed( FALSE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_CLOSE );
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::ToggleDropDown()
+{
+ if( IsDropDownBox() )
+ {
+ if( mpFloatWin->IsInPopupMode() )
+ mpFloatWin->EndPopupMode();
+ else
+ {
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
+ mpImplWin->GrabFocus();
+ mpBtn->SetPressed( TRUE );
+ mpFloatWin->StartFloat( TRUE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ mpImplLB->GetMainWindow()->ImplInitSettings( TRUE, TRUE, TRUE );
+
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Font aFont = mpImplLB->GetMainWindow()->GetDrawPixelFont( pDev );
+ OutDevType eOutDevType = pDev->GetOutDevType();
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ pDev->SetTextFillColor();
+
+ // Border/Background
+ pDev->SetLineColor();
+ pDev->SetFillColor();
+ BOOL bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
+ BOOL bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
+ if ( bBorder || bBackground )
+ {
+ Rectangle aRect( aPos, aSize );
+ if ( bBorder )
+ {
+ ImplDrawFrame( pDev, aRect );
+ }
+ if ( bBackground )
+ {
+ pDev->SetFillColor( GetControlBackground() );
+ pDev->DrawRect( aRect );
+ }
+ }
+
+ // Inhalt
+ if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
+ {
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ }
+ else
+ {
+ if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ pDev->SetTextColor( rStyleSettings.GetDisableColor() );
+ }
+ else
+ {
+ pDev->SetTextColor( GetTextColor() );
+ }
+ }
+
+ long nOnePixel = GetDrawPixel( pDev, 1 );
+ USHORT nTextStyle = TEXT_DRAW_VCENTER;
+ Rectangle aTextRect( aPos, aSize );
+
+ if ( GetStyle() & WB_CENTER )
+ nTextStyle |= TEXT_DRAW_CENTER;
+ else if ( GetStyle() & WB_RIGHT )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else
+ nTextStyle |= TEXT_DRAW_LEFT;
+
+ aTextRect.Left() += 3*nOnePixel;
+ aTextRect.Right() -= 3*nOnePixel;
+
+ if ( IsDropDownBox() )
+ {
+ XubString aText = GetSelectEntry();
+ long nTextHeight = pDev->GetTextHeight();
+ long nTextWidth = pDev->GetTextWidth( aText );
+ long nOffX = 3*nOnePixel;
+ long nOffY = (aSize.Height()-nTextHeight) / 2;
+
+ // Clipping?
+ if ( (nOffY < 0) ||
+ ((nOffY+nTextHeight) > aSize.Height()) ||
+ ((nOffX+nTextWidth) > aSize.Width()) )
+ {
+ Rectangle aClip( aPos, aSize );
+ if ( nTextHeight > aSize.Height() )
+ aClip.Bottom() += nTextHeight-aSize.Height()+1; // Damit HP-Drucker nicht 'weg-optimieren'
+ pDev->IntersectClipRegion( aClip );
+ }
+
+ pDev->DrawText( aTextRect, aText, nTextStyle );
+ }
+ else
+ {
+ long nTextHeight = pDev->GetTextHeight();
+ USHORT nLines = (USHORT)(aSize.Height() / nTextHeight);
+ Rectangle aClip( aPos, aSize );
+
+ pDev->IntersectClipRegion( aClip );
+
+ if ( !nLines )
+ nLines = 1;
+
+ for ( USHORT n = 0; n < nLines; n++ )
+ {
+ USHORT nEntry = n+mpImplLB->GetTopEntry();
+ BOOL bSelected = mpImplLB->GetEntryList()->IsEntryPosSelected( nEntry );
+ if ( bSelected )
+ {
+ pDev->SetFillColor( COL_BLACK );
+ pDev->DrawRect( Rectangle( Point( aPos.X(), aPos.Y() + n*nTextHeight ),
+ Point( aPos.X() + aSize.Width(), aPos.Y() + (n+1)*nTextHeight + 2*nOnePixel ) ) );
+ pDev->SetFillColor();
+ pDev->SetTextColor( COL_WHITE );
+ }
+
+ aTextRect.Top() = aPos.Y() + n*nTextHeight;
+ aTextRect.Bottom() = aTextRect.Top() + nTextHeight;
+
+ pDev->DrawText( aTextRect, mpImplLB->GetEntryList()->GetEntryText( nEntry ), nTextStyle );
+
+ if ( bSelected )
+ pDev->SetTextColor( COL_BLACK );
+ }
+ }
+
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::GetFocus()
+{
+ if ( mpImplLB )
+ {
+ if( IsDropDownBox() )
+ mpImplWin->GrabFocus();
+ else
+ mpImplLB->GrabFocus();
+ }
+
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+Window* ListBox::GetPreferredKeyInputWindow()
+{
+ if ( mpImplLB )
+ {
+ if( IsDropDownBox() )
+ return mpImplWin->GetPreferredKeyInputWindow();
+ else
+ return mpImplLB->GetPreferredKeyInputWindow();
+ }
+
+ return Control::GetPreferredKeyInputWindow();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::LoseFocus()
+{
+ if( IsDropDownBox() )
+ mpImplWin->HideFocus();
+ else
+ mpImplLB->HideFocus();
+
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ SetBackground(); // due to a hack in Window::UpdateSettings the background must be reset
+ // otherwise it will overpaint NWF drawn listboxes
+ Resize();
+ mpImplLB->Resize(); // Wird nicht durch ListBox::Resize() gerufen, wenn sich die ImplLB nicht aendert.
+
+ if ( mpImplWin )
+ {
+ mpImplWin->SetSettings( GetSettings() ); // Falls noch nicht eingestellt...
+ ImplInitFieldSettings( mpImplWin, TRUE, TRUE, TRUE );
+
+ mpBtn->SetSettings( GetSettings() );
+ ImplInitDropDownButton( mpBtn );
+ }
+
+
+ if ( IsDropDownBox() )
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::EnableAutoSize( BOOL bAuto )
+{
+ mbDDAutoSize = bAuto;
+ if ( mpFloatWin )
+ {
+ if ( bAuto && !mpFloatWin->GetDropDownLineCount() )
+ mpFloatWin->SetDropDownLineCount( 5 );
+ else if ( !bAuto )
+ mpFloatWin->SetDropDownLineCount( 0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::EnableDDAutoWidth( BOOL b )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetAutoWidth( b );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsDDAutoWidthEnabled() const
+{
+ return mpFloatWin ? mpFloatWin->IsAutoWidth() : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetDropDownLineCount( USHORT nLines )
+{
+ mnLineCount = nLines;
+ if ( mpFloatWin )
+ mpFloatWin->SetDropDownLineCount( mnLineCount );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetDropDownLineCount() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetDropDownLineCount();
+ return mnLineCount;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
+{
+ if( IsDropDownBox() && ( nFlags & WINDOW_POSSIZE_SIZE ) )
+ {
+ Size aPrefSz = mpFloatWin->GetPrefSize();
+ if ( ( nFlags & WINDOW_POSSIZE_HEIGHT ) && ( nHeight >= 2*mnDDHeight ) )
+ aPrefSz.Height() = nHeight-mnDDHeight;
+ if ( nFlags & WINDOW_POSSIZE_WIDTH )
+ aPrefSz.Width() = nWidth;
+ mpFloatWin->SetPrefSize( aPrefSz );
+
+ if ( IsAutoSizeEnabled() && ! (nFlags & WINDOW_POSSIZE_DROPDOWN) )
+ nHeight = mnDDHeight;
+ }
+
+ Control::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::Resize()
+{
+ Size aOutSz = GetOutputSizePixel();
+ if( IsDropDownBox() )
+ {
+ // initialize the dropdown button size with the standard scrollbar width
+ long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
+ long nTop = 0;
+ long nBottom = aOutSz.Height();
+
+ // note: in case of no border, pBorder will actually be this
+ Window *pBorder = GetWindow( WINDOW_BORDER );
+ ImplControlValue aControlValue;
+ Point aPoint;
+ Rectangle aContent, aBound;
+
+ // use the full extent of the control
+ Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
+
+ if ( GetNativeControlRegion( CTRL_LISTBOX, PART_BUTTON_DOWN,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ // convert back from border space to local coordinates
+ aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
+ aContent.Move( -aPoint.X(), -aPoint.Y() );
+
+ // use the themes drop down size for the button
+ aOutSz.Width() = aContent.Left();
+ mpBtn->SetPosSizePixel( aContent.Left(), nTop, aContent.Right(), (nBottom-nTop) );
+
+ // adjust the size of the edit field
+ if ( GetNativeControlRegion( CTRL_LISTBOX, PART_SUB_EDIT,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ // convert back from border space to local coordinates
+ aContent.Move( -aPoint.X(), -aPoint.Y() );
+
+ // use the themes drop down size
+ if( ! (GetStyle() & WB_BORDER) && ImplGetSVData()->maNWFData.mbNoFocusRects )
+ {
+ // no border but focus ring behavior -> we have a problem; the
+ // native rect relies on the border to draw the focus
+ // let's do the best we can and center vertically, so it doesn't look
+ // completely wrong.
+ Size aSz( GetOutputSizePixel() );
+ long nDiff = aContent.Top() - (aSz.Height() - aContent.GetHeight())/2;
+ aContent.Top() -= nDiff;
+ aContent.Bottom() -= nDiff;
+ }
+ mpImplWin->SetPosSizePixel( aContent.TopLeft(), aContent.GetSize() );
+ }
+ else
+ mpImplWin->SetSizePixel( aOutSz );
+ }
+ else
+ {
+ nSBWidth = CalcZoom( nSBWidth );
+ mpImplWin->SetPosSizePixel( 0, 0, aOutSz.Width() - nSBWidth, aOutSz.Height() );
+ mpBtn->SetPosSizePixel( aOutSz.Width() - nSBWidth, 0, nSBWidth, aOutSz.Height() );
+ }
+ }
+ else
+ {
+ mpImplLB->SetSizePixel( aOutSz );
+ }
+
+ // FloatingWindow-Groesse auch im unsichtbare Zustand auf Stand halten,
+ // weil KEY_PGUP/DOWN ausgewertet wird...
+ if ( mpFloatWin )
+ mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize() );
+
+ Control::Resize();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const Control* pMainWin = mpImplLB->GetMainWindow();
+ if( mpFloatWin )
+ {
+ // dropdown mode
+ AppendLayoutData( *mpImplWin );
+ mpImplWin->SetLayoutDataParent( this );
+ if( mpFloatWin->IsReallyVisible() )
+ {
+ AppendLayoutData( *pMainWin );
+ pMainWin->SetLayoutDataParent( this );
+ }
+ }
+ else
+ {
+ AppendLayoutData( *pMainWin );
+ pMainWin->SetLayoutDataParent( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long ListBox::GetIndexForPoint( const Point& rPoint, USHORT& rPos ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+
+ // check whether rPoint fits at all
+ long nIndex = Control::GetIndexForPoint( rPoint );
+ if( nIndex != -1 )
+ {
+ // point must be either in main list window
+ // or in impl window (dropdown case)
+ ImplListBoxWindow* pMain = mpImplLB->GetMainWindow();
+
+ // convert coordinates to ImplListBoxWindow pixel coordinate space
+ Point aConvPoint = LogicToPixel( rPoint );
+ aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
+ aConvPoint = pMain->AbsoluteScreenToOutputPixel( aConvPoint );
+ aConvPoint = pMain->PixelToLogic( aConvPoint );
+
+ // try to find entry
+ USHORT nEntry = pMain->GetEntryPosForPoint( aConvPoint );
+ if( nEntry == LISTBOX_ENTRY_NOTFOUND )
+ {
+ // not found, maybe dropdown case
+ if( mpImplWin && mpImplWin->IsReallyVisible() )
+ {
+ // convert to impl window pixel coordinates
+ aConvPoint = LogicToPixel( rPoint );
+ aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
+ aConvPoint = mpImplWin->AbsoluteScreenToOutputPixel( aConvPoint );
+
+ // check whether converted point is inside impl window
+ Size aImplWinSize = mpImplWin->GetOutputSizePixel();
+ if( aConvPoint.X() >= 0 && aConvPoint.Y() >= 0 && aConvPoint.X() < aImplWinSize.Width() && aConvPoint.Y() < aImplWinSize.Height() )
+ {
+ // inside the impl window, the position is the current item pos
+ rPos = mpImplWin->GetItemPos();
+ }
+ else
+ nIndex = -1;
+ }
+ else
+ nIndex = -1;
+ }
+ else
+ rPos = nEntry;
+
+ DBG_ASSERT( nIndex != -1, "found index for point, but relative index failed" );
+ }
+
+ // get line relative index
+ if( nIndex != -1 )
+ nIndex = ToRelativeLineIndex( nIndex );
+
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::StateChanged( StateChangedType nType )
+{
+ if( nType == STATE_CHANGE_READONLY )
+ {
+ if( mpImplWin )
+ mpImplWin->Enable( !IsReadOnly() );
+ if( mpBtn )
+ mpBtn->Enable( !IsReadOnly() );
+ }
+ else if( nType == STATE_CHANGE_ENABLE )
+ {
+ mpImplLB->Enable( IsEnabled() );
+ if( mpImplWin )
+ {
+ mpImplWin->Enable( IsEnabled() );
+ if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
+ {
+ GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
+ }
+ else
+ mpImplWin->Invalidate();
+ }
+ if( mpBtn )
+ mpBtn->Enable( IsEnabled() );
+ }
+ else if( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ mpImplLB->SetUpdateMode( IsUpdateMode() );
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ mpImplLB->SetZoom( GetZoom() );
+ if ( mpImplWin )
+ {
+ mpImplWin->SetZoom( GetZoom() );
+ mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
+ mpImplWin->Invalidate();
+ }
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ mpImplLB->SetControlFont( GetControlFont() );
+ if ( mpImplWin )
+ {
+ mpImplWin->SetControlFont( GetControlFont() );
+ mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
+ mpImplWin->Invalidate();
+ }
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ mpImplLB->SetControlForeground( GetControlForeground() );
+ if ( mpImplWin )
+ {
+ mpImplWin->SetControlForeground( GetControlForeground() );
+ mpImplWin->SetTextColor( GetControlForeground() );
+ mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
+ mpImplWin->Invalidate();
+ }
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ mpImplLB->SetControlBackground( GetControlBackground() );
+ if ( mpImplWin )
+ {
+ if ( mpImplWin->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL) )
+ {
+ // Transparent background
+ mpImplWin->SetBackground();
+ mpImplWin->SetControlBackground();
+ }
+ else
+ {
+ mpImplWin->SetBackground( mpImplLB->GetMainWindow()->GetControlBackground() );
+ mpImplWin->SetControlBackground( mpImplLB->GetMainWindow()->GetControlBackground() );
+ }
+ mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
+ mpImplWin->Invalidate();
+ }
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ mpImplLB->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT ) ? TRUE : FALSE );
+ BOOL bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) ? TRUE : FALSE;
+ mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );
+ }
+ else if( nType == STATE_CHANGE_MIRRORING )
+ {
+ if( mpBtn )
+ {
+ mpBtn->EnableRTL( IsRTLEnabled() );
+ ImplInitDropDownButton( mpBtn );
+ }
+ mpImplLB->EnableRTL( IsRTLEnabled() );
+ if( mpImplWin )
+ mpImplWin->EnableRTL( IsRTLEnabled() );
+ Resize();
+ }
+
+ Control::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+long ListBox::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ if ( mpImplLB )
+ {
+ if( ( rNEvt.GetType() == EVENT_KEYINPUT ) && ( rNEvt.GetWindow() == mpImplWin ) )
+ {
+ KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
+ switch( aKeyEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_DOWN:
+ {
+ if( mpFloatWin && !mpFloatWin->IsInPopupMode() &&
+ aKeyEvt.GetKeyCode().IsMod2() )
+ {
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
+ mpBtn->SetPressed( TRUE );
+ mpFloatWin->StartFloat( FALSE );
+ ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
+ nDone = 1;
+ }
+ else
+ {
+ nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
+ }
+ }
+ break;
+ case KEY_UP:
+ {
+ if( mpFloatWin && mpFloatWin->IsInPopupMode() &&
+ aKeyEvt.GetKeyCode().IsMod2() )
+ {
+ mpFloatWin->EndPopupMode();
+ nDone = 1;
+ }
+ else
+ {
+ nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
+ }
+ }
+ break;
+ case KEY_RETURN:
+ {
+ if( IsInDropDown() )
+ {
+ mpImplLB->ProcessKeyInput( aKeyEvt );
+ nDone = 1;
+ }
+ }
+ break;
+
+ default:
+ {
+ nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
+ }
+ }
+ }
+ else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if ( IsInDropDown() && !HasChildPathFocus( TRUE ) )
+ mpFloatWin->EndPopupMode();
+ }
+ else if ( (rNEvt.GetType() == EVENT_COMMAND) &&
+ (rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL) &&
+ (rNEvt.GetWindow() == mpImplWin) )
+ {
+ USHORT nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
+ if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
+ || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
+ && HasChildPathFocus()
+ )
+ )
+ {
+ nDone = mpImplLB->HandleWheelAsCursorTravel( *rNEvt.GetCommandEvent() );
+ }
+ else
+ {
+ nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
+ }
+ }
+ }
+
+ return nDone ? nDone : Control::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::Select()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_LISTBOX_SELECT, maSelectHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::DoubleClick()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_LISTBOX_DOUBLECLICK, maDoubleClickHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::Clear()
+{
+ mpImplLB->Clear();
+ if( IsDropDownBox() )
+ {
+ mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
+ mpImplWin->SetString( ImplGetSVEmptyStr() );
+ Image aImage;
+ mpImplWin->SetImage( aImage );
+ mpImplWin->Invalidate();
+ }
+ CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED, (void*) sal_IntPtr(-1) );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetNoSelection()
+{
+ mpImplLB->SetNoSelection();
+ if( IsDropDownBox() )
+ {
+ mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
+ mpImplWin->SetString( ImplGetSVEmptyStr() );
+ Image aImage;
+ mpImplWin->SetImage( aImage );
+ mpImplWin->Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::InsertEntry( const XubString& rStr, USHORT nPos )
+{
+ USHORT nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr );
+ nRealPos = sal::static_int_cast<USHORT>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
+ CallEventListeners( VCLEVENT_LISTBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
+ return nRealPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::InsertEntry( const Image& rImage, USHORT nPos )
+{
+ USHORT nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rImage );
+ nRealPos = sal::static_int_cast<USHORT>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
+ CallEventListeners( VCLEVENT_LISTBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
+ return nRealPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::InsertEntry( const XubString& rStr, const Image& rImage, USHORT nPos )
+{
+ USHORT nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr, rImage );
+ nRealPos = sal::static_int_cast<USHORT>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
+ CallEventListeners( VCLEVENT_LISTBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
+ return nRealPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::RemoveEntry( const XubString& rStr )
+{
+ RemoveEntry( GetEntryPos( rStr ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::RemoveEntry( USHORT nPos )
+{
+ mpImplLB->RemoveEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+ CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED, (void*) sal_IntPtr(nPos) );
+}
+
+// -----------------------------------------------------------------------
+
+Image ListBox::GetEntryImage( USHORT nPos ) const
+{
+ if ( mpImplLB->GetEntryList()->HasEntryImage( nPos ) )
+ return mpImplLB->GetEntryList()->GetEntryImage( nPos );
+ return Image();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetEntryPos( const XubString& rStr ) const
+{
+ USHORT nPos = mpImplLB->GetEntryList()->FindEntry( rStr );
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ nPos = sal::static_int_cast<USHORT>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetEntryPos( const void* pData ) const
+{
+ USHORT nPos = mpImplLB->GetEntryList()->FindEntry( pData );
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ nPos = sal::static_int_cast<USHORT>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+XubString ListBox::GetEntry( USHORT nPos ) const
+{
+ return mpImplLB->GetEntryList()->GetEntryText( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetEntryCount() const
+{
+ return mpImplLB->GetEntryList()->GetEntryCount() - mpImplLB->GetEntryList()->GetMRUCount();
+}
+
+// -----------------------------------------------------------------------
+
+XubString ListBox::GetSelectEntry( USHORT nIndex ) const
+{
+ return GetEntry( GetSelectEntryPos( nIndex ) );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetSelectEntryCount() const
+{
+ return mpImplLB->GetEntryList()->GetSelectEntryCount();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetSelectEntryPos( USHORT nIndex ) const
+{
+ USHORT nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( nIndex );
+ if ( nPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
+ nPos = mpImplLB->GetEntryList()->FindEntry( mpImplLB->GetEntryList()->GetEntryText( nPos ) );
+ nPos = sal::static_int_cast<USHORT>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
+ }
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsEntrySelected( const XubString& rStr ) const
+{
+ return IsEntryPosSelected( GetEntryPos( rStr ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsEntryPosSelected( USHORT nPos ) const
+{
+ return mpImplLB->GetEntryList()->IsEntryPosSelected( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SelectEntry( const XubString& rStr, BOOL bSelect )
+{
+ SelectEntryPos( GetEntryPos( rStr ), bSelect );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SelectEntryPos( USHORT nPos, BOOL bSelect )
+{
+ if ( nPos < mpImplLB->GetEntryList()->GetEntryCount() )
+ mpImplLB->SelectEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), bSelect );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetEntryData( USHORT nPos, void* pNewData )
+{
+ mpImplLB->SetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount(), pNewData );
+}
+
+// -----------------------------------------------------------------------
+
+void* ListBox::GetEntryData( USHORT nPos ) const
+{
+ return mpImplLB->GetEntryList()->GetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetEntryFlags( USHORT nPos, long nFlags )
+{
+ mpImplLB->SetEntryFlags( nPos + mpImplLB->GetEntryList()->GetMRUCount(), nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+long ListBox::GetEntryFlags( USHORT nPos ) const
+{
+ return mpImplLB->GetEntryList()->GetEntryFlags( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetTopEntry( USHORT nPos )
+{
+ mpImplLB->SetTopEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::ShowProminentEntry( USHORT nPos )
+{
+ mpImplLB->ShowProminentEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetTopEntry() const
+{
+ USHORT nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND;
+ if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
+ nPos = 0;
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetProminentEntryType( ProminentEntry eType )
+{
+ mpImplLB->SetProminentEntryType( eType );
+}
+
+// -----------------------------------------------------------------------
+
+ProminentEntry ListBox::GetProminentEntryType() const
+{
+ return mpImplLB->GetProminentEntryType();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsTravelSelect() const
+{
+ return mpImplLB->IsTravelSelect();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsInDropDown() const
+{
+ return mpFloatWin && mpFloatWin->IsInPopupMode();
+}
+
+// -----------------------------------------------------------------------
+
+long ListBox::CalcWindowSizePixel( USHORT nLines ) const
+{
+ return mpImplLB->GetEntryHeight() * nLines;
+}
+
+Rectangle ListBox::GetBoundingRectangle( USHORT nItem ) const
+{
+ Rectangle aRect = mpImplLB->GetMainWindow()->GetBoundingRectangle( nItem );
+ Rectangle aOffset = mpImplLB->GetMainWindow()->GetWindowExtentsRelative( (Window*)this );
+ aRect.Move( aOffset.TopLeft().X(), aOffset.TopLeft().Y() );
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::EnableMultiSelection( BOOL bMulti )
+{
+ EnableMultiSelection( bMulti, FALSE );
+}
+
+void ListBox::EnableMultiSelection( BOOL bMulti, BOOL bStackSelection )
+{
+ mpImplLB->EnableMultiSelection( bMulti, bStackSelection );
+
+ // WB_SIMPLEMODE:
+ // Die MultiListBox verh�lt sich wie eine normale ListBox.
+ // Die Mehrfachselektion kann nur �ber entsprechende Zusatztasten erfolgen.
+
+ BOOL bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) ? TRUE : FALSE;
+ mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );
+
+ // ohne Focus ist das Traveln in einer MultiSelection nicht zu sehen:
+ if ( mpFloatWin )
+ mpImplLB->GetMainWindow()->AllowGrabFocus( bMulti );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsMultiSelectionEnabled() const
+{
+ return mpImplLB->IsMultiSelectionEnabled();
+}
+
+// -----------------------------------------------------------------------
+
+Size ListBox::CalcMinimumSize() const
+{
+ Size aSz;
+ if ( !IsDropDownBox() )
+ aSz = mpImplLB->CalcSize (mnLineCount ? mnLineCount : mpImplLB->GetEntryList()->GetEntryCount());
+ else
+ {
+ aSz.Height() = mpImplLB->CalcSize( 1 ).Height();
+ aSz.Height() += 4; // add a space between entry and border
+ // size to maxmimum entry width and add a little breathing space
+ aSz.Width() = mpImplLB->GetMaxEntryWidth() + 4;
+ // do not create ultrathin ListBoxes, it doesn't look good
+ if( aSz.Width() < GetSettings().GetStyleSettings().GetScrollBarSize() )
+ aSz.Width() = GetSettings().GetStyleSettings().GetScrollBarSize();
+
+ // try native borders; scrollbar size may not be a good indicator
+ // see how large the edit area inside is to estimate what is needed for the dropdown
+ ImplControlValue aControlValue;
+ Point aPoint;
+ Rectangle aContent, aBound;
+ Size aTestSize( 100, 20 );
+ Rectangle aArea( aPoint, aTestSize );
+ if( const_cast<ListBox*>(this)->GetNativeControlRegion(
+ CTRL_LISTBOX, PART_SUB_EDIT, aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ // use the themes drop down size
+ aSz.Width() += aTestSize.Width() - aContent.GetWidth();
+ }
+ else
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ }
+
+ aSz = CalcWindowSize( aSz );
+
+ if ( IsDropDownBox() ) // check minimum height of dropdown box
+ {
+ ImplControlValue aControlValue;
+ Rectangle aRect( Point( 0, 0 ), aSz );
+ Rectangle aContent, aBound;
+ if( const_cast<ListBox*>(this)->GetNativeControlRegion(
+ CTRL_LISTBOX, PART_ENTIRE_CONTROL, aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ if( aBound.GetHeight() > aSz.Height() )
+ aSz.Height() = aBound.GetHeight();
+ }
+ }
+
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Size ListBox::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Control::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size ListBox::CalcAdjustedSize( const Size& rPrefSize ) const
+{
+ Size aSz = rPrefSize;
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom );
+ aSz.Height() -= nTop+nBottom;
+ if ( !IsDropDownBox() )
+ {
+ long nEntryHeight = CalcSize( 1, 1 ).Height();
+ long nLines = aSz.Height() / nEntryHeight;
+ if ( nLines < 1 )
+ nLines = 1;
+ aSz.Height() = nLines * nEntryHeight;
+ }
+ else
+ {
+ aSz.Height() = mnDDHeight;
+ }
+ aSz.Height() += nTop+nBottom;
+
+ aSz = CalcWindowSize( aSz );
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Size ListBox::CalcSize( USHORT nColumns, USHORT nLines ) const
+{
+ // ggf. werden ScrollBars eingeblendet
+ Size aMinSz = CalcMinimumSize();
+// aMinSz = ImplCalcOutSz( aMinSz );
+
+ Size aSz;
+
+ // Hoehe
+ if ( nLines )
+ {
+ if ( !IsDropDownBox() )
+ aSz.Height() = mpImplLB->CalcSize( nLines ).Height();
+ else
+ aSz.Height() = mnDDHeight;
+ }
+ else
+ aSz.Height() = aMinSz.Height();
+
+ // Breite
+ if ( nColumns )
+ aSz.Width() = nColumns * GetTextWidth( XubString( 'X' ) );
+ else
+ aSz.Width() = aMinSz.Width();
+
+ if ( IsDropDownBox() )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+
+ if ( !IsDropDownBox() )
+ {
+ if ( aSz.Width() < aMinSz.Width() )
+ aSz.Height() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ if ( aSz.Height() < aMinSz.Height() )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ }
+
+ aSz = CalcWindowSize( aSz );
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::GetMaxVisColumnsAndLines( USHORT& rnCols, USHORT& rnLines ) const
+{
+ long nCharWidth = GetTextWidth( UniString( 'x' ) );
+ if ( !IsDropDownBox() )
+ {
+ Size aOutSz = mpImplLB->GetMainWindow()->GetOutputSizePixel();
+ rnCols = (USHORT) (aOutSz.Width()/nCharWidth);
+ rnLines = (USHORT) (aOutSz.Height()/mpImplLB->GetEntryHeight());
+ }
+ else
+ {
+ Size aOutSz = mpImplWin->GetOutputSizePixel();
+ rnCols = (USHORT) (aOutSz.Width()/nCharWidth);
+ rnLines = 1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ListBox, ImplUserDrawHdl, UserDrawEvent*, pEvent )
+{
+ UserDraw( *pEvent );
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::UserDraw( const UserDrawEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::DrawEntry( const UserDrawEvent& rEvt, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos )
+{
+ if ( rEvt.GetDevice() == mpImplLB->GetMainWindow() )
+ mpImplLB->GetMainWindow()->DrawEntry( rEvt.GetItemId(), bDrawImage, bDrawText, bDrawTextAtImagePos );
+ else if ( rEvt.GetDevice() == mpImplWin )
+ mpImplWin->DrawEntry( bDrawImage, bDrawText, bDrawTextAtImagePos );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetUserItemSize( const Size& rSz )
+{
+ mpImplLB->GetMainWindow()->SetUserItemSize( rSz );
+ if ( mpImplWin )
+ mpImplWin->SetUserItemSize( rSz );
+}
+
+// -----------------------------------------------------------------------
+
+const Size& ListBox::GetUserItemSize() const
+{
+ return mpImplLB->GetMainWindow()->GetUserItemSize();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::EnableUserDraw( BOOL bUserDraw )
+{
+ mpImplLB->GetMainWindow()->EnableUserDraw( bUserDraw );
+ if ( mpImplWin )
+ mpImplWin->EnableUserDraw( bUserDraw );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsUserDrawEnabled() const
+{
+ return mpImplLB->GetMainWindow()->IsUserDrawEnabled();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetReadOnly( BOOL bReadOnly )
+{
+ if ( mpImplLB->IsReadOnly() != bReadOnly )
+ {
+ mpImplLB->SetReadOnly( bReadOnly );
+ StateChanged( STATE_CHANGE_READONLY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ListBox::IsReadOnly() const
+{
+ return mpImplLB->IsReadOnly();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetSeparatorPos( USHORT n )
+{
+ mpImplLB->SetSeparatorPos( n );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetSeparatorPos()
+{
+ mpImplLB->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetSeparatorPos() const
+{
+ return mpImplLB->GetSeparatorPos();
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
+{
+ mpImplLB->SetMRUEntries( rEntries, cSep );
+}
+
+// -----------------------------------------------------------------------
+
+XubString ListBox::GetMRUEntries( xub_Unicode cSep ) const
+{
+ return mpImplLB->GetMRUEntries( cSep );
+}
+
+// -----------------------------------------------------------------------
+
+void ListBox::SetMaxMRUCount( USHORT n )
+{
+ mpImplLB->SetMaxMRUCount( n );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetMaxMRUCount() const
+{
+ return mpImplLB->GetMaxMRUCount();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ListBox::GetDisplayLineCount() const
+{
+ return mpImplLB->GetDisplayLineCount();
+}
+
+// -----------------------------------------------------------------------
+
+// pb: #106948# explicit mirroring for calc
+
+void ListBox::EnableMirroring()
+{
+ mpImplLB->EnableMirroring();
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ListBox::GetDropDownPosSizePixel() const
+{
+ return mpFloatWin ? mpFloatWin->GetWindowExtentsRelative( const_cast<ListBox*>(this) ) : Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+const Wallpaper& ListBox::GetDisplayBackground() const
+{
+ // !!! recursion does not occur because the ImplListBox is default
+ // initialized to a nontransparent color in Window::ImplInitData
+ return mpImplLB->GetDisplayBackground();
+}
+
+// =======================================================================
+MultiListBox::MultiListBox( Window* pParent, WinBits nStyle ) :
+ ListBox( WINDOW_MULTILISTBOX )
+{
+ ImplInit( pParent, nStyle );
+ EnableMultiSelection( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+MultiListBox::MultiListBox( Window* pParent, const ResId& rResId ) :
+ ListBox( WINDOW_MULTILISTBOX )
+{
+ rResId.SetRT( RSC_MULTILISTBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE ) )
+ Show();
+ EnableMultiSelection( TRUE );
+}
diff --git a/vcl/source/control/makefile.mk b/vcl/source/control/makefile.mk
new file mode 100644
index 000000000000..a2553333246d
--- /dev/null
+++ b/vcl/source/control/makefile.mk
@@ -0,0 +1,79 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=ctrl
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+.IF "$(COM)"=="ICC"
+CDEFS+=-D_STD_NO_NAMESPACE -D_VOS_NO_NAMESPACE -D_UNO_NO_NAMESPACE
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/button.obj \
+ $(SLO)$/ctrl.obj \
+ $(SLO)$/combobox.obj \
+ $(SLO)$/edit.obj \
+ $(SLO)$/field.obj \
+ $(SLO)$/field2.obj \
+ $(SLO)$/fixbrd.obj \
+ $(SLO)$/fixed.obj \
+ $(SLO)$/group.obj \
+ $(SLO)$/ilstbox.obj \
+ $(SLO)$/imgctrl.obj \
+ $(SLO)$/longcurr.obj \
+ $(SLO)$/lstbox.obj \
+ $(SLO)$/morebtn.obj \
+ $(SLO)$/menubtn.obj \
+ $(SLO)$/scrbar.obj \
+ $(SLO)$/slider.obj \
+ $(SLO)$/spinfld.obj \
+ $(SLO)$/spinbtn.obj \
+ $(SLO)$/tabctrl.obj
+
+EXCEPTIONSFILES= \
+ $(SLO)$/button.obj \
+ $(SLO)$/ctrl.obj \
+ $(SLO)$/edit.obj \
+ $(SLO)$/field2.obj \
+ $(SLO)$/ilstbox.obj \
+ $(SLO)$/tabctrl.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/source/control/menubtn.cxx b/vcl/source/control/menubtn.cxx
new file mode 100644
index 000000000000..1c83779da1a9
--- /dev/null
+++ b/vcl/source/control/menubtn.cxx
@@ -0,0 +1,249 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/decoview.hxx>
+#include <vcl/event.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/menubtn.hxx>
+
+
+
+// =======================================================================
+
+#define IMAGEBUTTON_BORDER_OFF1 11
+#define IMAGEBUTTON_BORDER_OFF2 16
+
+// =======================================================================
+
+void MenuButton::ImplInitMenuButtonData()
+{
+ mnDDStyle = PUSHBUTTON_DROPDOWN_MENUBUTTON;
+
+ mpMenuTimer = NULL;
+ mpMenu = NULL;
+ mpOwnMenu = NULL;
+ mnCurItemId = 0;
+ mnMenuMode = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+
+ PushButton::ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::ImplExecuteMenu()
+{
+ Activate();
+
+ if ( mpMenu )
+ {
+ Point aPos( 0, 1 );
+ Size aSize = GetSizePixel();
+ Rectangle aRect( aPos, aSize );
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ if ( !((GetStyle() & (WB_RECTSTYLE | WB_SMALLSTYLE)) ||
+ !(rStyleSettings.GetOptions() & STYLE_OPTION_MACSTYLE)) )
+ {
+ aRect.Left() += 2;
+ aRect.Top() += 2;
+ aRect.Right() -= 2;
+ aRect.Bottom() -= 2;
+ }
+ SetPressed( TRUE );
+ EndSelection();
+ mnCurItemId = mpMenu->Execute( this, aRect, POPUPMENU_EXECUTE_DOWN );
+ SetPressed( FALSE );
+ if ( mnCurItemId )
+ {
+ Select();
+ mnCurItemId = 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MenuButton::MenuButton( Window* pParent, WinBits nWinBits ) :
+ PushButton( WINDOW_MENUBUTTON )
+{
+ ImplInitMenuButtonData();
+ ImplInit( pParent, nWinBits );
+}
+
+// -----------------------------------------------------------------------
+
+MenuButton::MenuButton( Window* pParent, const ResId& rResId ) :
+ PushButton( WINDOW_MENUBUTTON )
+{
+ ImplInitMenuButtonData();
+ rResId.SetRT( RSC_MENUBUTTON );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if ( RSCMENUBUTTON_MENU & nObjMask )
+ {
+ mpOwnMenu = new PopupMenu( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) );
+ SetPopupMenu( mpOwnMenu );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MenuButton::~MenuButton()
+{
+ if ( mpMenuTimer )
+ delete mpMenuTimer;
+ if ( mpOwnMenu )
+ delete mpOwnMenu;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( MenuButton, ImplMenuTimeoutHdl, Timer*, EMPTYARG )
+{
+ // Abfragen, ob Button-Benutzung noch aktiv ist, da diese ja auch
+ // vorher abgebrochen wurden sein koennte
+ if ( IsTracking() )
+ {
+ if ( !(GetStyle() & WB_NOPOINTERFOCUS) )
+ GrabFocus();
+ ImplExecuteMenu();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bExecute = true;
+ if ( mnMenuMode & MENUBUTTON_MENUMODE_TIMED )
+ {
+ // if the separated dropdown symbol is hit,
+ // execute the popup immediately
+ if( ! ImplGetSymbolRect().IsInside( rMEvt.GetPosPixel() ) )
+ {
+ if ( !mpMenuTimer )
+ {
+ mpMenuTimer = new Timer;
+ mpMenuTimer->SetTimeoutHdl( LINK( this, MenuButton, ImplMenuTimeoutHdl ) );
+ }
+
+ mpMenuTimer->SetTimeout( GetSettings().GetMouseSettings().GetActionDelay() );
+ mpMenuTimer->Start();
+
+ PushButton::MouseButtonDown( rMEvt );
+ bExecute = false;
+ }
+ }
+ if( bExecute )
+ {
+ if ( PushButton::ImplHitTestPushButton( this, rMEvt.GetPosPixel() ) )
+ {
+ if ( !(GetStyle() & WB_NOPOINTERFOCUS) )
+ GrabFocus();
+ ImplExecuteMenu();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+ USHORT nCode = aKeyCode.GetCode();
+ if ( (nCode == KEY_DOWN) && aKeyCode.IsMod2() )
+ ImplExecuteMenu();
+ else if ( !(mnMenuMode & MENUBUTTON_MENUMODE_TIMED) &&
+ !aKeyCode.GetModifier() &&
+ ((nCode == KEY_RETURN) || (nCode == KEY_SPACE)) )
+ ImplExecuteMenu();
+ else
+ PushButton::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::Activate()
+{
+ maActivateHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::Select()
+{
+ maSelectHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::SetMenuMode( USHORT nMode )
+{
+ // Fuer die 5.1-Auslieferung besser noch nicht inline, ansonsten kann
+ // diese Funktion zur 6.0 inline werden
+ mnMenuMode = nMode;
+}
+
+// -----------------------------------------------------------------------
+
+void MenuButton::SetPopupMenu( PopupMenu* pNewMenu )
+{
+ // Fuer die 5.1-Auslieferung besser noch nicht inline, ansonsten kann
+ // diese Funktion zur 6.0 inline werden
+ mpMenu = pNewMenu;
+}
diff --git a/vcl/source/control/morebtn.cxx b/vcl/source/control/morebtn.cxx
new file mode 100644
index 000000000000..921a25756d32
--- /dev/null
+++ b/vcl/source/control/morebtn.cxx
@@ -0,0 +1,280 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/morebtn.hxx>
+
+#ifndef _SV_RD_H
+#include <tools/rc.h>
+#endif
+
+
+
+// =======================================================================
+
+DECLARE_LIST( ImplMoreWindowList, Window* )
+
+struct ImplMoreButtonData
+{
+ ImplMoreWindowList *mpItemList;
+ XubString maMoreText;
+ XubString maLessText;
+};
+
+// =======================================================================
+
+void MoreButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ mpMBData = new ImplMoreButtonData;
+ mnDelta = 0;
+ meUnit = MAP_PIXEL;
+ mbState = FALSE;
+
+ mpMBData->mpItemList = NULL;
+
+ PushButton::ImplInit( pParent, nStyle );
+
+ mpMBData->maMoreText = Button::GetStandardText( BUTTON_MORE );
+ mpMBData->maLessText = Button::GetStandardText( BUTTON_LESS );
+
+ SetHelpText( Button::GetStandardHelpText( BUTTON_MORE ) );
+
+ ShowState();
+
+ SetSymbolAlign( SYMBOLALIGN_RIGHT );
+ ImplSetSmallSymbol( TRUE );
+
+ if ( ! ( nStyle & ( WB_RIGHT | WB_LEFT ) ) )
+ {
+ nStyle |= WB_CENTER;
+ SetStyle( nStyle );
+ }
+}
+
+// -----------------------------------------------------------------------
+void MoreButton::ShowState()
+{
+ if ( mbState )
+ {
+ SetSymbol( SYMBOL_PAGEUP );
+ SetText( mpMBData->maLessText );
+ }
+ else
+ {
+ SetSymbol( SYMBOL_PAGEDOWN );
+ SetText( mpMBData->maMoreText );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MoreButton::MoreButton( Window* pParent, WinBits nStyle ) :
+ PushButton( WINDOW_MOREBUTTON )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+MoreButton::MoreButton( Window* pParent, const ResId& rResId ) :
+ PushButton( WINDOW_MOREBUTTON )
+{
+ rResId.SetRT( RSC_MOREBUTTON );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void MoreButton::ImplLoadRes( const ResId& rResId )
+{
+ PushButton::ImplLoadRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if ( nObjMask & RSC_MOREBUTTON_STATE )
+ {
+ // Nicht Methode rufen, da Dialog nicht umgeschaltet werden soll
+ mbState = (BOOL)ReadShortRes();
+ // SetText( GetText() );
+ ShowState();
+ }
+ if ( nObjMask & RSC_MOREBUTTON_MAPUNIT )
+ meUnit = (MapUnit)ReadLongRes();
+ if ( nObjMask & RSC_MOREBUTTON_DELTA )
+ // Groesse fuer Erweitern des Dialogs
+ mnDelta = ReadShortRes();
+}
+
+// -----------------------------------------------------------------------
+
+MoreButton::~MoreButton()
+{
+ if ( mpMBData->mpItemList )
+ delete mpMBData->mpItemList;
+ delete mpMBData;
+}
+
+// -----------------------------------------------------------------------
+
+void MoreButton::Click()
+{
+ Window* pParent = GetParent();
+ Size aSize( pParent->GetSizePixel() );
+ Window* pWindow = (mpMBData->mpItemList) ? mpMBData->mpItemList->First() : NULL;
+ long nDeltaPixel = LogicToPixel( Size( 0, mnDelta ), meUnit ).Height();
+
+ // Status aendern
+ mbState = !mbState;
+ ShowState();
+
+ // Hier den Click-Handler rufen, damit vorher die Controls initialisiert
+ // werden koennen
+ PushButton::Click();
+
+ // Je nach Status die Fenster updaten
+ if ( mbState )
+ {
+ // Fenster anzeigen
+ while ( pWindow )
+ {
+ pWindow->Show();
+ pWindow = mpMBData->mpItemList->Next();
+ }
+
+ // Dialogbox anpassen
+ Point aPos( pParent->GetPosPixel() );
+ Rectangle aDeskRect( pParent->ImplGetFrameWindow()->GetDesktopRectPixel() );
+
+ aSize.Height() += nDeltaPixel;
+ if ( (aPos.Y()+aSize.Height()) > aDeskRect.Bottom() )
+ {
+ aPos.Y() = aDeskRect.Bottom()-aSize.Height();
+
+ if ( aPos.Y() < aDeskRect.Top() )
+ aPos.Y() = aDeskRect.Top();
+
+ pParent->SetPosSizePixel( aPos, aSize );
+ }
+ else
+ pParent->SetSizePixel( aSize );
+ }
+ else
+ {
+ // Dialogbox anpassen
+ aSize.Height() -= nDeltaPixel;
+ pParent->SetSizePixel( aSize );
+
+ // Fenster nicht mehr anzeigen
+ while ( pWindow )
+ {
+ pWindow->Hide();
+ pWindow = mpMBData->mpItemList->Next();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void MoreButton::AddWindow( Window* pWindow )
+{
+ if ( !mpMBData->mpItemList )
+ mpMBData->mpItemList = new ImplMoreWindowList( 1024, 16, 16 );
+
+ mpMBData->mpItemList->Insert( pWindow, LIST_APPEND );
+
+ if ( mbState )
+ pWindow->Show();
+ else
+ pWindow->Hide();
+}
+
+// -----------------------------------------------------------------------
+
+void MoreButton::RemoveWindow( Window* pWindow )
+{
+ if ( mpMBData->mpItemList )
+ mpMBData->mpItemList->Remove( pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void MoreButton::SetText( const XubString& rText )
+{
+ PushButton::SetText( rText );
+}
+
+// -----------------------------------------------------------------------
+
+XubString MoreButton::GetText() const
+{
+ return PushButton::GetText();
+}
+
+// -----------------------------------------------------------------------
+void MoreButton::SetMoreText( const XubString& rText )
+{
+ if ( mpMBData )
+ mpMBData->maMoreText = rText;
+
+ if ( !mbState )
+ SetText( rText );
+}
+
+// -----------------------------------------------------------------------
+XubString MoreButton::GetMoreText() const
+{
+ if ( mpMBData )
+ return mpMBData->maMoreText;
+ else
+ return PushButton::GetText();
+}
+
+// -----------------------------------------------------------------------
+void MoreButton::SetLessText( const XubString& rText )
+{
+ if ( mpMBData )
+ mpMBData->maLessText = rText;
+
+ if ( mbState )
+ SetText( rText );
+}
+
+// -----------------------------------------------------------------------
+XubString MoreButton::GetLessText() const
+{
+ if ( mpMBData )
+ return mpMBData->maLessText;
+ else
+ return PushButton::GetText();
+}
+
diff --git a/vcl/source/control/scrbar.cxx b/vcl/source/control/scrbar.cxx
new file mode 100644
index 000000000000..9c82bb096dec
--- /dev/null
+++ b/vcl/source/control/scrbar.cxx
@@ -0,0 +1,1648 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/event.hxx"
+#include "vcl/sound.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/scrbar.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/svdata.hxx"
+
+#include "rtl/string.hxx"
+#include "tools/rc.h"
+
+
+
+using namespace rtl;
+
+/* #i77549#
+ HACK: for scrollbars in case of thumb rect, page up and page down rect we
+ abuse the HitTestNativeControl interface. All theming engines but aqua
+ are actually able to draw the thumb according to our internal representation.
+ However aqua draws a little outside. The canonical way would be to enhance the
+ HitTestNativeControl passing a ScrollbarValue additionally so all necessary
+ information is available in the call.
+ .
+ However since there is only this one small exception we will deviate a little and
+ instead pass the respective rect as control region to allow for a small correction.
+
+ So all places using HitTestNativeControl on PART_THUMB_HORZ, PART_THUMB_VERT,
+ PART_TRACK_HORZ_LEFT, PART_TRACK_HORZ_RIGHT, PART_TRACK_VERT_UPPER, PART_TRACK_VERT_LOWER
+ do not use the control rectangle as region but the actuall part rectangle, making
+ only small deviations feasible.
+*/
+
+
+// =======================================================================
+
+static long ImplMulDiv( long nNumber, long nNumerator, long nDenominator )
+{
+ double n = ((double)nNumber * (double)nNumerator) / (double)nDenominator;
+ return (long)n;
+}
+
+// =======================================================================
+
+#define SCRBAR_DRAW_BTN1 ((USHORT)0x0001)
+#define SCRBAR_DRAW_BTN2 ((USHORT)0x0002)
+#define SCRBAR_DRAW_PAGE1 ((USHORT)0x0004)
+#define SCRBAR_DRAW_PAGE2 ((USHORT)0x0008)
+#define SCRBAR_DRAW_THUMB ((USHORT)0x0010)
+#define SCRBAR_DRAW_BACKGROUND ((USHORT)0x0020)
+#define SCRBAR_DRAW_ALL (SCRBAR_DRAW_BTN1 | SCRBAR_DRAW_BTN2 | \
+ SCRBAR_DRAW_PAGE1 | SCRBAR_DRAW_PAGE2 |\
+ SCRBAR_DRAW_THUMB | SCRBAR_DRAW_BACKGROUND )
+
+#define SCRBAR_STATE_BTN1_DOWN ((USHORT)0x0001)
+#define SCRBAR_STATE_BTN1_DISABLE ((USHORT)0x0002)
+#define SCRBAR_STATE_BTN2_DOWN ((USHORT)0x0004)
+#define SCRBAR_STATE_BTN2_DISABLE ((USHORT)0x0008)
+#define SCRBAR_STATE_PAGE1_DOWN ((USHORT)0x0010)
+#define SCRBAR_STATE_PAGE2_DOWN ((USHORT)0x0020)
+#define SCRBAR_STATE_THUMB_DOWN ((USHORT)0x0040)
+
+#define SCRBAR_VIEW_STYLE (WB_3DLOOK | WB_HORZ | WB_VERT)
+
+struct ImplScrollBarData
+{
+ AutoTimer maTimer; // Timer
+ BOOL mbHide;
+ Rectangle maTrackRect; // TODO: move to ScrollBar class when binary incompatibility of ScrollBar class is no longer problematic
+};
+
+// =======================================================================
+
+void ScrollBar::ImplInit( Window* pParent, WinBits nStyle )
+{
+ mpData = NULL;
+ mnThumbPixRange = 0;
+ mnThumbPixPos = 0;
+ mnThumbPixSize = 0;
+ mnMinRange = 0;
+ mnMaxRange = 100;
+ mnThumbPos = 0;
+ mnVisibleSize = 0;
+ mnLineSize = 1;
+ mnPageSize = 1;
+ mnDelta = 0;
+ mnDragDraw = 0;
+ mnStateFlags = 0;
+ meScrollType = SCROLL_DONTKNOW;
+ meDDScrollType = SCROLL_DONTKNOW;
+ mbCalcSize = TRUE;
+ mbFullDrag = 0;
+
+ if( !mpData ) // TODO: remove when maTrackRect is no longer in mpData
+ {
+ mpData = new ImplScrollBarData;
+ mpData->maTimer.SetTimeoutHdl( LINK( this, ScrollBar, ImplAutoTimerHdl ) );
+ mpData->mbHide = FALSE;
+ }
+
+ ImplInitStyle( nStyle );
+ Control::ImplInit( pParent, nStyle, NULL );
+
+ long nScrollSize = GetSettings().GetStyleSettings().GetScrollBarSize();
+ SetSizePixel( Size( nScrollSize, nScrollSize ) );
+ SetBackground();
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::ImplInitStyle( WinBits nStyle )
+{
+ if ( nStyle & WB_DRAG )
+ mbFullDrag = TRUE;
+ else
+ mbFullDrag = (GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SCROLL) != 0;
+}
+
+// -----------------------------------------------------------------------
+
+ScrollBar::ScrollBar( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_SCROLLBAR )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ScrollBar::ScrollBar( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_SCROLLBAR )
+{
+ rResId.SetRT( RSC_SCROLLBAR );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+ScrollBar::~ScrollBar()
+{
+ if( mpData )
+ delete mpData;
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ INT16 nMin = ReadShortRes();
+ INT16 nMax = ReadShortRes();
+ INT16 nThumbPos = ReadShortRes();
+ INT16 nPage = ReadShortRes();
+ INT16 nStep = ReadShortRes();
+ INT16 nVisibleSize = ReadShortRes();
+
+ SetRange( Range( nMin, nMax ) );
+ SetLineSize( nStep );
+ SetPageSize( nPage );
+ SetVisibleSize( nVisibleSize );
+ SetThumbPos( nThumbPos );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::ImplUpdateRects( BOOL bUpdate )
+{
+ USHORT nOldStateFlags = mnStateFlags;
+ Rectangle aOldPage1Rect = maPage1Rect;
+ Rectangle aOldPage2Rect = maPage2Rect;
+ Rectangle aOldThumbRect = maThumbRect;
+
+ mnStateFlags &= ~SCRBAR_STATE_BTN1_DISABLE;
+ mnStateFlags &= ~SCRBAR_STATE_BTN2_DISABLE;
+
+ Rectangle& maTrackRect = mpData->maTrackRect; // TODO: remove when maTrackRect is no longer in mpData
+ if ( mnThumbPixRange )
+ {
+ if ( GetStyle() & WB_HORZ )
+ {
+ maThumbRect.Left() = maTrackRect.Left()+mnThumbPixPos;
+ maThumbRect.Right() = maThumbRect.Left()+mnThumbPixSize-1;
+ if ( !mnThumbPixPos )
+ maPage1Rect.Right() = RECT_EMPTY;
+ else
+ maPage1Rect.Right() = maThumbRect.Left()-1;
+ if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
+ maPage2Rect.Right() = RECT_EMPTY;
+ else
+ {
+ maPage2Rect.Left() = maThumbRect.Right()+1;
+ maPage2Rect.Right() = maTrackRect.Right();
+ }
+ }
+ else
+ {
+ maThumbRect.Top() = maTrackRect.Top()+mnThumbPixPos;
+ maThumbRect.Bottom() = maThumbRect.Top()+mnThumbPixSize-1;
+ if ( !mnThumbPixPos )
+ maPage1Rect.Bottom() = RECT_EMPTY;
+ else
+ maPage1Rect.Bottom() = maThumbRect.Top()-1;
+ if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
+ maPage2Rect.Bottom() = RECT_EMPTY;
+ else
+ {
+ maPage2Rect.Top() = maThumbRect.Bottom()+1;
+ maPage2Rect.Bottom() = maTrackRect.Bottom();
+ }
+ }
+ }
+ else
+ {
+ Size aScrBarSize = GetOutputSizePixel();
+ if ( GetStyle() & WB_HORZ )
+ {
+ const long nSpace = maTrackRect.Right() - maTrackRect.Left();
+ if ( nSpace > 0 )
+ {
+ maPage1Rect.Left() = maTrackRect.Left();
+ maPage1Rect.Right() = maTrackRect.Left() + (nSpace/2);
+ maPage2Rect.Left() = maPage1Rect.Right() + 1;
+ maPage2Rect.Right() = maTrackRect.Right();
+ }
+ }
+ else
+ {
+ const long nSpace = maTrackRect.Bottom() - maTrackRect.Top();
+ if ( nSpace > 0 )
+ {
+ maPage1Rect.Top() = maTrackRect.Top();
+ maPage1Rect.Bottom() = maTrackRect.Top() + (nSpace/2);
+ maPage2Rect.Top() = maPage1Rect.Bottom() + 1;
+ maPage2Rect.Bottom() = maTrackRect.Bottom();
+ }
+ }
+ }
+
+ if( !IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL) )
+ {
+ // disable scrollbar buttons only in VCL's own 'theme'
+ // as it is uncommon on other platforms
+ if ( mnThumbPos == mnMinRange )
+ mnStateFlags |= SCRBAR_STATE_BTN1_DISABLE;
+ if ( mnThumbPos >= (mnMaxRange-mnVisibleSize) )
+ mnStateFlags |= SCRBAR_STATE_BTN2_DISABLE;
+ }
+
+ if ( bUpdate )
+ {
+ USHORT nDraw = 0;
+ if ( (nOldStateFlags & SCRBAR_STATE_BTN1_DISABLE) !=
+ (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) )
+ nDraw |= SCRBAR_DRAW_BTN1;
+ if ( (nOldStateFlags & SCRBAR_STATE_BTN2_DISABLE) !=
+ (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) )
+ nDraw |= SCRBAR_DRAW_BTN2;
+ if ( aOldPage1Rect != maPage1Rect )
+ nDraw |= SCRBAR_DRAW_PAGE1;
+ if ( aOldPage2Rect != maPage2Rect )
+ nDraw |= SCRBAR_DRAW_PAGE2;
+ if ( aOldThumbRect != maThumbRect )
+ nDraw |= SCRBAR_DRAW_THUMB;
+ ImplDraw( nDraw, this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long ScrollBar::ImplCalcThumbPos( long nPixPos )
+{
+ // Position berechnen
+ long nCalcThumbPos;
+ nCalcThumbPos = ImplMulDiv( nPixPos, mnMaxRange-mnVisibleSize-mnMinRange,
+ mnThumbPixRange-mnThumbPixSize );
+ nCalcThumbPos += mnMinRange;
+ return nCalcThumbPos;
+}
+
+// -----------------------------------------------------------------------
+
+long ScrollBar::ImplCalcThumbPosPix( long nPos )
+{
+ long nCalcThumbPos;
+
+ // Position berechnen
+ nCalcThumbPos = ImplMulDiv( nPos-mnMinRange, mnThumbPixRange-mnThumbPixSize,
+ mnMaxRange-mnVisibleSize-mnMinRange );
+
+ // Am Anfang und Ende des ScrollBars versuchen wir die Anzeige korrekt
+ // anzuzeigen
+ if ( !nCalcThumbPos && (mnThumbPos > mnMinRange) )
+ nCalcThumbPos = 1;
+ if ( nCalcThumbPos &&
+ ((nCalcThumbPos+mnThumbPixSize) >= mnThumbPixRange) &&
+ (mnThumbPos < (mnMaxRange-mnVisibleSize)) )
+ nCalcThumbPos--;
+
+ return nCalcThumbPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::ImplCalc( BOOL bUpdate )
+{
+ const Size aSize = GetOutputSizePixel();
+ const long nMinThumbSize = GetSettings().GetStyleSettings().GetMinThumbSize();;
+
+ Rectangle& maTrackRect = mpData->maTrackRect; // TODO: remove when maTrackRect is no longer in mpData
+ if ( mbCalcSize )
+ {
+ const Rectangle aControlRegion( Point(0,0), aSize );
+ Rectangle aBtn1Region, aBtn2Region, aTrackRegion, aBoundingRegion;
+
+ if ( GetStyle() & WB_HORZ )
+ {
+ if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_LEFT,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn1Region ) &&
+ GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_RIGHT,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn2Region ) )
+ {
+ maBtn1Rect = aBtn1Region;
+ maBtn2Rect = aBtn2Region;
+ }
+ else
+ {
+ Size aBtnSize( aSize.Height(), aSize.Height() );
+ maBtn2Rect.Top() = maBtn1Rect.Top();
+ maBtn2Rect.Left() = aSize.Width()-aSize.Height();
+ maBtn1Rect.SetSize( aBtnSize );
+ maBtn2Rect.SetSize( aBtnSize );
+ }
+
+ if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_HORZ_AREA,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) )
+ maTrackRect = aTrackRegion;
+ else
+ maTrackRect = Rectangle( maBtn1Rect.TopRight(), maBtn2Rect.BottomLeft() );
+
+ // Check if available space is big enough for thumb ( min thumb size = ScrBar width/height )
+ mnThumbPixRange = maTrackRect.Right() - maTrackRect.Left();
+ if( mnThumbPixRange > 0 )
+ {
+ maPage1Rect.Left() = maTrackRect.Left();
+ maPage1Rect.Bottom() =
+ maPage2Rect.Bottom() =
+ maThumbRect.Bottom() = maTrackRect.Bottom();
+ }
+ else
+ {
+ mnThumbPixRange = 0;
+ maPage1Rect.SetEmpty();
+ maPage2Rect.SetEmpty();
+ }
+ }
+ else
+ {
+ if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_UP,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn1Region ) &&
+ GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_DOWN,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn2Region ) )
+ {
+ maBtn1Rect = aBtn1Region;
+ maBtn2Rect = aBtn2Region;
+ }
+ else
+ {
+ const Size aBtnSize( aSize.Width(), aSize.Width() );
+ maBtn2Rect.Left() = maBtn1Rect.Left();
+ maBtn2Rect.Top() = aSize.Height()-aSize.Width();
+ maBtn1Rect.SetSize( aBtnSize );
+ maBtn2Rect.SetSize( aBtnSize );
+ }
+
+ if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_VERT_AREA,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) )
+ maTrackRect = aTrackRegion;
+ else
+ maTrackRect = Rectangle( maBtn1Rect.BottomLeft()+Point(0,1), maBtn2Rect.TopRight() );
+
+ // Check if available space is big enough for thumb
+ mnThumbPixRange = maTrackRect.Bottom() - maTrackRect.Top();
+ if( mnThumbPixRange > 0 )
+ {
+ maPage1Rect.Top() = maTrackRect.Top();
+ maPage1Rect.Right() =
+ maPage2Rect.Right() =
+ maThumbRect.Right() = maTrackRect.Right();
+ }
+ else
+ {
+ mnThumbPixRange = 0;
+ maPage1Rect.SetEmpty();
+ maPage2Rect.SetEmpty();
+ }
+ }
+
+ if ( !mnThumbPixRange )
+ maThumbRect.SetEmpty();
+
+ mbCalcSize = FALSE;
+ }
+
+ if ( mnThumbPixRange )
+ {
+ // Werte berechnen
+ if ( (mnVisibleSize >= (mnMaxRange-mnMinRange)) ||
+ ((mnMaxRange-mnMinRange) <= 0) )
+ {
+ mnThumbPos = mnMinRange;
+ mnThumbPixPos = 0;
+ mnThumbPixSize = mnThumbPixRange;
+ }
+ else
+ {
+ if ( mnVisibleSize )
+ mnThumbPixSize = ImplMulDiv( mnThumbPixRange, mnVisibleSize, mnMaxRange-mnMinRange );
+ else
+ {
+ if ( GetStyle() & WB_HORZ )
+ mnThumbPixSize = maThumbRect.GetWidth();
+ else
+ mnThumbPixSize = maThumbRect.GetHeight();
+ }
+ if ( mnThumbPixSize < nMinThumbSize )
+ mnThumbPixSize = nMinThumbSize;
+ if ( mnThumbPixSize > mnThumbPixRange )
+ mnThumbPixSize = mnThumbPixRange;
+ mnThumbPixPos = ImplCalcThumbPosPix( mnThumbPos );
+ }
+ }
+
+ // Wenn neu ausgegeben werden soll und wir schon ueber eine
+ // Aktion einen Paint-Event ausgeloest bekommen haben, dann
+ // geben wir nicht direkt aus, sondern invalidieren nur alles
+ if ( bUpdate && HasPaintEvent() )
+ {
+ Invalidate();
+ bUpdate = FALSE;
+ }
+ ImplUpdateRects( bUpdate );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Rectangle aRect( aPos, aSize );
+
+ pDev->Push();
+ pDev->SetMapMode();
+ if ( !(nFlags & WINDOW_DRAW_MONO) )
+ {
+ // DecoView uses the FaceColor...
+ AllSettings aSettings = pDev->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ if ( IsControlBackground() )
+ aStyleSettings.SetFaceColor( GetControlBackground() );
+ else
+ aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
+
+ aSettings.SetStyleSettings( aStyleSettings );
+ pDev->SetSettings( aSettings );
+ }
+
+ // for printing:
+ // -calculate the size of the rects
+ // -because this is zero-based add the correct offset
+ // -print
+ // -force recalculate
+
+ if ( mbCalcSize )
+ ImplCalc( FALSE );
+
+ maBtn1Rect+=aPos;
+ maBtn2Rect+=aPos;
+ maThumbRect+=aPos;
+ mpData->maTrackRect+=aPos; // TODO: update when maTrackRect is no longer in mpData
+ maPage1Rect+=aPos;
+ maPage2Rect+=aPos;
+
+ ImplDraw( SCRBAR_DRAW_ALL, pDev );
+ pDev->Pop();
+
+ mbCalcSize = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ScrollBar::ImplDrawNative( USHORT nDrawFlags )
+{
+ ScrollbarValue scrValue;
+
+ BOOL bNativeOK = IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL);
+ if( bNativeOK )
+ {
+ BOOL bHorz = (GetStyle() & WB_HORZ ? true : false);
+
+ // Draw the entire background if the control supports it
+ if( IsNativeControlSupported(CTRL_SCROLLBAR, bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT) )
+ {
+ ControlState nState = ( IsEnabled() ? CTRL_STATE_ENABLED : 0 ) | ( HasFocus() ? CTRL_STATE_FOCUSED : 0 );
+
+ scrValue.mnMin = mnMinRange;
+ scrValue.mnMax = mnMaxRange;
+ scrValue.mnCur = mnThumbPos;
+ scrValue.mnVisibleSize = mnVisibleSize;
+ scrValue.maThumbRect = maThumbRect;
+ scrValue.maButton1Rect = maBtn1Rect;
+ scrValue.maButton2Rect = maBtn2Rect;
+ scrValue.mnButton1State = ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0) |
+ ((!(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)) ? CTRL_STATE_ENABLED : 0);
+ scrValue.mnButton2State = ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0) |
+ ((!(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)) ? CTRL_STATE_ENABLED : 0);
+ scrValue.mnThumbState = nState | ((mnStateFlags & SCRBAR_STATE_THUMB_DOWN) ? CTRL_STATE_PRESSED : 0);
+ scrValue.mnPage1State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0);
+ scrValue.mnPage2State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0);
+
+ if( IsMouseOver() )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ if( pRect )
+ {
+ if( pRect == &maThumbRect )
+ scrValue.mnThumbState |= CTRL_STATE_ROLLOVER;
+ else if( pRect == &maBtn1Rect )
+ scrValue.mnButton1State |= CTRL_STATE_ROLLOVER;
+ else if( pRect == &maBtn2Rect )
+ scrValue.mnButton2State |= CTRL_STATE_ROLLOVER;
+ else if( pRect == &maPage1Rect )
+ scrValue.mnPage1State |= CTRL_STATE_ROLLOVER;
+ else if( pRect == &maPage2Rect )
+ scrValue.mnPage2State |= CTRL_STATE_ROLLOVER;
+ }
+ }
+
+ Rectangle aCtrlRegion;
+ aCtrlRegion.Union( maBtn1Rect );
+ aCtrlRegion.Union( maBtn2Rect );
+ aCtrlRegion.Union( maPage1Rect );
+ aCtrlRegion.Union( maPage2Rect );
+ aCtrlRegion.Union( maThumbRect );
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT),
+ aCtrlRegion, nState, scrValue, rtl::OUString() );
+ }
+ else
+ {
+ if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) || (nDrawFlags & SCRBAR_DRAW_PAGE2) )
+ {
+ sal_uInt32 part1 = bHorz ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER;
+ sal_uInt32 part2 = bHorz ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER;
+ Rectangle aCtrlRegion1( maPage1Rect );
+ Rectangle aCtrlRegion2( maPage2Rect );
+ ControlState nState1 = (IsEnabled() ? CTRL_STATE_ENABLED : 0) | (HasFocus() ? CTRL_STATE_FOCUSED : 0);
+ ControlState nState2 = nState1;
+
+ nState1 |= ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0);
+ nState2 |= ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0);
+
+ if( IsMouseOver() )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ if( pRect )
+ {
+ if( pRect == &maPage1Rect )
+ nState1 |= CTRL_STATE_ROLLOVER;
+ else if( pRect == &maPage2Rect )
+ nState2 |= CTRL_STATE_ROLLOVER;
+ }
+ }
+
+ if ( nDrawFlags & SCRBAR_DRAW_PAGE1 )
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1,
+ scrValue, rtl::OUString() );
+
+ if ( nDrawFlags & SCRBAR_DRAW_PAGE2 )
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
+ scrValue, rtl::OUString() );
+ }
+ if ( (nDrawFlags & SCRBAR_DRAW_BTN1) || (nDrawFlags & SCRBAR_DRAW_BTN2) )
+ {
+ sal_uInt32 part1 = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
+ sal_uInt32 part2 = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
+ Rectangle aCtrlRegion1( maBtn1Rect );
+ Rectangle aCtrlRegion2( maBtn2Rect );
+ ControlState nState1 = HasFocus() ? CTRL_STATE_FOCUSED : 0;
+ ControlState nState2 = nState1;
+
+ if ( !Window::IsEnabled() || !IsEnabled() )
+ nState1 = (nState2 &= ~CTRL_STATE_ENABLED);
+ else
+ nState1 = (nState2 |= CTRL_STATE_ENABLED);
+
+ nState1 |= ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0);
+ nState2 |= ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0);
+
+ if(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)
+ nState1 &= ~CTRL_STATE_ENABLED;
+ if(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)
+ nState2 &= ~CTRL_STATE_ENABLED;
+
+ if( IsMouseOver() )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ if( pRect )
+ {
+ if( pRect == &maBtn1Rect )
+ nState1 |= CTRL_STATE_ROLLOVER;
+ else if( pRect == &maBtn2Rect )
+ nState2 |= CTRL_STATE_ROLLOVER;
+ }
+ }
+
+ if ( nDrawFlags & SCRBAR_DRAW_BTN1 )
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1,
+ scrValue, rtl::OUString() );
+
+ if ( nDrawFlags & SCRBAR_DRAW_BTN2 )
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
+ scrValue, rtl::OUString() );
+ }
+ if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && !maThumbRect.IsEmpty() )
+ {
+ ControlState nState = IsEnabled() ? CTRL_STATE_ENABLED : 0;
+ Rectangle aCtrlRegion( maThumbRect );
+
+ if ( mnStateFlags & SCRBAR_STATE_THUMB_DOWN )
+ nState |= CTRL_STATE_PRESSED;
+
+ if ( HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+
+ if( IsMouseOver() )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ if( pRect )
+ {
+ if( pRect == &maThumbRect )
+ nState |= CTRL_STATE_ROLLOVER;
+ }
+ }
+
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_THUMB_HORZ : PART_THUMB_VERT),
+ aCtrlRegion, nState, scrValue, rtl::OUString() );
+ }
+ }
+ }
+ return bNativeOK;
+}
+
+void ScrollBar::ImplDraw( USHORT nDrawFlags, OutputDevice* pOutDev )
+{
+ DecorationView aDecoView( pOutDev );
+ Rectangle aTempRect;
+ USHORT nStyle;
+ const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
+ SymbolType eSymbolType;
+ BOOL bEnabled = IsEnabled();
+
+ // Evt. noch offene Berechnungen nachholen
+ if ( mbCalcSize )
+ ImplCalc( FALSE );
+
+ Window *pWin = NULL;
+ if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
+ pWin = (Window*) pOutDev;
+
+ // Draw the entire control if the native theme engine needs it
+ if ( nDrawFlags && pWin && pWin->IsNativeControlSupported(CTRL_SCROLLBAR, PART_DRAW_BACKGROUND_HORZ) )
+ {
+ ImplDrawNative( SCRBAR_DRAW_BACKGROUND );
+ return;
+ }
+
+ if( (nDrawFlags & SCRBAR_DRAW_BTN1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN1 ) ) )
+ {
+ nStyle = BUTTON_DRAW_NOLIGHTBORDER;
+ if ( mnStateFlags & SCRBAR_STATE_BTN1_DOWN )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ aTempRect = aDecoView.DrawButton( maBtn1Rect, nStyle );
+ ImplCalcSymbolRect( aTempRect );
+ nStyle = 0;
+ if ( (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) || !bEnabled )
+ nStyle |= SYMBOL_DRAW_DISABLE;
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW )
+ {
+ if ( GetStyle() & WB_HORZ )
+ eSymbolType = SYMBOL_ARROW_LEFT;
+ else
+ eSymbolType = SYMBOL_ARROW_UP;
+ }
+ else
+ {
+ if ( GetStyle() & WB_HORZ )
+ eSymbolType = SYMBOL_SPIN_LEFT;
+ else
+ eSymbolType = SYMBOL_SPIN_UP;
+ }
+ aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle );
+ }
+
+ if ( (nDrawFlags & SCRBAR_DRAW_BTN2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN2 ) ) )
+ {
+ nStyle = BUTTON_DRAW_NOLIGHTBORDER;
+ if ( mnStateFlags & SCRBAR_STATE_BTN2_DOWN )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ aTempRect = aDecoView.DrawButton( maBtn2Rect, nStyle );
+ ImplCalcSymbolRect( aTempRect );
+ nStyle = 0;
+ if ( (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) || !bEnabled )
+ nStyle |= SYMBOL_DRAW_DISABLE;
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW )
+ {
+ if ( GetStyle() & WB_HORZ )
+ eSymbolType = SYMBOL_ARROW_RIGHT;
+ else
+ eSymbolType = SYMBOL_ARROW_DOWN;
+ }
+ else
+ {
+ if ( GetStyle() & WB_HORZ )
+ eSymbolType = SYMBOL_SPIN_RIGHT;
+ else
+ eSymbolType = SYMBOL_SPIN_DOWN;
+ }
+ aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle );
+ }
+
+ pOutDev->SetLineColor();
+
+ if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_THUMB ) ) )
+ {
+ if ( !maThumbRect.IsEmpty() )
+ {
+ if ( bEnabled )
+ {
+ nStyle = BUTTON_DRAW_NOLIGHTBORDER;
+ // pressed thumbs only in OS2 style
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_OS2STYLE )
+ if ( mnStateFlags & SCRBAR_STATE_THUMB_DOWN )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ aTempRect = aDecoView.DrawButton( maThumbRect, nStyle );
+ // OS2 style requires pattern on the thumb
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_OS2STYLE )
+ {
+ if ( GetStyle() & WB_HORZ )
+ {
+ if ( aTempRect.GetWidth() > 6 )
+ {
+ long nX = aTempRect.Center().X();
+ nX -= 6;
+ if ( nX < aTempRect.Left() )
+ nX = aTempRect.Left();
+ for ( int i = 0; i < 6; i++ )
+ {
+ if ( nX > aTempRect.Right()-1 )
+ break;
+
+ pOutDev->SetLineColor( rStyleSettings.GetButtonTextColor() );
+ pOutDev->DrawLine( Point( nX, aTempRect.Top()+1 ),
+ Point( nX, aTempRect.Bottom()-1 ) );
+ nX++;
+ pOutDev->SetLineColor( rStyleSettings.GetLightColor() );
+ pOutDev->DrawLine( Point( nX, aTempRect.Top()+1 ),
+ Point( nX, aTempRect.Bottom()-1 ) );
+ nX++;
+ }
+ }
+ }
+ else
+ {
+ if ( aTempRect.GetHeight() > 6 )
+ {
+ long nY = aTempRect.Center().Y();
+ nY -= 6;
+ if ( nY < aTempRect.Top() )
+ nY = aTempRect.Top();
+ for ( int i = 0; i < 6; i++ )
+ {
+ if ( nY > aTempRect.Bottom()-1 )
+ break;
+
+ pOutDev->SetLineColor( rStyleSettings.GetButtonTextColor() );
+ pOutDev->DrawLine( Point( aTempRect.Left()+1, nY ),
+ Point( aTempRect.Right()-1, nY ) );
+ nY++;
+ pOutDev->SetLineColor( rStyleSettings.GetLightColor() );
+ pOutDev->DrawLine( Point( aTempRect.Left()+1, nY ),
+ Point( aTempRect.Right()-1, nY ) );
+ nY++;
+ }
+ }
+ }
+ pOutDev->SetLineColor();
+ }
+ }
+ else
+ {
+ pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
+ pOutDev->DrawRect( maThumbRect );
+ }
+ }
+ }
+
+ if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE1 ) ) )
+ {
+ if ( mnStateFlags & SCRBAR_STATE_PAGE1_DOWN )
+ pOutDev->SetFillColor( rStyleSettings.GetShadowColor() );
+ else
+ pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
+ pOutDev->DrawRect( maPage1Rect );
+ }
+ if ( (nDrawFlags & SCRBAR_DRAW_PAGE2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE2 ) ) )
+ {
+ if ( mnStateFlags & SCRBAR_STATE_PAGE2_DOWN )
+ pOutDev->SetFillColor( rStyleSettings.GetShadowColor() );
+ else
+ pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
+ pOutDev->DrawRect( maPage2Rect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long ScrollBar::ImplScroll( long nNewPos, BOOL bCallEndScroll )
+{
+ long nOldPos = mnThumbPos;
+ SetThumbPos( nNewPos );
+ long nDelta = mnThumbPos-nOldPos;
+ if ( nDelta )
+ {
+ mnDelta = nDelta;
+ Scroll();
+ if ( bCallEndScroll )
+ EndScroll();
+ mnDelta = 0;
+ }
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+long ScrollBar::ImplDoAction( BOOL bCallEndScroll )
+{
+ long nDelta = 0;
+
+ switch ( meScrollType )
+ {
+ case SCROLL_LINEUP:
+ nDelta = ImplScroll( mnThumbPos-mnLineSize, bCallEndScroll );
+ break;
+
+ case SCROLL_LINEDOWN:
+ nDelta = ImplScroll( mnThumbPos+mnLineSize, bCallEndScroll );
+ break;
+
+ case SCROLL_PAGEUP:
+ nDelta = ImplScroll( mnThumbPos-mnPageSize, bCallEndScroll );
+ break;
+
+ case SCROLL_PAGEDOWN:
+ nDelta = ImplScroll( mnThumbPos+mnPageSize, bCallEndScroll );
+ break;
+ default:
+ ;
+ }
+
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::ImplDoMouseAction( const Point& rMousePos, BOOL bCallAction )
+{
+ USHORT nOldStateFlags = mnStateFlags;
+ BOOL bAction = FALSE;
+ BOOL bHorizontal = ( GetStyle() & WB_HORZ )? TRUE: FALSE;
+ BOOL bIsInside = FALSE;
+
+ Point aPoint( 0, 0 );
+ Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
+
+ switch ( meScrollType )
+ {
+ case SCROLL_LINEUP:
+ if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
+ aControlRegion, rMousePos, bIsInside )?
+ bIsInside:
+ maBtn1Rect.IsInside( rMousePos ) )
+ {
+ bAction = bCallAction;
+ mnStateFlags |= SCRBAR_STATE_BTN1_DOWN;
+ }
+ else
+ mnStateFlags &= ~SCRBAR_STATE_BTN1_DOWN;
+ break;
+
+ case SCROLL_LINEDOWN:
+ if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
+ aControlRegion, rMousePos, bIsInside )?
+ bIsInside:
+ maBtn2Rect.IsInside( rMousePos ) )
+ {
+ bAction = bCallAction;
+ mnStateFlags |= SCRBAR_STATE_BTN2_DOWN;
+ }
+ else
+ mnStateFlags &= ~SCRBAR_STATE_BTN2_DOWN;
+ break;
+
+ case SCROLL_PAGEUP:
+ // HitTestNativeControl, see remark at top of file
+ if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT: PART_TRACK_VERT_UPPER,
+ maPage1Rect, rMousePos, bIsInside )?
+ bIsInside:
+ maPage1Rect.IsInside( rMousePos ) )
+ {
+ bAction = bCallAction;
+ mnStateFlags |= SCRBAR_STATE_PAGE1_DOWN;
+ }
+ else
+ mnStateFlags &= ~SCRBAR_STATE_PAGE1_DOWN;
+ break;
+
+ case SCROLL_PAGEDOWN:
+ // HitTestNativeControl, see remark at top of file
+ if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_RIGHT: PART_TRACK_VERT_LOWER,
+ maPage2Rect, rMousePos, bIsInside )?
+ bIsInside:
+ maPage2Rect.IsInside( rMousePos ) )
+ {
+ bAction = bCallAction;
+ mnStateFlags |= SCRBAR_STATE_PAGE2_DOWN;
+ }
+ else
+ mnStateFlags &= ~SCRBAR_STATE_PAGE2_DOWN;
+ break;
+ default:
+ ;
+ }
+
+ if ( nOldStateFlags != mnStateFlags )
+ ImplDraw( mnDragDraw, this );
+ if ( bAction )
+ ImplDoAction( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::ImplDragThumb( const Point& rMousePos )
+{
+ long nMovePix;
+ if ( GetStyle() & WB_HORZ )
+ nMovePix = rMousePos.X()-(maThumbRect.Left()+mnMouseOff);
+ else
+ nMovePix = rMousePos.Y()-(maThumbRect.Top()+mnMouseOff);
+
+ // move thumb if necessary
+ if ( nMovePix )
+ {
+ mnThumbPixPos += nMovePix;
+ if ( mnThumbPixPos < 0 )
+ mnThumbPixPos = 0;
+ if ( mnThumbPixPos > (mnThumbPixRange-mnThumbPixSize) )
+ mnThumbPixPos = mnThumbPixRange-mnThumbPixSize;
+ long nOldPos = mnThumbPos;
+ mnThumbPos = ImplCalcThumbPos( mnThumbPixPos );
+ ImplUpdateRects();
+ if ( mbFullDrag && (nOldPos != mnThumbPos) )
+ {
+ mnDelta = mnThumbPos-nOldPos;
+ Scroll();
+ mnDelta = 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() || rMEvt.IsMiddle() )
+ {
+ const Point& rMousePos = rMEvt.GetPosPixel();
+ USHORT nTrackFlags = 0;
+ BOOL bHorizontal = ( GetStyle() & WB_HORZ )? TRUE: FALSE;
+ BOOL bIsInside = FALSE;
+ BOOL bDragToMouse = FALSE;
+
+ Point aPoint( 0, 0 );
+ Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
+
+ if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
+ aControlRegion, rMousePos, bIsInside )?
+ bIsInside:
+ maBtn1Rect.IsInside( rMousePos ) )
+ {
+ if ( !(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) )
+ {
+ nTrackFlags = STARTTRACK_BUTTONREPEAT;
+ meScrollType = SCROLL_LINEUP;
+ mnDragDraw = SCRBAR_DRAW_BTN1;
+ }
+ else
+ Sound::Beep( SOUND_DISABLE, this );
+ }
+ else if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
+ aControlRegion, rMousePos, bIsInside )?
+ bIsInside:
+ maBtn2Rect.IsInside( rMousePos ) )
+ {
+ if ( !(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) )
+ {
+ nTrackFlags = STARTTRACK_BUTTONREPEAT;
+ meScrollType = SCROLL_LINEDOWN;
+ mnDragDraw = SCRBAR_DRAW_BTN2;
+ }
+ else
+ Sound::Beep( SOUND_DISABLE, this );
+ }
+ else
+ {
+ bool bThumbHit = HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_THUMB_HORZ : PART_THUMB_VERT,
+ maThumbRect, rMousePos, bIsInside )
+ ? bIsInside : maThumbRect.IsInside( rMousePos );
+ bool bDragHandling = rMEvt.IsMiddle() || bThumbHit || ImplGetSVData()->maNWFData.mbScrollbarJumpPage;
+ if( bDragHandling )
+ {
+ if( mpData )
+ {
+ mpData->mbHide = TRUE; // disable focus blinking
+ if( HasFocus() )
+ ImplDraw( SCRBAR_DRAW_THUMB, this ); // paint without focus
+ }
+
+ if ( mnVisibleSize < mnMaxRange-mnMinRange )
+ {
+ nTrackFlags = 0;
+ meScrollType = SCROLL_DRAG;
+ mnDragDraw = SCRBAR_DRAW_THUMB;
+
+ // calculate mouse offset
+ if( rMEvt.IsMiddle() || (ImplGetSVData()->maNWFData.mbScrollbarJumpPage && !bThumbHit) )
+ {
+ bDragToMouse = TRUE;
+ if ( GetStyle() & WB_HORZ )
+ mnMouseOff = maThumbRect.GetWidth()/2;
+ else
+ mnMouseOff = maThumbRect.GetHeight()/2;
+ }
+ else
+ {
+ if ( GetStyle() & WB_HORZ )
+ mnMouseOff = rMousePos.X()-maThumbRect.Left();
+ else
+ mnMouseOff = rMousePos.Y()-maThumbRect.Top();
+ }
+
+ mnStateFlags |= SCRBAR_STATE_THUMB_DOWN;
+ ImplDraw( mnDragDraw, this );
+ }
+ else
+ Sound::Beep( SOUND_DISABLE, this );
+ }
+ else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_AREA : PART_TRACK_VERT_AREA,
+ aControlRegion, rMousePos, bIsInside )?
+ bIsInside : TRUE )
+ {
+ nTrackFlags = STARTTRACK_BUTTONREPEAT;
+
+ // HitTestNativeControl, see remark at top of file
+ if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER,
+ maPage1Rect, rMousePos, bIsInside )?
+ bIsInside:
+ maPage1Rect.IsInside( rMousePos ) )
+ {
+ meScrollType = SCROLL_PAGEUP;
+ mnDragDraw = SCRBAR_DRAW_PAGE1;
+ }
+ else
+ {
+ meScrollType = SCROLL_PAGEDOWN;
+ mnDragDraw = SCRBAR_DRAW_PAGE2;
+ }
+ }
+ }
+
+ // Soll Tracking gestartet werden
+ if ( meScrollType != SCROLL_DONTKNOW )
+ {
+ // remember original position in case of abort or EndScroll-Delta
+ mnStartPos = mnThumbPos;
+ // #92906# Call StartTracking() before ImplDoMouseAction(), otherwise
+ // MouseButtonUp() / EndTracking() may be called if somebody is spending
+ // a lot of time in the scroll handler
+ StartTracking( nTrackFlags );
+ ImplDoMouseAction( rMousePos );
+
+ if( bDragToMouse )
+ ImplDragThumb( rMousePos );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::Tracking( const TrackingEvent& rTEvt )
+{
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ // Button und PageRect-Status wieder herstellen
+ USHORT nOldStateFlags = mnStateFlags;
+ mnStateFlags &= ~(SCRBAR_STATE_BTN1_DOWN | SCRBAR_STATE_BTN2_DOWN |
+ SCRBAR_STATE_PAGE1_DOWN | SCRBAR_STATE_PAGE2_DOWN |
+ SCRBAR_STATE_THUMB_DOWN);
+ if ( nOldStateFlags != mnStateFlags )
+ ImplDraw( mnDragDraw, this );
+ mnDragDraw = 0;
+
+ // Bei Abbruch, die alte ThumbPosition wieder herstellen
+ if ( rTEvt.IsTrackingCanceled() )
+ {
+ long nOldPos = mnThumbPos;
+ SetThumbPos( mnStartPos );
+ mnDelta = mnThumbPos-nOldPos;
+ Scroll();
+ }
+
+ if ( meScrollType == SCROLL_DRAG )
+ {
+ // Wenn gedragt wurde, berechnen wir den Thumb neu, damit
+ // er wieder auf einer gerundeten ThumbPosition steht
+ ImplCalc();
+
+ if ( !mbFullDrag && (mnStartPos != mnThumbPos) )
+ {
+ mnDelta = mnThumbPos-mnStartPos;
+ Scroll();
+ mnDelta = 0;
+ }
+ }
+
+ mnDelta = mnThumbPos-mnStartPos;
+ EndScroll();
+ mnDelta = 0;
+ meScrollType = SCROLL_DONTKNOW;
+
+ if( mpData )
+ mpData->mbHide = FALSE; // re-enable focus blinking
+ }
+ else
+ {
+ const Point rMousePos = rTEvt.GetMouseEvent().GetPosPixel();
+
+ // Dragging wird speziell behandelt
+ if ( meScrollType == SCROLL_DRAG )
+ ImplDragThumb( rMousePos );
+ else
+ ImplDoMouseAction( rMousePos, rTEvt.IsTrackingRepeat() );
+
+ // Wenn ScrollBar-Werte so umgesetzt wurden, das es nichts
+ // mehr zum Tracking gibt, dann berechen wir hier ab
+ if ( !IsVisible() || (mnVisibleSize >= (mnMaxRange-mnMinRange)) )
+ EndTracking();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::KeyInput( const KeyEvent& rKEvt )
+{
+ if ( !rKEvt.GetKeyCode().GetModifier() )
+ {
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_HOME:
+ DoScroll( 0 );
+ break;
+
+ case KEY_END:
+ DoScroll( GetRangeMax() );
+ break;
+
+ case KEY_LEFT:
+ case KEY_UP:
+ DoScrollAction( SCROLL_LINEUP );
+ break;
+
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ DoScrollAction( SCROLL_LINEDOWN );
+ break;
+
+ case KEY_PAGEUP:
+ DoScrollAction( SCROLL_PAGEUP );
+ break;
+
+ case KEY_PAGEDOWN:
+ DoScrollAction( SCROLL_PAGEDOWN );
+ break;
+
+ default:
+ Control::KeyInput( rKEvt );
+ break;
+ }
+ }
+ else
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::Paint( const Rectangle& )
+{
+ ImplDraw( SCRBAR_DRAW_ALL, this );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::Resize()
+{
+ Control::Resize();
+ mbCalcSize = TRUE;
+ if ( IsReallyVisible() )
+ ImplCalc( FALSE );
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ScrollBar, ImplAutoTimerHdl, AutoTimer*, EMPTYARG )
+{
+ if( mpData && mpData->mbHide )
+ return 0;
+ ImplInvert();
+ return 0;
+}
+
+void ScrollBar::ImplInvert()
+{
+ Rectangle aRect( maThumbRect );
+ if( aRect.getWidth() > 4 )
+ {
+ aRect.Left() += 2;
+ aRect.Right() -= 2;
+ }
+ if( aRect.getHeight() > 4 )
+ {
+ aRect.Top() += 2;
+ aRect.Bottom() -= 2;
+ }
+
+ Invert( aRect, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::GetFocus()
+{
+ if( !mpData )
+ {
+ mpData = new ImplScrollBarData;
+ mpData->maTimer.SetTimeoutHdl( LINK( this, ScrollBar, ImplAutoTimerHdl ) );
+ mpData->mbHide = FALSE;
+ }
+ ImplInvert(); // react immediately
+ mpData->maTimer.SetTimeout( GetSettings().GetStyleSettings().GetCursorBlinkTime() );
+ mpData->maTimer.Start();
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::LoseFocus()
+{
+ if( mpData )
+ mpData->maTimer.Stop();
+ ImplDraw( SCRBAR_DRAW_THUMB, this );
+
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ ImplCalc( FALSE );
+ else if ( nType == STATE_CHANGE_DATA )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ ImplCalc( TRUE );
+ }
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ ImplCalc( FALSE );
+ Invalidate();
+ }
+ }
+ else if ( nType == STATE_CHANGE_ENABLE )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ ImplInitStyle( GetStyle() );
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ if ( (GetPrevStyle() & SCRBAR_VIEW_STYLE) !=
+ (GetStyle() & SCRBAR_VIEW_STYLE) )
+ {
+ mbCalcSize = TRUE;
+ ImplCalc( FALSE );
+ Invalidate();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ mbCalcSize = TRUE;
+ ImplCalc( FALSE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle* ScrollBar::ImplFindPartRect( const Point& rPt )
+{
+ BOOL bHorizontal = ( GetStyle() & WB_HORZ )? TRUE: FALSE;
+ BOOL bIsInside = FALSE;
+
+ Point aPoint( 0, 0 );
+ Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
+
+ if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
+ aControlRegion, rPt, bIsInside )?
+ bIsInside:
+ maBtn1Rect.IsInside( rPt ) )
+ return &maBtn1Rect;
+ else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
+ aControlRegion, rPt, bIsInside )?
+ bIsInside:
+ maBtn2Rect.IsInside( rPt ) )
+ return &maBtn2Rect;
+ // HitTestNativeControl, see remark at top of file
+ else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER,
+ maPage1Rect, rPt, bIsInside)?
+ bIsInside:
+ maPage1Rect.IsInside( rPt ) )
+ return &maPage1Rect;
+ // HitTestNativeControl, see remark at top of file
+ else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER,
+ maPage2Rect, rPt, bIsInside)?
+ bIsInside:
+ maPage2Rect.IsInside( rPt ) )
+ return &maPage2Rect;
+ // HitTestNativeControl, see remark at top of file
+ else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal ? PART_THUMB_HORZ : PART_THUMB_VERT,
+ maThumbRect, rPt, bIsInside)?
+ bIsInside:
+ maThumbRect.IsInside( rPt ) )
+ return &maThumbRect;
+ else
+ return NULL;
+}
+
+long ScrollBar::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL) )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
+ if( pRect != pLastRect || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
+ {
+ Region aRgn( GetActiveClipRegion() );
+ Region aClipRegion;
+
+ if ( pRect )
+ aClipRegion.Union( *pRect );
+ if ( pLastRect )
+ aClipRegion.Union( *pLastRect );
+
+ // Support for 3-button scroll bars
+ BOOL bHas3Buttons = IsNativeControlSupported( CTRL_SCROLLBAR, HAS_THREE_BUTTONS );
+ if ( bHas3Buttons && ( pRect == &maBtn1Rect || pLastRect == &maBtn1Rect ) )
+ {
+ aClipRegion.Union( maBtn2Rect );
+ }
+
+ SetClipRegion( aClipRegion );
+ Paint( aClipRegion.GetBoundRect() );
+
+ SetClipRegion( aRgn );
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Control::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::Scroll()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_SCROLL, maScrollHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::EndScroll()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_ENDSCROLL, maEndScrollHdl, this );
+}
+
+// -----------------------------------------------------------------------
+
+long ScrollBar::DoScroll( long nNewPos )
+{
+ if ( meScrollType != SCROLL_DONTKNOW )
+ return 0;
+
+ meScrollType = SCROLL_DRAG;
+ long nDelta = ImplScroll( nNewPos, TRUE );
+ meScrollType = SCROLL_DONTKNOW;
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+long ScrollBar::DoScrollAction( ScrollType eScrollType )
+{
+ if ( (meScrollType != SCROLL_DONTKNOW) ||
+ (eScrollType == SCROLL_DONTKNOW) ||
+ (eScrollType == SCROLL_DRAG) )
+ return 0;
+
+ meScrollType = eScrollType;
+ long nDelta = ImplDoAction( TRUE );
+ meScrollType = SCROLL_DONTKNOW;
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::SetRangeMin( long nNewRange )
+{
+ SetRange( Range( nNewRange, GetRangeMax() ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::SetRangeMax( long nNewRange )
+{
+ SetRange( Range( GetRangeMin(), nNewRange ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::SetRange( const Range& rRange )
+{
+ // Range einpassen
+ Range aRange = rRange;
+ aRange.Justify();
+ long nNewMinRange = aRange.Min();
+ long nNewMaxRange = aRange.Max();
+
+ // Wenn Range sich unterscheidet, dann neuen setzen
+ if ( (mnMinRange != nNewMinRange) ||
+ (mnMaxRange != nNewMaxRange) )
+ {
+ mnMinRange = nNewMinRange;
+ mnMaxRange = nNewMaxRange;
+
+ // Thumb einpassen
+ if ( mnThumbPos > mnMaxRange-mnVisibleSize )
+ mnThumbPos = mnMaxRange-mnVisibleSize;
+ if ( mnThumbPos < mnMinRange )
+ mnThumbPos = mnMinRange;
+
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::SetThumbPos( long nNewThumbPos )
+{
+ if ( nNewThumbPos > mnMaxRange-mnVisibleSize )
+ nNewThumbPos = mnMaxRange-mnVisibleSize;
+ if ( nNewThumbPos < mnMinRange )
+ nNewThumbPos = mnMinRange;
+
+ if ( mnThumbPos != nNewThumbPos )
+ {
+ mnThumbPos = nNewThumbPos;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBar::SetVisibleSize( long nNewSize )
+{
+ if ( mnVisibleSize != nNewSize )
+ {
+ mnVisibleSize = nNewSize;
+
+ // Thumb einpassen
+ if ( mnThumbPos > mnMaxRange-mnVisibleSize )
+ mnThumbPos = mnMaxRange-mnVisibleSize;
+ if ( mnThumbPos < mnMinRange )
+ mnThumbPos = mnMinRange;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// =======================================================================
+
+void ScrollBarBox::ImplInit( Window* pParent, WinBits nStyle )
+{
+ Window::ImplInit( pParent, nStyle, NULL );
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ long nScrollSize = rStyleSettings.GetScrollBarSize();
+ SetSizePixel( Size( nScrollSize, nScrollSize ) );
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+ScrollBarBox::ScrollBarBox( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_SCROLLBARBOX )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ScrollBarBox::ScrollBarBox( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_SCROLLBARBOX )
+{
+ rResId.SetRT( RSC_SCROLLBAR );
+ ImplInit( pParent, ImplInitRes( rResId ) );
+ ImplLoadRes( rResId );
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBarBox::ImplInitSettings()
+{
+ // Hack, damit man auch DockingWindows ohne Hintergrund bauen kann
+ // und noch nicht alles umgestellt ist
+ if ( IsBackground() )
+ {
+ Color aColor;
+ if ( IsControlBackground() )
+ aColor = GetControlBackground();
+ else
+ aColor = GetSettings().GetStyleSettings().GetFaceColor();
+ SetBackground( aColor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBarBox::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ScrollBarBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
diff --git a/vcl/source/control/slider.cxx b/vcl/source/control/slider.cxx
new file mode 100644
index 000000000000..daf733a57a33
--- /dev/null
+++ b/vcl/source/control/slider.cxx
@@ -0,0 +1,1089 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/event.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/slider.hxx>
+
+
+
+// =======================================================================
+
+static long ImplMulDiv( long nNumber, long nNumerator, long nDenominator )
+{
+ double n = ((double)nNumber * (double)nNumerator) / (double)nDenominator;
+ return (long)n;
+}
+
+// =======================================================================
+
+#define SLIDER_DRAW_THUMB ((USHORT)0x0001)
+#define SLIDER_DRAW_CHANNEL1 ((USHORT)0x0002)
+#define SLIDER_DRAW_CHANNEL2 ((USHORT)0x0004)
+#define SLIDER_DRAW_CHANNEL (SLIDER_DRAW_CHANNEL1 | SLIDER_DRAW_CHANNEL2)
+#define SLIDER_DRAW_ALL (SLIDER_DRAW_THUMB | SLIDER_DRAW_CHANNEL)
+
+#define SLIDER_STATE_CHANNEL1_DOWN ((USHORT)0x0001)
+#define SLIDER_STATE_CHANNEL2_DOWN ((USHORT)0x0002)
+#define SLIDER_STATE_THUMB_DOWN ((USHORT)0x0004)
+
+#define SLIDER_THUMB_SIZE 9
+#define SLIDER_THUMB_HALFSIZE 4
+#define SLIDER_CHANNEL_OFFSET 0
+#define SLIDER_CHANNEL_SIZE 4
+#define SLIDER_CHANNEL_HALFSIZE 2
+
+#define SLIDER_HEIGHT 16
+
+#define SLIDER_VIEW_STYLE (WB_3DLOOK | WB_HORZ | WB_VERT)
+
+// =======================================================================
+
+void Slider::ImplInit( Window* pParent, WinBits nStyle )
+{
+ mnThumbPixOffset = 0;
+ mnThumbPixRange = 0;
+ mnThumbPixPos = 0; // between mnThumbPixOffset and mnThumbPixOffset+mnThumbPixRange
+ mnChannelPixOffset = 0;
+ mnChannelPixRange = 0;
+ mnChannelPixTop = 0;
+ mnChannelPixBottom = 0;
+
+ mnMinRange = 0;
+ mnMaxRange = 100;
+ mnThumbPos = 0;
+ mnLineSize = 1;
+ mnPageSize = 1;
+ mnDelta = 0;
+ mnDragDraw = 0;
+ mnStateFlags = 0;
+ meScrollType = SCROLL_DONTKNOW;
+ mbCalcSize = TRUE;
+ mbFullDrag = TRUE;
+
+ Control::ImplInit( pParent, nStyle, NULL );
+
+ ImplInitSettings();
+ SetSizePixel( CalcWindowSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+Slider::Slider( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_SLIDER )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+Slider::Slider( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_SLIDER )
+{
+ rResId.SetRT( RSC_SCROLLBAR );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ INT16 nMin = ReadShortRes();
+ INT16 nMax = ReadShortRes();
+ INT16 nThumbPos = ReadShortRes();
+ INT16 nPage = ReadShortRes();
+ INT16 nStep = ReadShortRes();
+ /* INT16 nVisibleSize = */ ReadShortRes();
+
+ SetRange( Range( nMin, nMax ) );
+ SetLineSize( nStep );
+ SetPageSize( nPage );
+ SetThumbPos( nThumbPos );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::ImplInitSettings()
+{
+ Window* pParent = GetParent();
+ if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::ImplUpdateRects( BOOL bUpdate )
+{
+ Rectangle aOldThumbRect = maThumbRect;
+ bool bInvalidateAll = false;
+
+ if ( mnThumbPixRange )
+ {
+ if ( GetStyle() & WB_HORZ )
+ {
+ maThumbRect.Left() = mnThumbPixPos-SLIDER_THUMB_HALFSIZE;
+ maThumbRect.Right() = maThumbRect.Left()+SLIDER_THUMB_SIZE-1;
+ if ( mnChannelPixOffset < maThumbRect.Left() )
+ {
+ maChannel1Rect.Left() = mnChannelPixOffset;
+ maChannel1Rect.Right() = maThumbRect.Left()-1;
+ maChannel1Rect.Top() = mnChannelPixTop;
+ maChannel1Rect.Bottom() = mnChannelPixBottom;
+ }
+ else
+ maChannel1Rect.SetEmpty();
+ if ( mnChannelPixOffset+mnChannelPixRange-1 > maThumbRect.Right() )
+ {
+ maChannel2Rect.Left() = maThumbRect.Right()+1;
+ maChannel2Rect.Right() = mnChannelPixOffset+mnChannelPixRange-1;
+ maChannel2Rect.Top() = mnChannelPixTop;
+ maChannel2Rect.Bottom() = mnChannelPixBottom;
+ }
+ else
+ maChannel2Rect.SetEmpty();
+
+ const Rectangle aControlRegion( Rectangle( Point(0,0), Size( SLIDER_THUMB_SIZE, 10 ) ) );
+ Rectangle aThumbBounds, aThumbContent;
+ if ( GetNativeControlRegion( CTRL_SLIDER, PART_THUMB_HORZ,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(),
+ aThumbBounds, aThumbContent ) )
+ {
+ maThumbRect.Left() = mnThumbPixPos - aThumbBounds.GetWidth()/2;
+ maThumbRect.Right() = maThumbRect.Left() + aThumbBounds.GetWidth() - 1;
+ bInvalidateAll = true;
+ }
+ }
+ else
+ {
+ maThumbRect.Top() = mnThumbPixPos-SLIDER_THUMB_HALFSIZE;
+ maThumbRect.Bottom() = maThumbRect.Top()+SLIDER_THUMB_SIZE-1;
+ if ( mnChannelPixOffset < maThumbRect.Top() )
+ {
+ maChannel1Rect.Top() = mnChannelPixOffset;
+ maChannel1Rect.Bottom() = maThumbRect.Top()-1;
+ maChannel1Rect.Left() = mnChannelPixTop;
+ maChannel1Rect.Right() = mnChannelPixBottom;
+ }
+ else
+ maChannel1Rect.SetEmpty();
+ if ( mnChannelPixOffset+mnChannelPixRange-1 > maThumbRect.Bottom() )
+ {
+ maChannel2Rect.Top() = maThumbRect.Bottom()+1;
+ maChannel2Rect.Bottom() = mnChannelPixOffset+mnChannelPixRange-1;
+ maChannel2Rect.Left() = mnChannelPixTop;
+ maChannel2Rect.Right() = mnChannelPixBottom;
+ }
+ else
+ maChannel2Rect.SetEmpty();
+
+ const Rectangle aControlRegion( Rectangle( Point(0,0), Size( 10, SLIDER_THUMB_SIZE ) ) );
+ Rectangle aThumbBounds, aThumbContent;
+ if ( GetNativeControlRegion( CTRL_SLIDER, PART_THUMB_VERT,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(),
+ aThumbBounds, aThumbContent ) )
+ {
+ maThumbRect.Top() = mnThumbPixPos - aThumbBounds.GetHeight()/2;
+ maThumbRect.Bottom() = maThumbRect.Top() + aThumbBounds.GetHeight() - 1;
+ bInvalidateAll = true;
+ }
+ }
+ }
+ else
+ {
+ maChannel1Rect.SetEmpty();
+ maChannel2Rect.SetEmpty();
+ maThumbRect.SetEmpty();
+ }
+
+ if ( bUpdate )
+ {
+ if ( aOldThumbRect != maThumbRect )
+ {
+ if( bInvalidateAll )
+ Invalidate();
+ else
+ {
+ Region aInvalidRegion( aOldThumbRect );
+ aInvalidRegion.Union( maThumbRect );
+
+ if( !IsBackground() && GetParent() )
+ {
+ const Point aPos( GetPosPixel() );
+ aInvalidRegion.Move( aPos.X(), aPos.Y() );
+ GetParent()->Invalidate( aInvalidRegion, INVALIDATE_TRANSPARENT | INVALIDATE_UPDATE );
+ }
+ else
+ Invalidate( aInvalidRegion );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long Slider::ImplCalcThumbPos( long nPixPos )
+{
+ // Position berechnen
+ long nCalcThumbPos;
+ nCalcThumbPos = ImplMulDiv( nPixPos-mnThumbPixOffset, mnMaxRange-mnMinRange, mnThumbPixRange-1 );
+ nCalcThumbPos += mnMinRange;
+ return nCalcThumbPos;
+}
+
+// -----------------------------------------------------------------------
+
+long Slider::ImplCalcThumbPosPix( long nPos )
+{
+ // Position berechnen
+ long nCalcThumbPos;
+ nCalcThumbPos = ImplMulDiv( nPos-mnMinRange, mnThumbPixRange-1, mnMaxRange-mnMinRange );
+ // Am Anfang und Ende des Sliders versuchen wir die Anzeige korrekt
+ // anzuzeigen
+ if ( !nCalcThumbPos && (mnThumbPos > mnMinRange) )
+ nCalcThumbPos = 1;
+ if ( nCalcThumbPos &&
+ (nCalcThumbPos == mnThumbPixRange-1) &&
+ (mnThumbPos < mnMaxRange) )
+ nCalcThumbPos--;
+ return nCalcThumbPos+mnThumbPixOffset;
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::ImplCalc( BOOL bUpdate )
+{
+ BOOL bInvalidateAll = FALSE;
+
+ if ( mbCalcSize )
+ {
+ long nOldChannelPixOffset = mnChannelPixOffset;
+ long nOldChannelPixRange = mnChannelPixRange;
+ long nOldChannelPixTop = mnChannelPixTop;
+ long nOldChannelPixBottom = mnChannelPixBottom;
+ long nCalcWidth;
+ long nCalcHeight;
+
+ maChannel1Rect.SetEmpty();
+ maChannel2Rect.SetEmpty();
+ maThumbRect.SetEmpty();
+
+ Size aSize = GetOutputSizePixel();
+ if ( GetStyle() & WB_HORZ )
+ {
+ nCalcWidth = aSize.Width();
+ nCalcHeight = aSize.Height();
+ maThumbRect.Top() = 0;
+ maThumbRect.Bottom()= aSize.Height()-1;
+ }
+ else
+ {
+ nCalcWidth = aSize.Height();
+ nCalcHeight = aSize.Width();
+ maThumbRect.Left() = 0;
+ maThumbRect.Right() = aSize.Width()-1;
+ }
+
+ if ( nCalcWidth >= SLIDER_THUMB_SIZE )
+ {
+ mnThumbPixOffset = SLIDER_THUMB_HALFSIZE;
+ mnThumbPixRange = nCalcWidth-(SLIDER_THUMB_HALFSIZE*2);
+ mnThumbPixPos = 0;
+ mnChannelPixOffset = SLIDER_CHANNEL_OFFSET;
+ mnChannelPixRange = nCalcWidth-(SLIDER_CHANNEL_OFFSET*2);
+ mnChannelPixTop = (nCalcHeight/2)-SLIDER_CHANNEL_HALFSIZE;
+ mnChannelPixBottom = mnChannelPixTop+SLIDER_CHANNEL_SIZE-1;
+ }
+ else
+ {
+ mnThumbPixRange = 0;
+ mnChannelPixRange = 0;
+ }
+
+ if ( (nOldChannelPixOffset != mnChannelPixOffset) ||
+ (nOldChannelPixRange != mnChannelPixRange) ||
+ (nOldChannelPixTop != mnChannelPixTop) ||
+ (nOldChannelPixBottom != mnChannelPixBottom) )
+ bInvalidateAll = TRUE;
+
+ mbCalcSize = FALSE;
+ }
+
+ if ( mnThumbPixRange )
+ mnThumbPixPos = ImplCalcThumbPosPix( mnThumbPos );
+
+ if ( bUpdate && bInvalidateAll )
+ {
+ Invalidate();
+ bUpdate = FALSE;
+ }
+ ImplUpdateRects( bUpdate );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::ImplDraw( USHORT nDrawFlags )
+{
+ DecorationView aDecoView( this );
+ USHORT nStyle;
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ BOOL bEnabled = IsEnabled();
+
+ // Evt. noch offene Berechnungen nachholen
+ if ( mbCalcSize )
+ ImplCalc( FALSE );
+
+ ControlPart nPart = (GetStyle() & WB_HORZ) ? PART_TRACK_HORZ_AREA : PART_TRACK_VERT_AREA;
+ ControlState nState = ( IsEnabled() ? CTRL_STATE_ENABLED : 0 ) | ( HasFocus() ? CTRL_STATE_FOCUSED : 0 );
+ SliderValue sldValue;
+
+ sldValue.mnMin = mnMinRange;
+ sldValue.mnMax = mnMaxRange;
+ sldValue.mnCur = mnThumbPos;
+ sldValue.maThumbRect = maThumbRect;
+
+ if( IsMouseOver() )
+ {
+ if( maThumbRect.IsInside( GetPointerPosPixel() ) )
+ sldValue.mnThumbState |= CTRL_STATE_ROLLOVER;
+ }
+
+ const Rectangle aCtrlRegion( Point(0,0), GetOutputSizePixel() );
+ bool bNativeOK = DrawNativeControl( CTRL_SLIDER, nPart,
+ aCtrlRegion, nState, sldValue, rtl::OUString() );
+ if( bNativeOK )
+ return;
+
+ if ( (nDrawFlags & SLIDER_DRAW_CHANNEL1) && !maChannel1Rect.IsEmpty() )
+ {
+ long nRectSize;
+ Rectangle aRect = maChannel1Rect;
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ if ( GetStyle() & WB_HORZ )
+ {
+ DrawLine( aRect.TopLeft(), Point( aRect.Left(), aRect.Bottom()-1 ) );
+ DrawLine( aRect.TopLeft(), aRect.TopRight() );
+ }
+ else
+ {
+ DrawLine( aRect.TopLeft(), Point( aRect.Right()-1, aRect.Top() ) );
+ DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
+ }
+ SetLineColor( rStyleSettings.GetLightColor() );
+ if ( GetStyle() & WB_HORZ )
+ {
+ DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ nRectSize = aRect.GetWidth();
+ }
+ else
+ {
+ DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ nRectSize = aRect.GetHeight();
+ }
+
+ if ( nRectSize > 1 )
+ {
+ aRect.Left()++;
+ aRect.Top()++;
+ if ( GetStyle() & WB_HORZ )
+ aRect.Bottom()--;
+ else
+ aRect.Right()--;
+ SetLineColor();
+ if ( mnStateFlags & SLIDER_STATE_CHANNEL1_DOWN )
+ SetFillColor( rStyleSettings.GetShadowColor() );
+ else
+ SetFillColor( rStyleSettings.GetCheckedColor() );
+ DrawRect( aRect );
+ }
+ }
+
+ if ( (nDrawFlags & SLIDER_DRAW_CHANNEL2) && !maChannel2Rect.IsEmpty() )
+ {
+ long nRectSize;
+ Rectangle aRect = maChannel2Rect;
+ SetLineColor( rStyleSettings.GetLightColor() );
+ if ( GetStyle() & WB_HORZ )
+ {
+ DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ nRectSize = aRect.GetWidth();
+ }
+ else
+ {
+ DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ nRectSize = aRect.GetHeight();
+ }
+
+ if ( nRectSize > 1 )
+ {
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ if ( GetStyle() & WB_HORZ )
+ DrawLine( aRect.TopLeft(), Point( aRect.Right()-1, aRect.Top() ) );
+ else
+ DrawLine( aRect.TopLeft(), Point( aRect.Left(), aRect.Bottom()-1 ) );
+
+ aRect.Right()--;
+ aRect.Bottom()--;
+ if ( GetStyle() & WB_HORZ )
+ aRect.Top()++;
+ else
+ aRect.Left()++;
+ SetLineColor();
+ if ( mnStateFlags & SLIDER_STATE_CHANNEL2_DOWN )
+ SetFillColor( rStyleSettings.GetShadowColor() );
+ else
+ SetFillColor( rStyleSettings.GetCheckedColor() );
+ DrawRect( aRect );
+ }
+ }
+
+ if ( nDrawFlags & SLIDER_DRAW_THUMB )
+ {
+ if ( !maThumbRect.IsEmpty() )
+ {
+ if ( bEnabled )
+ {
+ nStyle = 0;
+ if ( mnStateFlags & SLIDER_STATE_THUMB_DOWN )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ aDecoView.DrawButton( maThumbRect, nStyle );
+ }
+ else
+ {
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ SetFillColor( rStyleSettings.GetCheckedColor() );
+ DrawRect( maThumbRect );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Slider::ImplIsPageUp( const Point& rPos )
+{
+ Size aSize = GetOutputSizePixel();
+ Rectangle aRect = maChannel1Rect;
+ if ( GetStyle() & WB_HORZ )
+ {
+ aRect.Top() = 0;
+ aRect.Bottom() = aSize.Height()-1;
+ }
+ else
+ {
+ aRect.Left() = 0;
+ aRect.Right() = aSize.Width()-1;
+ }
+ return aRect.IsInside( rPos );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Slider::ImplIsPageDown( const Point& rPos )
+{
+ Size aSize = GetOutputSizePixel();
+ Rectangle aRect = maChannel2Rect;
+ if ( GetStyle() & WB_HORZ )
+ {
+ aRect.Top() = 0;
+ aRect.Bottom() = aSize.Height()-1;
+ }
+ else
+ {
+ aRect.Left() = 0;
+ aRect.Right() = aSize.Width()-1;
+ }
+ return aRect.IsInside( rPos );
+}
+
+// -----------------------------------------------------------------------
+
+long Slider::ImplSlide( long nNewPos, BOOL bCallEndSlide )
+{
+ long nOldPos = mnThumbPos;
+ SetThumbPos( nNewPos );
+ long nDelta = mnThumbPos-nOldPos;
+ if ( nDelta )
+ {
+ mnDelta = nDelta;
+ Slide();
+ if ( bCallEndSlide )
+ EndSlide();
+ mnDelta = 0;
+ }
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+long Slider::ImplDoAction( BOOL bCallEndSlide )
+{
+ long nDelta = 0;
+
+ switch ( meScrollType )
+ {
+ case SCROLL_LINEUP:
+ nDelta = ImplSlide( mnThumbPos-mnLineSize, bCallEndSlide );
+ break;
+
+ case SCROLL_LINEDOWN:
+ nDelta = ImplSlide( mnThumbPos+mnLineSize, bCallEndSlide );
+ break;
+
+ case SCROLL_PAGEUP:
+ nDelta = ImplSlide( mnThumbPos-mnPageSize, bCallEndSlide );
+ break;
+
+ case SCROLL_PAGEDOWN:
+ nDelta = ImplSlide( mnThumbPos+mnPageSize, bCallEndSlide );
+ break;
+
+ case SCROLL_SET:
+ nDelta = ImplSlide( ImplCalcThumbPos( GetPointerPosPixel().X() ), bCallEndSlide );
+ break;
+ default:
+ break;
+ }
+
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::ImplDoMouseAction( const Point& rMousePos, BOOL bCallAction )
+{
+ USHORT nOldStateFlags = mnStateFlags;
+ BOOL bAction = FALSE;
+
+ switch ( meScrollType )
+ {
+ case( SCROLL_SET ):
+ {
+ const bool bUp = ImplIsPageUp( rMousePos ), bDown = ImplIsPageDown( rMousePos );
+
+ if ( bUp || bDown )
+ {
+ bAction = bCallAction;
+ mnStateFlags |= ( bUp ? SLIDER_STATE_CHANNEL1_DOWN : SLIDER_STATE_CHANNEL2_DOWN );
+ }
+ else
+ mnStateFlags &= ~( SLIDER_STATE_CHANNEL1_DOWN | SLIDER_STATE_CHANNEL2_DOWN );
+ break;
+ }
+
+ case SCROLL_PAGEUP:
+ if ( ImplIsPageUp( rMousePos ) )
+ {
+ bAction = bCallAction;
+ mnStateFlags |= SLIDER_STATE_CHANNEL1_DOWN;
+ }
+ else
+ mnStateFlags &= ~SLIDER_STATE_CHANNEL1_DOWN;
+ break;
+
+ case SCROLL_PAGEDOWN:
+ if ( ImplIsPageDown( rMousePos ) )
+ {
+ bAction = bCallAction;
+ mnStateFlags |= SLIDER_STATE_CHANNEL2_DOWN;
+ }
+ else
+ mnStateFlags &= ~SLIDER_STATE_CHANNEL2_DOWN;
+ break;
+ default:
+ break;
+ }
+
+ if ( bAction )
+ {
+ if ( ImplDoAction( FALSE ) )
+ {
+ // Update the channel complete
+ if ( mnDragDraw & SLIDER_DRAW_CHANNEL )
+ {
+ Update();
+ ImplDraw( mnDragDraw );
+ }
+ }
+ }
+ else if ( nOldStateFlags != mnStateFlags )
+ ImplDraw( mnDragDraw );
+}
+
+// -----------------------------------------------------------------------
+
+long Slider::ImplDoSlide( long nNewPos )
+{
+ if ( meScrollType != SCROLL_DONTKNOW )
+ return 0;
+
+ meScrollType = SCROLL_DRAG;
+ long nDelta = ImplSlide( nNewPos, TRUE );
+ meScrollType = SCROLL_DONTKNOW;
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+long Slider::ImplDoSlideAction( ScrollType eScrollType )
+{
+ if ( (meScrollType != SCROLL_DONTKNOW) ||
+ (eScrollType == SCROLL_DONTKNOW) ||
+ (eScrollType == SCROLL_DRAG) )
+ return 0;
+
+ meScrollType = eScrollType;
+ long nDelta = ImplDoAction( TRUE );
+ meScrollType = SCROLL_DONTKNOW;
+ return nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() )
+ {
+ const Point& rMousePos = rMEvt.GetPosPixel();
+ USHORT nTrackFlags = 0;
+
+ if ( maThumbRect.IsInside( rMousePos ) )
+ {
+ nTrackFlags = 0;
+ meScrollType = SCROLL_DRAG;
+ mnDragDraw = SLIDER_DRAW_THUMB;
+
+ // Zusaetzliche Daten berechnen
+ Point aCenterPos = maThumbRect.Center();
+ if ( GetStyle() & WB_HORZ )
+ mnMouseOff = rMousePos.X()-aCenterPos.X();
+ else
+ mnMouseOff = rMousePos.Y()-aCenterPos.Y();
+
+ // Im OS2-Look geben wir den Thumb gedrueckt aus
+ if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_OS2STYLE )
+ {
+ mnStateFlags |= SLIDER_STATE_THUMB_DOWN;
+ ImplDraw( SLIDER_DRAW_THUMB );
+ }
+ }
+ else if ( ImplIsPageUp( rMousePos ) )
+ {
+ if( GetStyle() & WB_SLIDERSET )
+ meScrollType = SCROLL_SET;
+ else
+ {
+ nTrackFlags = STARTTRACK_BUTTONREPEAT;
+ meScrollType = SCROLL_PAGEUP;
+ }
+
+ mnDragDraw = SLIDER_DRAW_CHANNEL;
+ }
+ else if ( ImplIsPageDown( rMousePos ) )
+ {
+ if( GetStyle() & WB_SLIDERSET )
+ meScrollType = SCROLL_SET;
+ else
+ {
+ nTrackFlags = STARTTRACK_BUTTONREPEAT;
+ meScrollType = SCROLL_PAGEDOWN;
+ }
+
+ mnDragDraw = SLIDER_DRAW_CHANNEL;
+ }
+
+ // Soll Tracking gestartet werden
+ if( meScrollType != SCROLL_DONTKNOW )
+ {
+ // Startposition merken fuer Abbruch und EndScroll-Delta
+ mnStartPos = mnThumbPos;
+ ImplDoMouseAction( rMousePos, meScrollType != SCROLL_SET );
+ Update();
+
+ if( meScrollType != SCROLL_SET )
+ StartTracking( nTrackFlags );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::MouseButtonUp( const MouseEvent& )
+{
+ if( SCROLL_SET == meScrollType )
+ {
+ // Button und PageRect-Status wieder herstellen
+ const USHORT nOldStateFlags = mnStateFlags;
+
+ mnStateFlags &= ~( SLIDER_STATE_CHANNEL1_DOWN | SLIDER_STATE_CHANNEL2_DOWN | SLIDER_STATE_THUMB_DOWN );
+
+ if ( nOldStateFlags != mnStateFlags )
+ ImplDraw( mnDragDraw );
+
+ mnDragDraw = 0;
+ ImplDoAction( TRUE );
+ meScrollType = SCROLL_DONTKNOW;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::Tracking( const TrackingEvent& rTEvt )
+{
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ // Button und PageRect-Status wieder herstellen
+ USHORT nOldStateFlags = mnStateFlags;
+ mnStateFlags &= ~(SLIDER_STATE_CHANNEL1_DOWN | SLIDER_STATE_CHANNEL2_DOWN |
+ SLIDER_STATE_THUMB_DOWN);
+ if ( nOldStateFlags != mnStateFlags )
+ ImplDraw( mnDragDraw );
+ mnDragDraw = 0;
+
+ // Bei Abbruch, die alte ThumbPosition wieder herstellen
+ if ( rTEvt.IsTrackingCanceled() )
+ {
+ long nOldPos = mnThumbPos;
+ SetThumbPos( mnStartPos );
+ mnDelta = mnThumbPos-nOldPos;
+ Slide();
+ }
+
+ if ( meScrollType == SCROLL_DRAG )
+ {
+ // Wenn gedragt wurde, berechnen wir den Thumb neu, damit
+ // er wieder auf einer gerundeten ThumbPosition steht
+ ImplCalc();
+ Update();
+
+ if ( !mbFullDrag && (mnStartPos != mnThumbPos) )
+ {
+ mnDelta = mnThumbPos-mnStartPos;
+ Slide();
+ mnDelta = 0;
+ }
+ }
+
+ mnDelta = mnThumbPos-mnStartPos;
+ EndSlide();
+ mnDelta = 0;
+ meScrollType = SCROLL_DONTKNOW;
+ }
+ else
+ {
+ const Point rMousePos = rTEvt.GetMouseEvent().GetPosPixel();
+
+ // Dragging wird speziell behandelt
+ if ( meScrollType == SCROLL_DRAG )
+ {
+ long nMovePix;
+ Point aCenterPos = maThumbRect.Center();
+ if ( GetStyle() & WB_HORZ )
+ nMovePix = rMousePos.X()-(aCenterPos.X()+mnMouseOff);
+ else
+ nMovePix = rMousePos.Y()-(aCenterPos.Y()+mnMouseOff);
+ // Nur wenn sich Maus in die Scrollrichtung bewegt, muessen
+ // wir etwas tun
+ if ( nMovePix )
+ {
+ mnThumbPixPos += nMovePix;
+ if ( mnThumbPixPos < mnThumbPixOffset )
+ mnThumbPixPos = mnThumbPixOffset;
+ if ( mnThumbPixPos > (mnThumbPixOffset+mnThumbPixRange-1) )
+ mnThumbPixPos = mnThumbPixOffset+mnThumbPixRange-1;
+ long nOldPos = mnThumbPos;
+ mnThumbPos = ImplCalcThumbPos( mnThumbPixPos );
+ if ( nOldPos != mnThumbPos )
+ {
+ ImplUpdateRects();
+ Update();
+ if ( mbFullDrag && (nOldPos != mnThumbPos) )
+ {
+ mnDelta = mnThumbPos-nOldPos;
+ Slide();
+ mnDelta = 0;
+ }
+ }
+ }
+ }
+ else
+ ImplDoMouseAction( rMousePos, rTEvt.IsTrackingRepeat() );
+
+ // Wenn Slider-Werte so umgesetzt wurden, das es nichts
+ // mehr zum Tracking gibt, dann berechen wir hier ab
+ if ( !IsVisible() )
+ EndTracking();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::KeyInput( const KeyEvent& rKEvt )
+{
+ if ( !rKEvt.GetKeyCode().GetModifier() )
+ {
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_HOME:
+ ImplDoSlide( GetRangeMin() );
+ break;
+ case KEY_END:
+ ImplDoSlide( GetRangeMax() );
+ break;
+
+ case KEY_LEFT:
+ case KEY_UP:
+ ImplDoSlideAction( SCROLL_LINEUP );
+ break;
+
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ ImplDoSlideAction( SCROLL_LINEDOWN );
+ break;
+
+ case KEY_PAGEUP:
+ ImplDoSlideAction( SCROLL_PAGEUP );
+ break;
+
+ case KEY_PAGEDOWN:
+ ImplDoSlideAction( SCROLL_PAGEDOWN );
+ break;
+
+ default:
+ Control::KeyInput( rKEvt );
+ break;
+ }
+ }
+ else
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::Paint( const Rectangle& )
+{
+ ImplDraw( SLIDER_DRAW_ALL );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::Resize()
+{
+ Control::Resize();
+ mbCalcSize = TRUE;
+ if ( IsReallyVisible() )
+ ImplCalc( FALSE );
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::RequestHelp( const HelpEvent& rHEvt )
+{
+ Control::RequestHelp( rHEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ ImplCalc( FALSE );
+ else if ( nType == STATE_CHANGE_DATA )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ ImplCalc( TRUE );
+ }
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ ImplCalc( FALSE );
+ Invalidate();
+ }
+ }
+ else if ( nType == STATE_CHANGE_ENABLE )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ if ( (GetPrevStyle() & SLIDER_VIEW_STYLE) !=
+ (GetStyle() & SLIDER_VIEW_STYLE) )
+ {
+ mbCalcSize = TRUE;
+ ImplCalc( FALSE );
+ Invalidate();
+ }
+ }
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::Slide()
+{
+ maSlideHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::EndSlide()
+{
+ maEndSlideHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::SetRangeMin( long nNewRange )
+{
+ SetRange( Range( nNewRange, GetRangeMax() ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::SetRangeMax( long nNewRange )
+{
+ SetRange( Range( GetRangeMin(), nNewRange ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::SetRange( const Range& rRange )
+{
+ // Range einpassen
+ Range aRange = rRange;
+ aRange.Justify();
+ long nNewMinRange = aRange.Min();
+ long nNewMaxRange = aRange.Max();
+
+ // Wenn Range sich unterscheidet, dann neuen setzen
+ if ( (mnMinRange != nNewMinRange) ||
+ (mnMaxRange != nNewMaxRange) )
+ {
+ mnMinRange = nNewMinRange;
+ mnMaxRange = nNewMaxRange;
+
+ // Thumb einpassen
+ if ( mnThumbPos > mnMaxRange )
+ mnThumbPos = mnMaxRange;
+ if ( mnThumbPos < mnMinRange )
+ mnThumbPos = mnMinRange;
+
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Slider::SetThumbPos( long nNewThumbPos )
+{
+ if ( nNewThumbPos < mnMinRange )
+ nNewThumbPos = mnMinRange;
+ if ( nNewThumbPos > mnMaxRange )
+ nNewThumbPos = mnMaxRange;
+
+ if ( mnThumbPos != nNewThumbPos )
+ {
+ mnThumbPos = nNewThumbPos;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size Slider::CalcWindowSizePixel()
+{
+ long nWidth = mnMaxRange-mnMinRange+(SLIDER_THUMB_HALFSIZE*2)+1;
+ long nHeight = SLIDER_HEIGHT;
+ Size aSize;
+ if ( GetStyle() & WB_HORZ )
+ {
+ aSize.Width() = nWidth;
+ aSize.Height() = nHeight;
+ }
+ else
+ {
+ aSize.Height() = nWidth;
+ aSize.Width() = nHeight;
+ }
+ return aSize;
+}
diff --git a/vcl/source/control/spinbtn.cxx b/vcl/source/control/spinbtn.cxx
new file mode 100644
index 000000000000..921ba2a24e5a
--- /dev/null
+++ b/vcl/source/control/spinbtn.cxx
@@ -0,0 +1,550 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/rcid.h>
+#include <vcl/spin.h>
+#include <vcl/event.hxx>
+#include <vcl/spin.hxx>
+
+// =======================================================================
+
+void SpinButton::ImplInit( Window* pParent, WinBits nStyle )
+{
+ mbUpperIn = FALSE;
+ mbLowerIn = FALSE;
+ mbInitialUp = FALSE;
+ mbInitialDown = FALSE;
+
+ mnMinRange = 0;
+ mnMaxRange = 100;
+ mnValue = 0;
+ mnValueStep = 1;
+
+ maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+ maRepeatTimer.SetTimeoutHdl( LINK( this, SpinButton, ImplTimeout ) );
+
+ mbRepeat = 0 != ( nStyle & WB_REPEAT );
+
+ if ( nStyle & WB_HSCROLL )
+ mbHorz = TRUE;
+ else
+ mbHorz = FALSE;
+
+ Control::ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+SpinButton::SpinButton( Window* pParent, WinBits nStyle )
+ :Control( WINDOW_SPINBUTTON )
+ ,mbUpperIsFocused( FALSE )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+SpinButton::SpinButton( Window* pParent, const ResId& rResId )
+ :Control( WINDOW_SPINBUTTON )
+ ,mbUpperIsFocused( FALSE )
+{
+ rResId.SetRT( RSC_SPINBUTTON );
+ ImplInit( pParent, ImplInitRes( rResId ) );
+ ImplLoadRes( rResId );
+ Resize();
+}
+
+// -----------------------------------------------------------------------
+
+SpinButton::~SpinButton()
+{
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( SpinButton, ImplTimeout, Timer*, pTimer )
+{
+ if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
+ {
+ pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
+ pTimer->Start();
+ }
+ else
+ {
+ if ( mbInitialUp )
+ Up();
+ else
+ Down();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::Up()
+{
+ if ( ImplIsUpperEnabled() )
+ {
+ mnValue += mnValueStep;
+ StateChanged( STATE_CHANGE_DATA );
+
+ ImplMoveFocus( TRUE );
+ }
+
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINBUTTON_UP, maUpHdlLink, this );
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::Down()
+{
+ if ( ImplIsLowerEnabled() )
+ {
+ mnValue -= mnValueStep;
+ StateChanged( STATE_CHANGE_DATA );
+
+ ImplMoveFocus( FALSE );
+ }
+
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINBUTTON_DOWN, maDownHdlLink, this );
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::Resize()
+{
+ Control::Resize();
+
+ Size aSize( GetOutputSizePixel() );
+ Point aTmpPoint;
+ Rectangle aRect( aTmpPoint, aSize );
+ if ( mbHorz )
+ {
+ maLowerRect = Rectangle( 0, 0, aSize.Width()/2, aSize.Height()-1 );
+ maUpperRect = Rectangle( maLowerRect.TopRight(), aRect.BottomRight() );
+ }
+ else
+ {
+ maUpperRect = Rectangle( 0, 0, aSize.Width()-1, aSize.Height()/2 );
+ maLowerRect = Rectangle( maUpperRect.BottomLeft(), aRect.BottomRight() );
+ }
+
+ ImplCalcFocusRect( ImplIsUpperEnabled() || !ImplIsLowerEnabled() );
+
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+
+ pDev->Push();
+ pDev->SetMapMode();
+ if ( !(nFlags & WINDOW_DRAW_MONO) )
+ {
+ // DecoView uses the FaceColor...
+ AllSettings aSettings = pDev->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ if ( IsControlBackground() )
+ aStyleSettings.SetFaceColor( GetControlBackground() );
+ else
+ aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
+
+ aSettings.SetStyleSettings( aStyleSettings );
+ pDev->SetSettings( aSettings );
+ }
+
+ Rectangle aRect( Point( 0, 0 ), aSize );
+ Rectangle aLowerRect, aUpperRect;
+ if ( mbHorz )
+ {
+ aLowerRect = Rectangle( 0, 0, aSize.Width()/2, aSize.Height()-1 );
+ aUpperRect = Rectangle( aLowerRect.TopRight(), aRect.BottomRight() );
+ }
+ else
+ {
+ aUpperRect = Rectangle( 0, 0, aSize.Width()-1, aSize.Height()/2 );
+ aLowerRect = Rectangle( aUpperRect.BottomLeft(), aRect.BottomRight() );
+ }
+
+ aUpperRect += aPos;
+ aLowerRect += aPos;
+
+ ImplDrawSpinButton( pDev, aUpperRect, aLowerRect, FALSE, FALSE,
+ IsEnabled() && ImplIsUpperEnabled(),
+ IsEnabled() && ImplIsLowerEnabled(), mbHorz, TRUE );
+ pDev->Pop();
+}
+
+
+void SpinButton::Paint( const Rectangle& )
+{
+ HideFocus();
+
+ BOOL bEnable = IsEnabled();
+ ImplDrawSpinButton( this, maUpperRect, maLowerRect, mbUpperIn, mbLowerIn,
+ bEnable && ImplIsUpperEnabled(),
+ bEnable && ImplIsLowerEnabled(), mbHorz, TRUE );
+
+ if ( HasFocus() )
+ ShowFocus( maFocusRect );
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsUpperEnabled() ) )
+ {
+ mbUpperIn = TRUE;
+ mbInitialUp = TRUE;
+ Invalidate( maUpperRect );
+ }
+ else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsLowerEnabled() ) )
+ {
+ mbLowerIn = TRUE;
+ mbInitialDown = TRUE;
+ Invalidate( maLowerRect );
+ }
+
+ if ( mbUpperIn || mbLowerIn )
+ {
+ Update();
+ CaptureMouse();
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::MouseButtonUp( const MouseEvent& )
+{
+ ReleaseMouse();
+ if ( mbRepeat )
+ {
+ maRepeatTimer.Stop();
+ maRepeatTimer.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+ }
+
+ if ( mbUpperIn )
+ {
+ mbUpperIn = FALSE;
+ Invalidate( maUpperRect );
+ Update();
+ Up();
+ }
+ else if ( mbLowerIn )
+ {
+ mbLowerIn = FALSE;
+ Invalidate( maLowerRect );
+ Update();
+ Down();
+ }
+
+ mbInitialUp = mbInitialDown = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( !rMEvt.IsLeft() || (!mbInitialUp && !mbInitialDown) )
+ return;
+
+ if ( !maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
+ mbUpperIn && mbInitialUp )
+ {
+ mbUpperIn = FALSE;
+ maRepeatTimer.Stop();
+ Invalidate( maUpperRect );
+ Update();
+ }
+ else if ( !maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
+ mbLowerIn & mbInitialDown )
+ {
+ mbLowerIn = FALSE;
+ maRepeatTimer.Stop();
+ Invalidate( maLowerRect );
+ Update();
+ }
+ else if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
+ !mbUpperIn && mbInitialUp )
+ {
+ mbUpperIn = TRUE;
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ Invalidate( maUpperRect );
+ Update();
+ }
+ else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
+ !mbLowerIn && mbInitialDown )
+ {
+ mbLowerIn = TRUE;
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ Invalidate( maLowerRect );
+ Update();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aCode = rKEvt.GetKeyCode();
+
+ if ( !rKEvt.GetKeyCode().GetModifier() )
+ {
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ BOOL bUp = KEY_RIGHT == rKEvt.GetKeyCode().GetCode();
+ if ( mbHorz && !ImplMoveFocus( bUp ) )
+ bUp ? Up() : Down();
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_DOWN:
+ {
+ BOOL bUp = KEY_UP == rKEvt.GetKeyCode().GetCode();
+ if ( !mbHorz && !ImplMoveFocus( KEY_UP == rKEvt.GetKeyCode().GetCode() ) )
+ bUp ? Up() : Down();
+ }
+ break;
+
+ case KEY_SPACE:
+ mbUpperIsFocused ? Up() : Down();
+ break;
+
+ default:
+ Control::KeyInput( rKEvt );
+ break;
+ }
+ }
+ else
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::StateChanged( StateChangedType nType )
+{
+ switch ( nType )
+ {
+ case STATE_CHANGE_DATA:
+ case STATE_CHANGE_ENABLE:
+ Invalidate();
+ break;
+
+ case STATE_CHANGE_STYLE:
+ {
+ BOOL bNewRepeat = 0 != ( GetStyle() & WB_REPEAT );
+ if ( bNewRepeat != mbRepeat )
+ {
+ if ( maRepeatTimer.IsActive() )
+ {
+ maRepeatTimer.Stop();
+ maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+ }
+ mbRepeat = bNewRepeat;
+ }
+
+ BOOL bNewHorz = 0 != ( GetStyle() & WB_HSCROLL );
+ if ( bNewHorz != mbHorz )
+ {
+ mbHorz = bNewHorz;
+ Resize();
+ }
+ }
+ break;
+ }
+
+ Control::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::SetRangeMin( long nNewRange )
+{
+ SetRange( Range( nNewRange, GetRangeMax() ) );
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::SetRangeMax( long nNewRange )
+{
+ SetRange( Range( GetRangeMin(), nNewRange ) );
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::SetRange( const Range& rRange )
+{
+ // adjust rage
+ Range aRange = rRange;
+ aRange.Justify();
+ long nNewMinRange = aRange.Min();
+ long nNewMaxRange = aRange.Max();
+
+ // do something only if old and new range differ
+ if ( (mnMinRange != nNewMinRange) ||
+ (mnMaxRange != nNewMaxRange) )
+ {
+ mnMinRange = nNewMinRange;
+ mnMaxRange = nNewMaxRange;
+
+ // adjust value to new range, if necessary
+ if ( mnValue > mnMaxRange )
+ mnValue = mnMaxRange;
+ if ( mnValue < mnMinRange )
+ mnValue = mnMinRange;
+
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::SetValue( long nValue )
+{
+ // adjust, if necessary
+ if ( nValue > mnMaxRange )
+ nValue = mnMaxRange;
+ if ( nValue < mnMinRange )
+ nValue = mnMinRange;
+
+ if ( mnValue != nValue )
+ {
+ mnValue = nValue;
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::GetFocus()
+{
+ ShowFocus( maFocusRect );
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::LoseFocus()
+{
+ HideFocus();
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SpinButton::ImplMoveFocus( BOOL _bUpper )
+{
+ if ( _bUpper == mbUpperIsFocused )
+ return FALSE;
+
+ HideFocus();
+ ImplCalcFocusRect( _bUpper );
+ if ( HasFocus() )
+ ShowFocus( maFocusRect );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void SpinButton::ImplCalcFocusRect( BOOL _bUpper )
+{
+ maFocusRect = _bUpper ? maUpperRect : maLowerRect;
+ // inflate by some pixels
+ maFocusRect.Left() += 2;
+ maFocusRect.Top() += 2;
+ maFocusRect.Right() -= 2;
+ maFocusRect.Bottom() -= 2;
+ mbUpperIsFocused = _bUpper;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle* SpinButton::ImplFindPartRect( const Point& rPt )
+{
+ if( maUpperRect.IsInside( rPt ) )
+ return &maUpperRect;
+ else if( maLowerRect.IsInside( rPt ) )
+ return &maLowerRect;
+ else
+ return NULL;
+}
+
+long SpinButton::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
+ IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
+ if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
+ {
+ Region aRgn( GetActiveClipRegion() );
+ if( pLastRect )
+ {
+ SetClipRegion( *pLastRect );
+ Paint( *pLastRect );
+ SetClipRegion( aRgn );
+ }
+ if( pRect )
+ {
+ SetClipRegion( *pRect );
+ Paint( *pRect );
+ SetClipRegion( aRgn );
+ }
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Control::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/source/control/spinfld.cxx b/vcl/source/control/spinfld.cxx
new file mode 100644
index 000000000000..754270e9012f
--- /dev/null
+++ b/vcl/source/control/spinfld.cxx
@@ -0,0 +1,1091 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "tools/rc.h"
+#include "vcl/event.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/spin.h"
+#include "vcl/spinfld.hxx"
+#include "vcl/controldata.hxx"
+#include "vcl/svdata.hxx"
+
+// =======================================================================
+
+void ImplGetSpinbuttonValue( Window *pWin, const Rectangle& rUpperRect,
+ const Rectangle& rLowerRect,
+ BOOL bUpperIn, BOOL bLowerIn,
+ BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz,
+ SpinbuttonValue& rValue )
+{
+ // convert spinbutton data to a SpinbuttonValue structure for native painting
+
+ rValue.maUpperRect = rUpperRect;
+ rValue.maLowerRect = rLowerRect;
+
+ Point aPointerPos = pWin->GetPointerPosPixel();
+
+ ControlState nState = CTRL_STATE_ENABLED;
+ if ( bUpperIn )
+ nState |= CTRL_STATE_PRESSED;
+ if ( !pWin->IsEnabled() || !bUpperEnabled )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( pWin->HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ if( pWin->IsMouseOver() && rUpperRect.IsInside( aPointerPos ) )
+ nState |= CTRL_STATE_ROLLOVER;
+ rValue.mnUpperState = nState;
+
+ nState = CTRL_STATE_ENABLED;
+ if ( bLowerIn )
+ nState |= CTRL_STATE_PRESSED;
+ if ( !pWin->IsEnabled() || !bLowerEnabled )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( pWin->HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ // for overlapping spins: highlight only one
+ if( pWin->IsMouseOver() && rLowerRect.IsInside( aPointerPos ) &&
+ !rUpperRect.IsInside( aPointerPos ) )
+ nState |= CTRL_STATE_ROLLOVER;
+ rValue.mnLowerState = nState;
+
+ rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
+ rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
+}
+
+
+BOOL ImplDrawNativeSpinfield( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
+{
+ BOOL bNativeOK = FALSE;
+
+ if( pWin->IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) &&
+ // there is just no useful native support for spinfields with dropdown
+ !(pWin->GetStyle() & WB_DROPDOWN) )
+ {
+ if( pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) &&
+ pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart) )
+ {
+ // only paint the embedded spin buttons, all buttons are painted at once
+ bNativeOK = pWin->DrawNativeControl( CTRL_SPINBOX, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
+ rSpinbuttonValue, rtl::OUString() );
+ }
+ else
+ {
+ // paint the spinbox as a whole, use borderwindow to have proper clipping
+ Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
+
+ // to not overwrite everything, set the button region as clipregion to the border window
+ Rectangle aClipRect( rSpinbuttonValue.maLowerRect );
+ aClipRect.Union( rSpinbuttonValue.maUpperRect );
+
+ // convert from screen space to borderwin space
+ aClipRect.SetPos( pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())) );
+
+ Region oldRgn( pBorder->GetClipRegion() );
+ pBorder->SetClipRegion( Region( aClipRect ) );
+
+ Point aPt;
+ Size aSize( pBorder->GetOutputSizePixel() ); // the size of the border window, i.e., the whole control
+ Rectangle aBound, aContent;
+ Rectangle aNatRgn( aPt, aSize );
+ if( pBorder->GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
+ aNatRgn, 0, rSpinbuttonValue, rtl::OUString(), aBound, aContent) )
+ {
+ aSize = aContent.GetSize();
+ }
+
+ Rectangle aRgn( aPt, aSize );
+ bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED,
+ rSpinbuttonValue, rtl::OUString() );
+
+ pBorder->SetClipRegion( oldRgn );
+ }
+ }
+ return bNativeOK;
+}
+
+BOOL ImplDrawNativeSpinbuttons( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
+{
+ BOOL bNativeOK = FALSE;
+
+ if( pWin->IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL) )
+ {
+ // only paint the standalone spin buttons, all buttons are painted at once
+ bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
+ rSpinbuttonValue, rtl::OUString() );
+ }
+ return bNativeOK;
+}
+
+void ImplDrawSpinButton( OutputDevice* pOutDev,
+ const Rectangle& rUpperRect,
+ const Rectangle& rLowerRect,
+ BOOL bUpperIn, BOOL bLowerIn,
+ BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz, BOOL bMirrorHorz )
+{
+ DecorationView aDecoView( pOutDev );
+
+ USHORT nStyle = BUTTON_DRAW_NOLEFTLIGHTBORDER;
+ USHORT nSymStyle = 0;
+
+ SymbolType eType1, eType2;
+
+ const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_SPINARROW )
+ {
+ // arrows are only use in OS/2 look
+ if ( bHorz )
+ {
+ eType1 = bMirrorHorz ? SYMBOL_ARROW_RIGHT : SYMBOL_ARROW_LEFT;
+ eType2 = bMirrorHorz ? SYMBOL_ARROW_LEFT : SYMBOL_ARROW_RIGHT;
+ }
+ else
+ {
+ eType1 = SYMBOL_ARROW_UP;
+ eType2 = SYMBOL_ARROW_DOWN;
+ }
+ }
+ else
+ {
+ if ( bHorz )
+ {
+ eType1 = bMirrorHorz ? SYMBOL_SPIN_RIGHT : SYMBOL_SPIN_LEFT;
+ eType2 = bMirrorHorz ? SYMBOL_SPIN_LEFT : SYMBOL_SPIN_RIGHT;
+ }
+ else
+ {
+ eType1 = SYMBOL_SPIN_UP;
+ eType2 = SYMBOL_SPIN_DOWN;
+ }
+ }
+
+ // Oberen/linken Button malen
+ USHORT nTempStyle = nStyle;
+ if ( bUpperIn )
+ nTempStyle |= BUTTON_DRAW_PRESSED;
+
+ BOOL bNativeOK = FALSE;
+ Rectangle aUpRect;
+
+ if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
+ {
+ Window *pWin = (Window*) pOutDev;
+
+ // are we drawing standalone spin buttons or members of a spinfield ?
+ ControlType aControl = CTRL_SPINBUTTONS;
+ switch( pWin->GetType() )
+ {
+ case WINDOW_EDIT:
+ case WINDOW_MULTILINEEDIT:
+ case WINDOW_PATTERNFIELD:
+ case WINDOW_METRICFIELD:
+ case WINDOW_CURRENCYFIELD:
+ case WINDOW_DATEFIELD:
+ case WINDOW_TIMEFIELD:
+ case WINDOW_LONGCURRENCYFIELD:
+ case WINDOW_NUMERICFIELD:
+ case WINDOW_SPINFIELD:
+ aControl = CTRL_SPINBOX;
+ break;
+ default:
+ aControl = CTRL_SPINBUTTONS;
+ break;
+ }
+
+ SpinbuttonValue aValue;
+ ImplGetSpinbuttonValue( pWin, rUpperRect, rLowerRect,
+ bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
+ bHorz, aValue );
+
+ if( aControl == CTRL_SPINBOX )
+ bNativeOK = ImplDrawNativeSpinfield( pWin, aValue );
+ else if( aControl == CTRL_SPINBUTTONS )
+ bNativeOK = ImplDrawNativeSpinbuttons( pWin, aValue );
+ }
+
+ if( !bNativeOK )
+ aUpRect = aDecoView.DrawButton( rUpperRect, nTempStyle );
+
+ // Unteren/rechten Button malen
+ if ( bLowerIn )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ Rectangle aLowRect;
+ if( !bNativeOK )
+ aLowRect = aDecoView.DrawButton( rLowerRect, nStyle );
+
+ // Zusaetzliche Default-Kante wollen wir auch ausnutzen
+ aUpRect.Left()--;
+ aUpRect.Top()--;
+ aUpRect.Right()++;
+ aUpRect.Bottom()++;
+ aLowRect.Left()--;
+ aLowRect.Top()--;
+ aLowRect.Right()++;
+ aLowRect.Bottom()++;
+
+ // Wir malen auch in die Kante rein, damit man etwas erkennen kann,
+ // wenn das Rechteck zu klein ist
+ if ( aUpRect.GetHeight() < 4 )
+ {
+ aUpRect.Right()++;
+ aUpRect.Bottom()++;
+ aLowRect.Right()++;
+ aLowRect.Bottom()++;
+ }
+
+ // Symbolgroesse berechnen
+ long nTempSize1 = aUpRect.GetWidth();
+ long nTempSize2 = aLowRect.GetWidth();
+ if ( Abs( nTempSize1-nTempSize2 ) == 1 )
+ {
+ if ( nTempSize1 > nTempSize2 )
+ aUpRect.Left()++;
+ else
+ aLowRect.Left()++;
+ }
+ nTempSize1 = aUpRect.GetHeight();
+ nTempSize2 = aLowRect.GetHeight();
+ if ( Abs( nTempSize1-nTempSize2 ) == 1 )
+ {
+ if ( nTempSize1 > nTempSize2 )
+ aUpRect.Top()++;
+ else
+ aLowRect.Top()++;
+ }
+
+ nTempStyle = nSymStyle;
+ if ( !bUpperEnabled )
+ nTempStyle |= SYMBOL_DRAW_DISABLE;
+ if( !bNativeOK )
+ aDecoView.DrawSymbol( aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempStyle );
+
+ if ( !bLowerEnabled )
+ nSymStyle |= SYMBOL_DRAW_DISABLE;
+ if( !bNativeOK )
+ aDecoView.DrawSymbol( aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle );
+}
+
+// =======================================================================
+
+void SpinField::ImplInitSpinFieldData()
+{
+ mpEdit = NULL;
+ mbSpin = FALSE;
+ mbRepeat = FALSE;
+ mbUpperIn = FALSE;
+ mbLowerIn = FALSE;
+ mbInitialUp = FALSE;
+ mbInitialDown = FALSE;
+ mbNoSelect = FALSE;
+ mbInDropDown = FALSE;
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::ImplInit( Window* pParent, WinBits nWinStyle )
+{
+ Edit::ImplInit( pParent, nWinStyle );
+
+ if ( nWinStyle & (WB_SPIN|WB_DROPDOWN) )
+ {
+ mbSpin = TRUE;
+
+ // Some themes want external spin buttons, therefore the main
+ // spinfield should not overdraw the border between its encapsulated
+ // edit field and the spin buttons
+ if ( (nWinStyle & WB_SPIN) && ImplUseNativeBorder( nWinStyle ) )
+ {
+ SetBackground();
+ mpEdit = new Edit( this, WB_NOBORDER );
+ mpEdit->SetBackground();
+ }
+ else
+ mpEdit = new Edit( this, WB_NOBORDER );
+
+ mpEdit->EnableRTL( FALSE );
+ mpEdit->SetPosPixel( Point() );
+ mpEdit->Show();
+ SetSubEdit( mpEdit );
+
+ maRepeatTimer.SetTimeoutHdl( LINK( this, SpinField, ImplTimeout ) );
+ maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+ if ( nWinStyle & WB_REPEAT )
+ mbRepeat = TRUE;
+
+ SetCompoundControl( TRUE );
+ }
+}
+
+// --------------------------------------------------------------------
+
+SpinField::SpinField( WindowType nTyp ) :
+ Edit( nTyp )
+{
+ ImplInitSpinFieldData();
+}
+
+// --------------------------------------------------------------------
+
+SpinField::SpinField( Window* pParent, WinBits nWinStyle ) :
+ Edit( WINDOW_SPINFIELD )
+{
+ ImplInitSpinFieldData();
+ ImplInit( pParent, nWinStyle );
+}
+
+// --------------------------------------------------------------------
+
+SpinField::SpinField( Window* pParent, const ResId& rResId ) :
+ Edit( WINDOW_SPINFIELD )
+{
+ ImplInitSpinFieldData();
+ rResId.SetRT( RSC_SPINFIELD );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// --------------------------------------------------------------------
+
+SpinField::~SpinField()
+{
+ delete mpEdit;
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Up()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Down()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::First()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Last()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( !HasFocus() && ( !mpEdit || !mpEdit->HasFocus() ) )
+ {
+ mbNoSelect = TRUE;
+ GrabFocus();
+ }
+
+ if ( !IsReadOnly() )
+ {
+ if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ mbUpperIn = TRUE;
+ mbInitialUp = TRUE;
+ Invalidate( maUpperRect );
+ }
+ else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ mbLowerIn = TRUE;
+ mbInitialDown = TRUE;
+ Invalidate( maLowerRect );
+ }
+ else if ( maDropDownRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ // Rechts daneben liegt der DropDownButton:
+ mbInDropDown = ShowDropDown( mbInDropDown ? FALSE : TRUE );
+ Paint( Rectangle( Point(), GetOutputSizePixel() ) );
+ }
+
+ if ( mbUpperIn || mbLowerIn )
+ {
+ Update();
+ CaptureMouse();
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ return;
+ }
+ }
+
+ Edit::MouseButtonDown( rMEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ ReleaseMouse();
+ mbInitialUp = mbInitialDown = FALSE;
+ maRepeatTimer.Stop();
+ maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+
+ if ( mbUpperIn )
+ {
+ mbUpperIn = FALSE;
+ Invalidate( maUpperRect );
+ Update();
+ Up();
+ }
+ else if ( mbLowerIn )
+ {
+ mbLowerIn = FALSE;
+ Invalidate( maLowerRect );
+ Update();
+ Down();
+ }
+
+ Edit::MouseButtonUp( rMEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() )
+ {
+ if ( mbInitialUp )
+ {
+ BOOL bNewUpperIn = maUpperRect.IsInside( rMEvt.GetPosPixel() );
+ if ( bNewUpperIn != mbUpperIn )
+ {
+ if ( bNewUpperIn )
+ {
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ }
+ else
+ maRepeatTimer.Stop();
+
+ mbUpperIn = bNewUpperIn;
+ Invalidate( maUpperRect );
+ Update();
+ }
+ }
+ else if ( mbInitialDown )
+ {
+ BOOL bNewLowerIn = maLowerRect.IsInside( rMEvt.GetPosPixel() );
+ if ( bNewLowerIn != mbLowerIn )
+ {
+ if ( bNewLowerIn )
+ {
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ }
+ else
+ maRepeatTimer.Stop();
+
+ mbLowerIn = bNewLowerIn;
+ Invalidate( maLowerRect );
+ Update();
+ }
+ }
+ }
+
+ Edit::MouseMove( rMEvt );
+}
+
+// --------------------------------------------------------------------
+
+long SpinField::Notify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
+ if ( !IsReadOnly() )
+ {
+ USHORT nMod = rKEvt.GetKeyCode().GetModifier();
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_UP:
+ {
+ if ( !nMod )
+ {
+ Up();
+ nDone = 1;
+ }
+ }
+ break;
+ case KEY_DOWN:
+ {
+ if ( !nMod )
+ {
+ Down();
+ nDone = 1;
+ }
+ else if ( ( nMod == KEY_MOD2 ) && !mbInDropDown && ( GetStyle() & WB_DROPDOWN ) )
+ {
+ mbInDropDown = ShowDropDown( TRUE );
+ Paint( Rectangle( Point(), GetOutputSizePixel() ) );
+ nDone = 1;
+ }
+ }
+ break;
+ case KEY_PAGEUP:
+ {
+ if ( !nMod )
+ {
+ Last();
+ nDone = 1;
+ }
+ }
+ break;
+ case KEY_PAGEDOWN:
+ {
+ if ( !nMod )
+ {
+ First();
+ nDone = 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if ( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ if ( ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) && !IsReadOnly() )
+ {
+ USHORT nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
+ if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
+ || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
+ && HasChildPathFocus()
+ )
+ )
+ {
+ const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
+ if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
+ {
+ if ( pData->GetDelta() < 0L )
+ Down();
+ else
+ Up();
+ nDone = 1;
+ }
+ }
+ else
+ nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
+ }
+ }
+
+ return nDone ? nDone : Edit::Notify( rNEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Command( const CommandEvent& rCEvt )
+{
+ Edit::Command( rCEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::FillLayoutData() const
+{
+ if( mbSpin )
+ {
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ AppendLayoutData( *GetSubEdit() );
+ GetSubEdit()->SetLayoutDataParent( this );
+ }
+ else
+ Edit::FillLayoutData();
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Paint( const Rectangle& rRect )
+{
+ if ( mbSpin )
+ {
+ BOOL bEnable = IsEnabled();
+ ImplDrawSpinButton( this, maUpperRect, maLowerRect,
+ mbUpperIn, mbLowerIn, bEnable, bEnable );
+ }
+
+ if ( GetStyle() & WB_DROPDOWN )
+ {
+ DecorationView aView( this );
+
+ USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
+ if ( mbInDropDown )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ Rectangle aInnerRect = aView.DrawButton( maDropDownRect, nStyle );
+
+ SymbolType eSymbol = SYMBOL_SPIN_DOWN;
+ if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
+ eSymbol = SYMBOL_SPIN_UPDOWN;
+
+ nStyle = IsEnabled() ? 0 : SYMBOL_DRAW_DISABLE;
+ aView.DrawSymbol( aInnerRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
+ }
+
+ Edit::Paint( rRect );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea )
+{
+ const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
+
+ Size aSize = rOutSz;
+ Size aDropDownSize;
+
+ if ( GetStyle() & WB_DROPDOWN )
+ {
+ long nW = rStyleSettings.GetScrollBarSize();
+ nW = GetDrawPixel( pDev, nW );
+ aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
+ aSize.Width() -= aDropDownSize.Width();
+ rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
+ rDDArea.Top()--;
+ }
+ else
+ rDDArea.SetEmpty();
+
+ // Je nach Hoehe, die groessen Berechnen
+ if ( GetStyle() & WB_SPIN )
+ {
+ long nBottom1 = aSize.Height()/2;
+ long nBottom2 = aSize.Height()-1;
+ long nTop2 = nBottom1;
+ long nTop1 = 0;
+ if ( !(aSize.Height() & 0x01) )
+ nBottom1--;
+
+ BOOL bNativeRegionOK = FALSE;
+ Rectangle aContentUp, aContentDown;
+
+ if ( (pDev->GetOutDevType() == OUTDEV_WINDOW) &&
+ // there is just no useful native support for spinfields with dropdown
+ ! (GetStyle() & WB_DROPDOWN) &&
+ IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) )
+ {
+ Window *pWin = (Window*) pDev;
+ Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
+
+ // get the system's spin button size
+ ImplControlValue aControlValue;
+ Rectangle aBound;
+ Point aPoint;
+
+ // use the full extent of the control
+ Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
+
+ bNativeRegionOK =
+ pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContentUp) &&
+ pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContentDown);
+
+ if( bNativeRegionOK )
+ {
+ // convert back from border space to local coordinates
+ aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
+ aContentUp.Move(-aPoint.X(), -aPoint.Y());
+ aContentDown.Move(-aPoint.X(), -aPoint.Y());
+ }
+ }
+
+ if( bNativeRegionOK )
+ {
+ rSpinUpArea = aContentUp;
+ rSpinDownArea = aContentDown;
+ }
+ else
+ {
+ aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) );
+
+ rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
+ rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
+ }
+ }
+ else
+ {
+ rSpinUpArea.SetEmpty();
+ rSpinDownArea.SetEmpty();
+ }
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Resize()
+{
+ if ( mbSpin )
+ {
+ Control::Resize();
+ Size aSize = GetOutputSizePixel();
+ bool bSubEditPositioned = false;
+
+ if ( GetStyle() & (WB_SPIN|WB_DROPDOWN) )
+ {
+ ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect );
+
+ ImplControlValue aControlValue;
+ Point aPoint;
+ Rectangle aContent, aBound;
+
+ // use the full extent of the control
+ Window *pBorder = GetWindow( WINDOW_BORDER );
+ Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
+
+ // adjust position and size of the edit field
+ if ( GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ // convert back from border space to local coordinates
+ aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
+ aContent.Move(-aPoint.X(), -aPoint.Y());
+
+ // use the themes drop down size
+ mpEdit->SetPosPixel( aContent.TopLeft() );
+ bSubEditPositioned = true;
+ aSize = aContent.GetSize();
+ }
+ else
+ {
+ if ( maUpperRect.IsEmpty() )
+ {
+ DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
+ aSize.Width() = maDropDownRect.Left();
+ }
+ else
+ aSize.Width() = maUpperRect.Left();
+ }
+ }
+
+ if( ! bSubEditPositioned )
+ {
+ // this moves our sub edit if RTL gets switched
+ mpEdit->SetPosPixel( Point() );
+ }
+ mpEdit->SetSizePixel( aSize );
+
+ if ( GetStyle() & WB_SPIN )
+ Invalidate( Rectangle( maUpperRect.TopLeft(), maLowerRect.BottomRight() ) );
+ if ( GetStyle() & WB_DROPDOWN )
+ Invalidate( maDropDownRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::StateChanged( StateChangedType nType )
+{
+ Edit::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_ENABLE )
+ {
+ if ( mbSpin || ( GetStyle() & WB_DROPDOWN ) )
+ {
+ mpEdit->Enable( IsEnabled() );
+
+ if ( mbSpin )
+ {
+ Invalidate( maLowerRect );
+ Invalidate( maUpperRect );
+ }
+ if ( GetStyle() & WB_DROPDOWN )
+ Invalidate( maDropDownRect );
+ }
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ if ( GetStyle() & WB_REPEAT )
+ mbRepeat = TRUE;
+ else
+ mbRepeat = FALSE;
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ Resize();
+ if ( mpEdit )
+ mpEdit->SetZoom( GetZoom() );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ if ( mpEdit )
+ mpEdit->SetControlFont( GetControlFont() );
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ if ( mpEdit )
+ mpEdit->SetControlForeground( GetControlForeground() );
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ if ( mpEdit )
+ mpEdit->SetControlBackground( GetControlBackground() );
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+ else if( nType == STATE_CHANGE_MIRRORING )
+ {
+ if( mpEdit )
+ mpEdit->StateChanged( STATE_CHANGE_MIRRORING );
+ Resize();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Edit::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ Resize();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle* SpinField::ImplFindPartRect( const Point& rPt )
+{
+ if( maUpperRect.IsInside( rPt ) )
+ return &maUpperRect;
+ else if( maLowerRect.IsInside( rPt ) )
+ return &maLowerRect;
+ else
+ return NULL;
+}
+
+long SpinField::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
+ IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
+ if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
+ {
+ // FIXME: this is currently only on aqua
+ // check for other platforms that need similar handling
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
+ {
+ ImplInvalidateOutermostBorder( this );
+ }
+ else
+ {
+ // paint directly
+ Region aRgn( GetActiveClipRegion() );
+ if( pLastRect )
+ {
+ SetClipRegion( *pLastRect );
+ Paint( *pLastRect );
+ SetClipRegion( aRgn );
+ }
+ if( pRect )
+ {
+ SetClipRegion( *pRect );
+ Paint( *pRect );
+ SetClipRegion( aRgn );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Edit::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::EndDropDown()
+{
+ mbInDropDown = FALSE;
+ Paint( Rectangle( Point(), GetOutputSizePixel() ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SpinField::ShowDropDown( BOOL )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Size SpinField::CalcMinimumSize() const
+{
+ Size aSz = Edit::CalcMinimumSize();
+
+ if ( GetStyle() & WB_DROPDOWN )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ if ( GetStyle() & WB_SPIN )
+ aSz.Width() += maUpperRect.GetWidth();
+
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Size SpinField::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Edit::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size SpinField::CalcSize( USHORT nChars ) const
+{
+ Size aSz = Edit::CalcSize( nChars );
+
+ if ( GetStyle() & WB_DROPDOWN )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ if ( GetStyle() & WB_SPIN )
+ aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize();
+
+ return aSz;
+}
+
+// --------------------------------------------------------------------
+
+IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer )
+{
+ if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
+ {
+ pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
+ pTimer->Start();
+ }
+ else
+ {
+ if ( mbInitialUp )
+ Up();
+ else
+ Down();
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ Edit::Draw( pDev, rPos, rSize, nFlags );
+
+ WinBits nFieldStyle = GetStyle();
+ if ( !(nFlags & WINDOW_DRAW_NOCONTROLS ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
+ {
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ OutDevType eOutDevType = pDev->GetOutDevType();
+ AllSettings aOldSettings = pDev->GetSettings();
+
+ pDev->Push();
+ pDev->SetMapMode();
+
+ if ( eOutDevType == OUTDEV_PRINTER )
+ {
+ StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
+ aStyleSettings.SetFaceColor( COL_LIGHTGRAY );
+ aStyleSettings.SetButtonTextColor( COL_BLACK );
+ AllSettings aSettings( aOldSettings );
+ aSettings.SetStyleSettings( aStyleSettings );
+ pDev->SetSettings( aSettings );
+ }
+
+ Rectangle aDD, aUp, aDown;
+ ImplCalcButtonAreas( pDev, aSize, aDD, aUp, aDown );
+ aDD.Move( aPos.X(), aPos.Y() );
+ aUp.Move( aPos.X(), aPos.Y() );
+ aUp.Top()++;
+ aDown.Move( aPos.X(), aPos.Y() );
+
+ Color aButtonTextColor;
+ if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
+ aButtonTextColor = Color( COL_BLACK );
+ else
+ aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
+
+ if ( GetStyle() & WB_DROPDOWN )
+ {
+ DecorationView aView( pDev );
+ USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
+ Rectangle aInnerRect = aView.DrawButton( aDD, nStyle );
+ SymbolType eSymbol = SYMBOL_SPIN_DOWN;
+ if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
+ eSymbol = SYMBOL_SPIN_UPDOWN;
+
+ nStyle = ( IsEnabled() || ( nFlags & WINDOW_DRAW_NODISABLE ) ) ? 0 : SYMBOL_DRAW_DISABLE;
+ aView.DrawSymbol( aInnerRect, eSymbol, aButtonTextColor, nStyle );
+ }
+
+ if ( GetStyle() & WB_SPIN )
+ {
+ ImplDrawSpinButton( pDev, aUp, aDown, FALSE, FALSE, TRUE, TRUE );
+ }
+
+ pDev->Pop();
+ pDev->SetSettings( aOldSettings );
+ }
+}
diff --git a/vcl/source/control/tabctrl.cxx b/vcl/source/control/tabctrl.cxx
new file mode 100644
index 000000000000..c892b32534ec
--- /dev/null
+++ b/vcl/source/control/tabctrl.cxx
@@ -0,0 +1,2356 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include "tools/debug.hxx"
+
+#include "tools/rc.h"
+#include "vcl/svdata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/help.hxx"
+#include "vcl/event.hxx"
+#include "vcl/menu.hxx"
+#include "vcl/button.hxx"
+#include "vcl/tabpage.hxx"
+#include "vcl/tabctrl.hxx"
+#include "vcl/controllayout.hxx"
+#include "vcl/controldata.hxx"
+#include "vcl/sound.hxx"
+#include "vcl/lstbox.hxx"
+#include "vcl/smartid.hxx"
+
+#include "vcl/window.h"
+
+#include <hash_map>
+#include <vector>
+
+// =======================================================================
+
+struct ImplTabItem
+{
+ USHORT mnId;
+ USHORT mnTabPageResId;
+ TabPage* mpTabPage;
+ String maText;
+ String maFormatText;
+ String maHelpText;
+ ULONG mnHelpId;
+ Rectangle maRect;
+ USHORT mnLine;
+ bool mbFullVisible;
+ bool mbEnabled;
+ Image maTabImage;
+
+ ImplTabItem()
+ : mnId( 0 ), mnTabPageResId( 0 ), mpTabPage( NULL ), mnHelpId( 0 ),
+ mnLine( 0 ), mbFullVisible( FALSE ), mbEnabled( true )
+ {}
+};
+
+// -----------------------------------------------------------------------
+
+struct ImplTabCtrlData
+{
+ PushButton* mpLeftBtn;
+ PushButton* mpRightBtn;
+ std::hash_map< int, int > maLayoutPageIdToLine;
+ std::hash_map< int, int > maLayoutLineToPageId;
+ std::vector< Rectangle > maTabRectangles;
+ Point maItemsOffset; // offset of the tabitems
+ std::vector< ImplTabItem > maItemList;
+ ListBox* mpListBox;
+ Size maMinSize;
+};
+
+// -----------------------------------------------------------------------
+
+#if 0
+// not used
+#define TABCOLORCOUNT 10
+
+static ColorData aImplTabColorAry[TABCOLORCOUNT] =
+{
+ RGB_COLORDATA( 80, 216, 248 ),
+ RGB_COLORDATA( 128, 216, 168 ),
+ RGB_COLORDATA( 128, 144, 248 ),
+ RGB_COLORDATA( 208, 180, 168 ),
+ RGB_COLORDATA( 248, 252, 168 ),
+ RGB_COLORDATA( 168, 144, 168 ),
+ RGB_COLORDATA( 248, 144, 80 ),
+ RGB_COLORDATA( 248, 216, 80 ),
+ RGB_COLORDATA( 248, 180, 168 ),
+ RGB_COLORDATA( 248, 216, 168 )
+};
+#endif
+
+// -----------------------------------------------------------------------
+
+#define TAB_OFFSET 3
+#define TAB_TABOFFSET_X 3
+#define TAB_TABOFFSET_Y 3
+#define TAB_EXTRASPACE_X 6
+#define TAB_BORDER_LEFT 1
+#define TAB_BORDER_TOP 1
+#define TAB_BORDER_RIGHT 2
+#define TAB_BORDER_BOTTOM 2
+
+// Fuer die Ermittlung von den Tab-Positionen
+#define TAB_PAGERECT 0xFFFF
+
+// =======================================================================
+
+void TabControl::ImplInit( Window* pParent, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ if ( !(nStyle & WB_NODIALOGCONTROL) )
+ nStyle |= WB_DIALOGCONTROL;
+
+ // no single line tabs since NWF
+ nStyle &= ~WB_SINGLELINE;
+
+ Control::ImplInit( pParent, nStyle, NULL );
+
+ mnLastWidth = 0;
+ mnLastHeight = 0;
+ mnBtnSize = 0;
+ mnMaxPageWidth = 0;
+ mnActPageId = 0;
+ mnCurPageId = 0;
+ mnFirstPagePos = 0;
+ mnLastFirstPagePos = 0;
+ mbFormat = TRUE;
+ mbRestoreHelpId = FALSE;
+ mbRestoreUnqId = FALSE;
+ mbSingleLine = FALSE;
+ mbScroll = FALSE;
+ mbRestoreSmartId = FALSE;
+ mbSmallInvalidate = FALSE;
+ mbExtraSpace = FALSE;
+ mpTabCtrlData = new ImplTabCtrlData;
+ mpTabCtrlData->mpLeftBtn = NULL;
+ mpTabCtrlData->mpRightBtn = NULL;
+ mpTabCtrlData->mpListBox = NULL;
+
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+
+ if( (nStyle & WB_DROPDOWN) )
+ {
+ mpTabCtrlData->mpListBox = new ListBox( this, WB_DROPDOWN );
+ mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) );
+ mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) );
+ mpTabCtrlData->mpListBox->Show();
+ }
+
+ // if the tabcontrol is drawn (ie filled) by a native widget, make sure all contols will have transparent background
+ // otherwise they will paint with a wrong background
+ if( IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) )
+ EnableChildTransparentMode( TRUE );
+
+ if ( pParent->IsDialog() )
+ pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
+}
+
+// -----------------------------------------------------------------
+
+const Font& TabControl::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetAppFont();
+}
+
+// -----------------------------------------------------------------
+const Color& TabControl::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetButtonTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Control::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ Window* pParent = GetParent();
+ if ( !IsControlBackground() &&
+ (pParent->IsChildTransparentModeEnabled()
+ || IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL)
+ || IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) ) )
+
+ {
+ // set transparent mode for NWF tabcontrols to have
+ // the background always cleared properly
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+ }
+
+ ImplScrollBtnsColor();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplFreeLayoutData()
+{
+ if( HasLayoutData() )
+ {
+ ImplClearLayoutData();
+ mpTabCtrlData->maLayoutPageIdToLine.clear();
+ mpTabCtrlData->maLayoutLineToPageId.clear();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TabControl::TabControl( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_TABCONTROL )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+TabControl::TabControl( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_TABCONTROL )
+{
+ rResId.SetRT( RSC_TABCONTROL );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if ( nObjMask & RSC_TABCONTROL_ITEMLIST )
+ {
+ ULONG nEle = ReadLongRes();
+
+ // Item hinzufuegen
+ for( ULONG i = 0; i < nEle; i++ )
+ {
+ InsertPage( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TabControl::~TabControl()
+{
+ if ( GetParent()->IsDialog() )
+ GetParent()->RemoveChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
+
+ ImplFreeLayoutData();
+
+ // TabCtrl-Daten loeschen
+ if ( mpTabCtrlData )
+ {
+ if( mpTabCtrlData->mpListBox )
+ delete mpTabCtrlData->mpListBox;
+ if ( mpTabCtrlData->mpLeftBtn )
+ delete mpTabCtrlData->mpLeftBtn;
+ if ( mpTabCtrlData->mpRightBtn )
+ delete mpTabCtrlData->mpRightBtn;
+ delete mpTabCtrlData;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplTabItem* TabControl::ImplGetItem( USHORT nId ) const
+{
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if( it->mnId == nId )
+ return &(*it);
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplScrollBtnsColor()
+{
+ if ( mpTabCtrlData && mpTabCtrlData->mpLeftBtn )
+ {
+ mpTabCtrlData->mpLeftBtn->SetControlForeground();
+ mpTabCtrlData->mpRightBtn->SetControlForeground();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplSetScrollBtnsState()
+{
+ if ( mbScroll )
+ {
+ mpTabCtrlData->mpLeftBtn->Enable( mnFirstPagePos != 0 );
+ mpTabCtrlData->mpRightBtn->Enable( mnFirstPagePos < mnLastFirstPagePos );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplPosScrollBtns()
+{
+ if ( mbScroll )
+ {
+ if ( !mpTabCtrlData->mpLeftBtn )
+ {
+ mpTabCtrlData->mpLeftBtn = new PushButton( this, WB_RECTSTYLE | WB_SMALLSTYLE | WB_NOPOINTERFOCUS | WB_REPEAT );
+ mpTabCtrlData->mpLeftBtn->SetSymbol( SYMBOL_PREV );
+ mpTabCtrlData->mpLeftBtn->SetClickHdl( LINK( this, TabControl, ImplScrollBtnHdl ) );
+ }
+ if ( !mpTabCtrlData->mpRightBtn )
+ {
+ mpTabCtrlData->mpRightBtn = new PushButton( this, WB_RECTSTYLE | WB_SMALLSTYLE | WB_NOPOINTERFOCUS | WB_REPEAT );
+ mpTabCtrlData->mpRightBtn->SetSymbol( SYMBOL_NEXT );
+ mpTabCtrlData->mpRightBtn->SetClickHdl( LINK( this, TabControl, ImplScrollBtnHdl ) );
+ }
+
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+ aRect.Left() -= TAB_OFFSET;
+ aRect.Top() -= TAB_OFFSET;
+ aRect.Right() += TAB_OFFSET;
+ aRect.Bottom() += TAB_OFFSET;
+ long nX = aRect.Right()-mnBtnSize+1;
+ long nY = aRect.Top()-mnBtnSize;
+ mpTabCtrlData->mpRightBtn->SetPosSizePixel( nX, nY, mnBtnSize, mnBtnSize );
+ nX -= mnBtnSize;
+ mpTabCtrlData->mpLeftBtn->SetPosSizePixel( nX, nY, mnBtnSize, mnBtnSize );
+ ImplScrollBtnsColor();
+ ImplSetScrollBtnsState();
+ mpTabCtrlData->mpLeftBtn->Show();
+ mpTabCtrlData->mpRightBtn->Show();
+ }
+ else
+ {
+ if ( mpTabCtrlData )
+ {
+ if ( mpTabCtrlData->mpLeftBtn )
+ mpTabCtrlData->mpLeftBtn->Hide();
+ if ( mpTabCtrlData->mpRightBtn )
+ mpTabCtrlData->mpRightBtn->Hide();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size TabControl::ImplGetItemSize( ImplTabItem* pItem, long nMaxWidth )
+{
+ pItem->maFormatText = pItem->maText;
+ Size aSize( GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
+ Size aImageSize( 0, 0 );
+ if( !!pItem->maTabImage )
+ {
+ aImageSize = pItem->maTabImage.GetSizePixel();
+ if( pItem->maFormatText.Len() )
+ aImageSize.Width() += GetTextHeight()/4;
+ }
+ aSize.Width() += aImageSize.Width();
+ if( aImageSize.Height() > aSize.Height() )
+ aSize.Height() = aImageSize.Height();
+
+ aSize.Width() += TAB_TABOFFSET_X*2;
+ aSize.Height() += TAB_TABOFFSET_Y*2;
+
+ Rectangle aCtrlRegion( Point( 0, 0 ), aSize );
+ Rectangle aBoundingRgn, aContentRgn;
+ const ImplControlValue aControlValue;
+ if(GetNativeControlRegion( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ return aContentRgn.GetSize();
+ }
+
+ // For systems without synthetic bold support
+ if ( mbExtraSpace )
+ aSize.Width() += TAB_EXTRASPACE_X;
+ // For languages with short names (e.g. Chinese), because the space is
+ // normally only one pixel per char
+ else if ( pItem->maFormatText.Len() < TAB_EXTRASPACE_X )
+ aSize.Width() += TAB_EXTRASPACE_X-pItem->maFormatText.Len();
+
+ // Evt. den Text kuerzen
+ if ( aSize.Width()+4 >= nMaxWidth )
+ {
+ XubString aAppendStr( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
+ pItem->maFormatText += aAppendStr;
+ do
+ {
+ pItem->maFormatText.Erase( pItem->maFormatText.Len()-aAppendStr.Len()-1, 1 );
+ aSize.Width() = GetCtrlTextWidth( pItem->maFormatText );
+ aSize.Width() += aImageSize.Width();
+ aSize.Width() += TAB_TABOFFSET_X*2;
+ }
+ while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.Len() > aAppendStr.Len()) );
+ if ( aSize.Width()+4 >= nMaxWidth )
+ {
+ pItem->maFormatText.Assign( '.' );
+ aSize.Width() = 1;
+ }
+ }
+
+ if( pItem->maFormatText.Len() == 0 )
+ {
+ if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
+ aSize.Height() = aImageSize.Height()+4;
+ }
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::ImplGetTabRect( USHORT nItemPos, long nWidth, long nHeight )
+{
+ Size aWinSize = Control::GetOutputSizePixel();
+ if ( nWidth == -1 )
+ nWidth = aWinSize.Width();
+ if ( nHeight == -1 )
+ nHeight = aWinSize.Height();
+
+ if ( mpTabCtrlData->maItemList.empty() )
+ {
+ return Rectangle( Point( TAB_OFFSET, TAB_OFFSET ),
+ Size( nWidth-TAB_OFFSET*2, nHeight-TAB_OFFSET*2 ) );
+ }
+
+ if ( nItemPos == TAB_PAGERECT )
+ {
+ USHORT nLastPos;
+ if ( mnCurPageId )
+ nLastPos = GetPagePos( mnCurPageId );
+ else
+ nLastPos = 0;
+
+ Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
+ aRect = Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ),
+ Size( nWidth-TAB_OFFSET*2,
+ nHeight-aRect.Bottom()-TAB_OFFSET*2 ) );
+ return aRect;
+ }
+
+ nWidth -= 1;
+
+ if ( (nWidth <= 0) || (nHeight <= 0) )
+ return Rectangle();
+
+ if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
+ {
+ Font aFont( GetFont() );
+ Font aLightFont = aFont;
+ aFont.SetTransparent( TRUE );
+ aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT );
+ aLightFont.SetTransparent( TRUE );
+ aLightFont.SetWeight( WEIGHT_LIGHT );
+
+ // If Bold and none Bold strings have the same width, we
+ // add in the calcultion extra space, so that the tabs
+ // looks better. The could be the case on systems without
+ // an bold UI font and without synthetic bold support
+ XubString aTestStr( RTL_CONSTASCII_USTRINGPARAM( "Abc." ) );
+ SetFont( aLightFont );
+ long nTextWidth1 = GetTextWidth( aTestStr );
+ SetFont( aFont );
+ long nTextWidth2 = GetTextWidth( aTestStr );
+ mbExtraSpace = (nTextWidth1 == nTextWidth2);
+
+ Size aSize;
+ const long nOffsetX = 2 + GetItemsOffset().X();
+ const long nOffsetY = 2 + GetItemsOffset().Y();
+ long nX = nOffsetX;
+ long nY = nOffsetY;
+ long nMaxWidth = nWidth;
+ USHORT nPos = 0;
+
+ if ( (mnMaxPageWidth > 0) && (mnMaxPageWidth < nMaxWidth) )
+ nMaxWidth = mnMaxPageWidth;
+ nMaxWidth -= GetItemsOffset().X();
+
+ mbScroll = FALSE;
+
+ USHORT nLines = 0;
+ USHORT nCurLine = 0;
+ long nLineWidthAry[100];
+ USHORT nLinePosAry[101];
+
+ nLineWidthAry[0] = 0;
+ nLinePosAry[0] = 0;
+ for( std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ aSize = ImplGetItemSize( &(*it), nMaxWidth );
+
+ if ( ((nX+aSize.Width()) > nWidth - 2) && (nWidth > 2+nOffsetX) )
+ {
+ if ( nLines == 99 )
+ break;
+
+ nX = nOffsetX;
+ nY += aSize.Height();
+ nLines++;
+ nLineWidthAry[nLines] = 0;
+ nLinePosAry[nLines] = nPos;
+ }
+
+ Rectangle aNewRect( Point( nX, nY ), aSize );
+ if ( mbSmallInvalidate && (it->maRect != aNewRect) )
+ mbSmallInvalidate = FALSE;
+ it->maRect = aNewRect;
+ it->mnLine = nLines;
+ it->mbFullVisible = TRUE;
+
+ nLineWidthAry[nLines] += aSize.Width();
+ nX += aSize.Width();
+
+ if ( it->mnId == mnCurPageId )
+ nCurLine = nLines;
+
+ nPos++;
+ }
+
+ if ( nLines && !mpTabCtrlData->maItemList.empty() )
+ {
+ long nDX = 0;
+ long nModDX = 0;
+ long nIDX = 0;
+ USHORT i;
+ USHORT n;
+ long nLineHeightAry[100];
+ long nIH = mpTabCtrlData->maItemList[0].maRect.Bottom()-2;
+
+ i = 0;
+ while ( i < nLines+1 )
+ {
+ if ( i <= nCurLine )
+ nLineHeightAry[i] = nIH*(nLines-(nCurLine-i)) + GetItemsOffset().Y();
+ else
+ nLineHeightAry[i] = nIH*(i-nCurLine-1) + GetItemsOffset().Y();
+ i++;
+ }
+
+ i = 0;
+ n = 0;
+ nLinePosAry[nLines+1] = (USHORT)mpTabCtrlData->maItemList.size();
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( i == nLinePosAry[n] )
+ {
+ if ( n == nLines+1 )
+ break;
+
+ nIDX = 0;
+ if( nLinePosAry[n+1]-i > 0 )
+ {
+ nDX = (nWidth-nOffsetX-nLineWidthAry[n]) / (nLinePosAry[n+1]-i);
+ nModDX = (nWidth-nOffsetX-nLineWidthAry[n]) % (nLinePosAry[n+1]-i);
+ }
+ else
+ {
+ // FIXME: this is a bad case of tabctrl way too small
+ nDX = 0;
+ nModDX = 0;
+ }
+ n++;
+ }
+
+ it->maRect.Left() += nIDX;
+ it->maRect.Right() += nIDX+nDX;
+ it->maRect.Top() = nLineHeightAry[n-1];
+ it->maRect.Bottom() = nLineHeightAry[n-1]+nIH;
+ nIDX += nDX;
+
+ if ( nModDX )
+ {
+ nIDX++;
+ it->maRect.Right()++;
+ nModDX--;
+ }
+
+ i++;
+ }
+ }
+ else
+ {//only one line
+ if(ImplGetSVData()->maNWFData.mbCenteredTabs)
+ {
+ int nRightSpace=nMaxWidth;//space left on the right by the tabs
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ nRightSpace-=it->maRect.Right()-it->maRect.Left();
+ }
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ it->maRect.Left()+=(int) (nRightSpace/2);
+ it->maRect.Right()+=(int) (nRightSpace/2);
+ }
+ }
+ }
+
+ mnLastWidth = nWidth;
+ mnLastHeight = nHeight;
+ mbFormat = FALSE;
+
+ ImplPosScrollBtns();
+ }
+
+ return size_t(nItemPos) < mpTabCtrlData->maItemList.size() ? mpTabCtrlData->maItemList[nItemPos].maRect : Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplChangeTabPage( USHORT nId, USHORT nOldId )
+{
+ ImplFreeLayoutData();
+
+ ImplTabItem* pOldItem = ImplGetItem( nOldId );
+ ImplTabItem* pItem = ImplGetItem( nId );
+ TabPage* pOldPage = (pOldItem) ? pOldItem->mpTabPage : NULL;
+ TabPage* pPage = (pItem) ? pItem->mpTabPage : NULL;
+ Window* pCtrlParent = GetParent();
+
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ USHORT nPos = GetPagePos( nId );
+ Rectangle aRect = ImplGetTabRect( nPos );
+
+ if ( !pOldItem || (pOldItem->mnLine != pItem->mnLine) )
+ {
+ aRect.Left() = 0;
+ aRect.Top() = 0;
+ aRect.Right() = Control::GetOutputSizePixel().Width();
+ }
+ else
+ {
+ aRect.Left() -= 3;
+ aRect.Top() -= 2;
+ aRect.Right() += 3;
+ Invalidate( aRect );
+ nPos = GetPagePos( nOldId );
+ aRect = ImplGetTabRect( nPos );
+ aRect.Left() -= 3;
+ aRect.Top() -= 2;
+ aRect.Right() += 3;
+ }
+ Invalidate( aRect );
+ }
+
+ if ( pOldPage == pPage )
+ return;
+
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+
+ if ( pOldPage )
+ {
+ if ( mbRestoreHelpId )
+ pCtrlParent->SetHelpId( 0 );
+ if ( mbRestoreUnqId )
+ pCtrlParent->SetUniqueId( 0 );
+ if( mbRestoreSmartId )
+ pCtrlParent->SetSmartHelpId( SmartId() );
+ pOldPage->DeactivatePage();
+ }
+
+ if ( pPage )
+ {
+ pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
+
+ // activate page here so the conbtrols can be switched
+ // also set the help id of the parent window to that of the tab page
+ if ( !GetHelpId() )
+ {
+ mbRestoreHelpId = TRUE;
+ pCtrlParent->SetHelpId( pPage->GetHelpId() );
+ }
+ if ( !pCtrlParent->GetUniqueId() )
+ {
+ mbRestoreUnqId = TRUE;
+ pCtrlParent->SetUniqueId( pPage->GetUniqueId() );
+ }
+ if( ! GetSmartHelpId().HasAny() )
+ {
+ mbRestoreSmartId = TRUE;
+ pCtrlParent->SetSmartHelpId( pPage->GetSmartHelpId() );
+ }
+
+ pPage->ActivatePage();
+
+ if ( pOldPage && pOldPage->HasChildPathFocus() )
+ {
+ USHORT n = 0;
+ Window* pFirstChild = pPage->ImplGetDlgWindow( n, DLGWINDOW_FIRST );
+ if ( pFirstChild )
+ pFirstChild->ImplControlFocus( GETFOCUS_INIT );
+ else
+ GrabFocus();
+ }
+
+ pPage->Show();
+ }
+
+ if ( pOldPage )
+ pOldPage->Hide();
+
+ // Invalidate the same region that will be send to NWF
+ // to always allow for bitmap caching
+ // see Window::DrawNativeControl()
+ if( IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL ) )
+ {
+ aRect.Left() -= TAB_OFFSET;
+ aRect.Top() -= TAB_OFFSET;
+ aRect.Right() += TAB_OFFSET;
+ aRect.Bottom() += TAB_OFFSET;
+ }
+
+ Invalidate( aRect );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL TabControl::ImplPosCurTabPage()
+{
+ // Aktuelle TabPage resizen/positionieren
+ ImplTabItem* pItem = ImplGetItem( GetCurPageId() );
+ if ( pItem && pItem->mpTabPage )
+ {
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+ pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplActivateTabPage( BOOL bNext )
+{
+ USHORT nCurPos = GetPagePos( GetCurPageId() );
+
+ if ( bNext )
+ nCurPos = (nCurPos + 1) % GetPageCount();
+ else
+ {
+ if ( !nCurPos )
+ nCurPos = GetPageCount()-1;
+ else
+ nCurPos--;
+ }
+
+ SelectTabPage( GetPageId( nCurPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplSetFirstPagePos( USHORT )
+{
+ return; // was only required for single line
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplShowFocus()
+{
+ if ( !GetPageCount() || mpTabCtrlData->mpListBox )
+ return;
+
+ // make sure the focussed item rect is computed using a bold font
+ // the font may have changed meanwhile due to mouse over
+
+ Font aOldFont( GetFont() );
+ Font aFont( aOldFont );
+ aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT );
+ SetFont( aFont );
+
+ USHORT nCurPos = GetPagePos( mnCurPageId );
+ Rectangle aRect = ImplGetTabRect( nCurPos );
+ const ImplTabItem& rItem = mpTabCtrlData->maItemList[ nCurPos ];
+ Size aTabSize = aRect.GetSize();
+ Size aImageSize( 0, 0 );
+ long nTextHeight = GetTextHeight();
+ long nTextWidth = GetCtrlTextWidth( rItem.maFormatText );
+ USHORT nOff;
+
+ if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_MONO) )
+ nOff = 1;
+ else
+ nOff = 0;
+
+ if( !! rItem.maTabImage )
+ {
+ aImageSize = rItem.maTabImage.GetSizePixel();
+ if( rItem.maFormatText.Len() )
+ aImageSize.Width() += GetTextHeight()/4;
+ }
+
+ if( rItem.maFormatText.Len() )
+ {
+ // show focus around text
+ aRect.Left() = aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1;
+ aRect.Top() = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1;
+ aRect.Right() = aRect.Left()+nTextWidth+2;
+ aRect.Bottom() = aRect.Top()+nTextHeight+2;
+ }
+ else
+ {
+ // show focus around image
+ long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
+ long nYPos = aRect.Top();
+ if( aImageSize.Height() < aRect.GetHeight() )
+ nYPos += (aRect.GetHeight() - aImageSize.Height())/2;
+
+ aRect.Left() = nXPos - 2;
+ aRect.Top() = nYPos - 2;
+ aRect.Right() = aRect.Left() + aImageSize.Width() + 4;
+ aRect.Bottom() = aRect.Top() + aImageSize.Height() + 4;
+ }
+ ShowFocus( aRect );
+
+ SetFont( aOldFont );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplDrawItem( ImplTabItem* pItem, const Rectangle& rCurRect, bool bLayout, bool bFirstInGroup, bool bLastInGroup, bool bIsCurrentItem )
+{
+ if ( pItem->maRect.IsEmpty() )
+ return;
+
+ if( bLayout )
+ {
+ if( !HasLayoutData() )
+ {
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ mpTabCtrlData->maLayoutLineToPageId.clear();
+ mpTabCtrlData->maLayoutPageIdToLine.clear();
+ mpTabCtrlData->maTabRectangles.clear();
+ }
+ }
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Rectangle aRect = pItem->maRect;
+ long nLeftBottom = aRect.Bottom();
+ long nRightBottom = aRect.Bottom();
+ BOOL bLeftBorder = TRUE;
+ BOOL bRightBorder = TRUE;
+ USHORT nOff;
+ BOOL bNativeOK = FALSE;
+
+ USHORT nOff2 = 0;
+ USHORT nOff3 = 0;
+
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ nOff = 1;
+ else
+ nOff = 0;
+
+ // Wenn wir die aktuelle Page sind, muessen wir etwas mehr zeichnen
+ if ( pItem->mnId == mnCurPageId )
+ {
+ nOff2 = 2;
+ if( ! ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise )
+ nOff3 = 1;
+ }
+ else
+ {
+ Point aLeftTestPos = aRect.BottomLeft();
+ Point aRightTestPos = aRect.BottomRight();
+ if ( aLeftTestPos.Y() == rCurRect.Bottom() )
+ {
+ aLeftTestPos.X() -= 2;
+ if ( rCurRect.IsInside( aLeftTestPos ) )
+ bLeftBorder = FALSE;
+ aRightTestPos.X() += 2;
+ if ( rCurRect.IsInside( aRightTestPos ) )
+ bRightBorder = FALSE;
+ }
+ else
+ {
+ if ( rCurRect.IsInside( aLeftTestPos ) )
+ nLeftBottom -= 2;
+ if ( rCurRect.IsInside( aRightTestPos ) )
+ nRightBottom -= 2;
+ }
+ }
+
+ if( !bLayout && (bNativeOK = IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL)) == TRUE )
+ {
+ Rectangle aCtrlRegion( pItem->maRect );
+ ControlState nState = 0;
+
+ if( pItem->mnId == mnCurPageId )
+ {
+ nState |= CTRL_STATE_SELECTED;
+ // only the selected item can be focussed
+ if ( HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ }
+ if ( IsEnabled() )
+ nState |= CTRL_STATE_ENABLED;
+ if( IsMouseOver() && pItem->maRect.IsInside( GetPointerPosPixel() ) )
+ {
+ nState |= CTRL_STATE_ROLLOVER;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if( (&(*it) != pItem) && (it->maRect.IsInside( GetPointerPosPixel() ) ) )
+ {
+ nState &= ~CTRL_STATE_ROLLOVER; // avoid multiple highlighted tabs
+ break;
+ }
+ }
+ }
+
+ TabitemValue tiValue;
+ if(pItem->maRect.Left() < 5)
+ tiValue.mnAlignment |= TABITEM_LEFTALIGNED;
+ if(pItem->maRect.Right() > mnLastWidth - 5)
+ tiValue.mnAlignment |= TABITEM_RIGHTALIGNED;
+ if ( bFirstInGroup )
+ tiValue.mnAlignment |= TABITEM_FIRST_IN_GROUP;
+ if ( bLastInGroup )
+ tiValue.mnAlignment |= TABITEM_LAST_IN_GROUP;
+
+ bNativeOK = DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ tiValue, rtl::OUString() );
+ }
+
+ if( ! bLayout && !bNativeOK )
+ {
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ {
+ SetLineColor( rStyleSettings.GetLightColor() );
+ DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) ); // diagonally indented top-left pixel
+ if ( bLeftBorder )
+ {
+ DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
+ Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
+ }
+ DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ), // top line starting 2px from left border
+ Point( aRect.Right()+nOff2-3, aRect.Top()-nOff2 ) ); // ending 3px from right border
+
+ if ( bRightBorder )
+ {
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ),
+ Point( aRect.Right()+nOff2-2, nRightBottom-1 ) );
+
+ SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+3-nOff2 ),
+ Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
+ }
+ }
+ else
+ {
+ SetLineColor( Color( COL_BLACK ) );
+ DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) );
+ DrawPixel( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ) );
+ if ( bLeftBorder )
+ {
+ DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
+ Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
+ }
+ DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ),
+ Point( aRect.Right()-3, aRect.Top()-nOff2 ) );
+ if ( bRightBorder )
+ {
+ DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+2-nOff2 ),
+ Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
+ }
+ }
+ }
+
+ if( bLayout )
+ {
+ int nLine = mpControlData->mpLayoutData->m_aLineIndices.size();
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
+ mpTabCtrlData->maLayoutPageIdToLine[ (int)pItem->mnId ] = nLine;
+ mpTabCtrlData->maLayoutLineToPageId[ nLine ] = (int)pItem->mnId;
+ mpTabCtrlData->maTabRectangles.push_back( aRect );
+ }
+
+ // set font accordingly, current item is painted bold
+ // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints)
+ Font aFont( GetFont() );
+ aFont.SetTransparent( TRUE );
+ aFont.SetWeight( ((bIsCurrentItem) && (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus)) ? WEIGHT_BOLD : WEIGHT_LIGHT );
+ SetFont( aFont );
+
+ Size aTabSize = aRect.GetSize();
+ Size aImageSize( 0, 0 );
+ long nTextHeight = GetTextHeight();
+ long nTextWidth = GetCtrlTextWidth( pItem->maFormatText );
+ if( !! pItem->maTabImage )
+ {
+ aImageSize = pItem->maTabImage.GetSizePixel();
+ if( pItem->maFormatText.Len() )
+ aImageSize.Width() += GetTextHeight()/4;
+ }
+ long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-nOff3;
+ long nYPos = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-nOff3;
+ if( pItem->maFormatText.Len() )
+ {
+ USHORT nStyle = TEXT_DRAW_MNEMONIC;
+ if( ! pItem->mbEnabled )
+ nStyle |= TEXT_DRAW_DISABLE;
+ DrawCtrlText( Point( nXPos + aImageSize.Width(), nYPos ),
+ pItem->maFormatText,
+ 0, STRING_LEN, nStyle,
+ bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL,
+ bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL
+ );
+ }
+
+ if( !! pItem->maTabImage )
+ {
+ Point aImgTL( nXPos, aRect.Top() );
+ if( aImageSize.Height() < aRect.GetHeight() )
+ aImgTL.Y() += (aRect.GetHeight() - aImageSize.Height())/2;
+ DrawImage( aImgTL, pItem->maTabImage, pItem->mbEnabled ? 0 : IMAGE_DRAW_DISABLE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::ImplHandleKeyEvent( const KeyEvent& rKeyEvent )
+{
+ long nRet = 0;
+
+ if ( GetPageCount() > 1 )
+ {
+ KeyCode aKeyCode = rKeyEvent.GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+
+ if ( aKeyCode.IsMod1() )
+ {
+ if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
+ {
+ if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
+ {
+ ImplActivateTabPage( FALSE );
+ nRet = 1;
+ }
+ }
+ else
+ {
+ if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
+ {
+ ImplActivateTabPage( TRUE );
+ nRet = 1;
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( TabControl, ImplScrollBtnHdl, PushButton*, EMPTYARG )
+{
+ ImplSetScrollBtnsState();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( TabControl, ImplListBoxSelectHdl, ListBox*, EMPTYARG )
+{
+ SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectEntryPos() ) );
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( TabControl, ImplWindowEventListener, VclSimpleEvent*, pEvent )
+{
+ if ( pEvent && pEvent->ISA( VclWindowEvent ) && (pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT) )
+ {
+ VclWindowEvent* pWindowEvent = static_cast< VclWindowEvent* >(pEvent);
+ // Do not handle events from TabControl or it's children, which is done in Notify(), where the events can be consumed.
+ if ( !IsWindowOrChild( pWindowEvent->GetWindow() ) )
+ {
+ KeyEvent* pKeyEvent = static_cast< KeyEvent* >(pWindowEvent->GetData());
+ ImplHandleKeyEvent( *pKeyEvent );
+ }
+ }
+ return 0;
+}
+
+
+// -----------------------------------------------------------------------
+
+void TabControl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if( mpTabCtrlData->mpListBox == NULL )
+ {
+ if( rMEvt.IsLeft() )
+ {
+ USHORT nPageId = GetPageId( rMEvt.GetPosPixel() );
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+ if( pItem && pItem->mbEnabled )
+ SelectTabPage( nPageId );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::KeyInput( const KeyEvent& rKEvt )
+{
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->KeyInput( rKEvt );
+ else if ( GetPageCount() > 1 )
+ {
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+
+ if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) )
+ {
+ BOOL bNext = (nKeyCode == KEY_RIGHT);
+ ImplActivateTabPage( bNext );
+ }
+ }
+
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Paint( const Rectangle& rRect )
+{
+ ImplPaint( rRect, false );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout )
+{
+ if( ! bLayout )
+ HideFocus();
+
+ // Hier wird gegebenenfalls auch neu formatiert
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+
+ // find current item
+ ImplTabItem* pCurItem = NULL;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( it->mnId == mnCurPageId )
+ {
+ pCurItem = &(*it);
+ break;
+ }
+ }
+
+ // Draw the TabPage border
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Rectangle aCurRect;
+ long nTopOff = 1;
+ aRect.Left() -= TAB_OFFSET;
+ aRect.Top() -= TAB_OFFSET;
+ aRect.Right() += TAB_OFFSET;
+ aRect.Bottom() += TAB_OFFSET;
+
+ // if we have an invisible tabpage or no tabpage at all the tabpage rect should be
+ // increased to avoid round corners that might be drawn by a theme
+ // in this case we're only interested in the top border of the tabpage because the tabitems are used
+ // standalone (eg impress)
+ BOOL bNoTabPage = FALSE;
+ TabPage* pCurPage = (pCurItem) ? pCurItem->mpTabPage : NULL;
+ if( !pCurPage || !pCurPage->IsVisible() )
+ {
+ bNoTabPage = TRUE;
+ aRect.Left()-=10;
+ aRect.Right()+=10;
+ }
+
+ BOOL bNativeOK = FALSE;
+ if( ! bLayout && (bNativeOK = IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) == TRUE )
+ {
+ const ImplControlValue aControlValue;
+
+ ControlState nState = CTRL_STATE_ENABLED;
+ int part = PART_ENTIRE_CONTROL;
+ if ( !IsEnabled() )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+
+ Region aClipRgn( GetActiveClipRegion() );
+ aClipRgn.Intersect( aRect );
+ if( !rRect.IsEmpty() )
+ aClipRgn.Intersect( rRect );
+
+ if( !aClipRgn.IsEmpty() )
+ bNativeOK = DrawNativeControl( CTRL_TAB_PANE, part, aRect, nState,
+ aControlValue, rtl::OUString() );
+ }
+ else
+ {
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ SetLineColor( rStyleSettings.GetLightColor() );
+ else
+ SetLineColor( Color( COL_BLACK ) );
+ if ( pCurItem && !pCurItem->maRect.IsEmpty() )
+ {
+ aCurRect = pCurItem->maRect;
+ if( ! bLayout )
+ DrawLine( aRect.TopLeft(), Point( aCurRect.Left()-2, aRect.Top() ) );
+ if ( aCurRect.Right()+1 < aRect.Right() )
+ {
+ if( ! bLayout )
+ DrawLine( Point( aCurRect.Right(), aRect.Top() ), aRect.TopRight() );
+ }
+ else
+ nTopOff = 0;
+ }
+ else
+ if( ! bLayout )
+ DrawLine( aRect.TopLeft(), aRect.TopRight() );
+
+ if( ! bLayout )
+ {
+ DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
+
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ {
+ // if we have not tab page the bottom line of the tab page
+ // directly touches the tab items, so choose a color that fits seamlessly
+ if( bNoTabPage )
+ SetLineColor( rStyleSettings.GetDialogColor() );
+ else
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( 1, aRect.Bottom()-1 ),
+ Point( aRect.Right()-1, aRect.Bottom()-1 ) );
+ DrawLine( Point( aRect.Right()-1, aRect.Top()+nTopOff ),
+ Point( aRect.Right()-1, aRect.Bottom()-1 ) );
+ if( bNoTabPage )
+ SetLineColor( rStyleSettings.GetDialogColor() );
+ else
+ SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ DrawLine( Point( 0, aRect.Bottom() ),
+ Point( aRect.Right(), aRect.Bottom() ) );
+ DrawLine( Point( aRect.Right(), aRect.Top()+nTopOff ),
+ Point( aRect.Right(), aRect.Bottom() ) );
+ }
+ else
+ {
+ DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ }
+ }
+ }
+
+ if ( !mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == NULL )
+ {
+ // Some native toolkits (GTK+) draw tabs right-to-left, with an
+ // overlap between adjacent tabs
+ bool bDrawTabsRTL = IsNativeControlSupported( CTRL_TAB_ITEM, PART_TABS_DRAW_RTL );
+ ImplTabItem * pFirstTab = NULL;
+ ImplTabItem * pLastTab = NULL;
+ size_t idx;
+
+ // Event though there is a tab overlap with GTK+, the first tab is not
+ // overlapped on the left side. Other tookits ignore this option.
+ if ( bDrawTabsRTL )
+ {
+ pFirstTab = &mpTabCtrlData->maItemList.front();
+ pLastTab = &mpTabCtrlData->maItemList.back();
+ idx = mpTabCtrlData->maItemList.size()-1;
+ }
+ else
+ {
+ pLastTab = &mpTabCtrlData->maItemList.back();
+ pFirstTab = &mpTabCtrlData->maItemList.front();
+ idx = 0;
+ }
+
+ while ( idx < mpTabCtrlData->maItemList.size() )
+ {
+ ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
+ if ( pItem != pCurItem )
+ {
+ Region aClipRgn( GetActiveClipRegion() );
+ aClipRgn.Intersect( pItem->maRect );
+ if( !rRect.IsEmpty() )
+ aClipRgn.Intersect( rRect );
+ if( bLayout || !aClipRgn.IsEmpty() )
+ ImplDrawItem( pItem, aCurRect, bLayout, (pItem==pFirstTab), (pItem==pLastTab), FALSE );
+ }
+
+ if ( bDrawTabsRTL )
+ idx--;
+ else
+ idx++;
+ }
+
+ if ( pCurItem )
+ {
+ Region aClipRgn( GetActiveClipRegion() );
+ aClipRgn.Intersect( pCurItem->maRect );
+ if( !rRect.IsEmpty() )
+ aClipRgn.Intersect( rRect );
+ if( bLayout || !aClipRgn.IsEmpty() )
+ ImplDrawItem( pCurItem, aCurRect, bLayout, (pCurItem==pFirstTab), (pCurItem==pLastTab), TRUE );
+ }
+ }
+
+ if ( !bLayout && HasFocus() )
+ ImplShowFocus();
+
+ if( ! bLayout )
+ mbSmallInvalidate = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Resize()
+{
+ ImplFreeLayoutData();
+
+ if ( !IsReallyShown() )
+ return;
+
+ if( mpTabCtrlData->mpListBox )
+ {
+ // get the listbox' preferred size
+ Size aTabCtrlSize( GetSizePixel() );
+ long nPrefWidth = mpTabCtrlData->mpListBox->GetOptimalSize( WINDOWSIZE_PREFERRED ).Width();
+ if( nPrefWidth > aTabCtrlSize.Width() )
+ nPrefWidth = aTabCtrlSize.Width();
+ Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MAP_APPFONT ) ).Height() );
+ Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 );
+ mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize );
+ }
+
+ mbFormat = TRUE;
+
+ // Aktuelle TabPage resizen/positionieren
+ BOOL bTabPage = ImplPosCurTabPage();
+ // Feststellen, was invalidiert werden muss
+ Size aNewSize = Control::GetOutputSizePixel();
+ long nNewWidth = aNewSize.Width();
+ if ( mbScroll )
+ mbSmallInvalidate = FALSE;
+ else
+ {
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( !it->mbFullVisible ||
+ (it->maRect.Right()-2 >= nNewWidth) )
+ {
+ mbSmallInvalidate = FALSE;
+ break;
+ }
+ }
+ }
+
+ if ( mbSmallInvalidate )
+ {
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+ aRect.Left() -= TAB_OFFSET+TAB_BORDER_LEFT;
+ aRect.Top() -= TAB_OFFSET+TAB_BORDER_TOP;
+ aRect.Right() += TAB_OFFSET+TAB_BORDER_RIGHT;
+ aRect.Bottom() += TAB_OFFSET+TAB_BORDER_BOTTOM;
+ if ( bTabPage )
+ Invalidate( aRect, INVALIDATE_NOCHILDREN );
+ else
+ Invalidate( aRect );
+
+ }
+ else
+ {
+ if ( bTabPage )
+ Invalidate( INVALIDATE_NOCHILDREN );
+ else
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::GetFocus()
+{
+ if( ! mpTabCtrlData->mpListBox )
+ {
+ ImplShowFocus();
+ SetInputContext( InputContext( GetFont() ) );
+ }
+ else
+ {
+ if( mpTabCtrlData->mpListBox->IsReallyVisible() )
+ mpTabCtrlData->mpListBox->GrabFocus();
+ }
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::LoseFocus()
+{
+ if( ! mpTabCtrlData->mpListBox )
+ HideFocus();
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::RequestHelp( const HelpEvent& rHEvt )
+{
+ USHORT nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
+
+ if ( nItemId )
+ {
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ {
+ XubString aStr = GetHelpText( nItemId );
+ if ( aStr.Len() )
+ {
+ Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.Left() = aPt.X();
+ aItemRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.Right() = aPt.X();
+ aItemRect.Bottom() = aPt.Y();
+ Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
+ return;
+ }
+ }
+ else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
+ {
+ ULONG nHelpId = GetHelpId( nItemId );
+ if ( nHelpId )
+ {
+ // Wenn eine Hilfe existiert, dann ausloesen
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ pHelp->Start( nHelpId, this );
+ return;
+ }
+ }
+
+ // Bei Quick- oder Balloon-Help zeigen wir den Text an,
+ // wenn dieser abgeschnitten ist
+ if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
+ {
+ ImplTabItem* pItem = ImplGetItem( nItemId );
+ const XubString& rStr = pItem->maText;
+ if ( rStr != pItem->maFormatText )
+ {
+ Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.Left() = aPt.X();
+ aItemRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.Right() = aPt.X();
+ aItemRect.Bottom() = aPt.Y();
+ if ( rStr.Len() )
+ {
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
+ else
+ Help::ShowQuickHelp( this, aItemRect, rStr );
+ return;
+ }
+ }
+ }
+
+ if ( rHEvt.GetMode() & HELPMODE_QUICK )
+ {
+ ImplTabItem* pItem = ImplGetItem( nItemId );
+ const XubString& rHelpText = pItem->maHelpText;
+ // show tooltip if not text but image is set and helptext is available
+ if ( rHelpText.Len() > 0 && pItem->maText.Len() == 0 && !!pItem->maTabImage )
+ {
+ Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.Left() = aPt.X();
+ aItemRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.Right() = aPt.X();
+ aItemRect.Bottom() = aPt.Y();
+ Help::ShowQuickHelp( this, aItemRect, rHelpText );
+ return;
+ }
+ }
+ }
+
+ Control::RequestHelp( rHEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Command( const CommandEvent& rCEvt )
+{
+ if( (mpTabCtrlData->mpListBox == NULL) && (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) )
+ {
+ Point aMenuPos;
+ BOOL bMenu;
+ if ( rCEvt.IsMouseEvent() )
+ {
+ aMenuPos = rCEvt.GetMousePosPixel();
+ bMenu = GetPageId( aMenuPos ) != 0;
+ }
+ else
+ {
+ aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
+ bMenu = TRUE;
+ }
+
+ if ( bMenu )
+ {
+ PopupMenu aMenu;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ aMenu.InsertItem( it->mnId, it->maText, MIB_CHECKABLE | MIB_RADIOCHECK );
+ if ( it->mnId == mnCurPageId )
+ aMenu.CheckItem( it->mnId );
+ aMenu.SetHelpId( it->mnId, it->mnHelpId );
+ }
+
+ USHORT nId = aMenu.Execute( this, aMenuPos );
+ if ( nId && (nId != mnCurPageId) )
+ SelectTabPage( nId );
+ return;
+ }
+ }
+
+ Control::Command( rCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ ImplPosCurTabPage();
+ if( mpTabCtrlData->mpListBox )
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle* TabControl::ImplFindPartRect( const Point& rPt )
+{
+ ImplTabItem* pFoundItem = NULL;
+ int nFound = 0;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( it->maRect.IsInside( rPt ) )
+ {
+ // assure that only one tab is highlighted at a time
+ nFound++;
+ pFoundItem = &(*it);
+ }
+ }
+ // assure that only one tab is highlighted at a time
+ return nFound == 1 ? &pFoundItem->maRect : NULL;
+}
+
+long TabControl::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
+ if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
+ {
+ Region aClipRgn;
+ if( pLastRect )
+ {
+ // allow for slightly bigger tabitems
+ // as used by gtk
+ // TODO: query for the correct sizes
+ Rectangle aRect(*pLastRect);
+ aRect.nLeft-=2;
+ aRect.nRight+=2;
+ aRect.nTop-=3;
+ aClipRgn.Union( aRect );
+ }
+ if( pRect )
+ {
+ // allow for slightly bigger tabitems
+ // as used by gtk
+ // TODO: query for the correct sizes
+ Rectangle aRect(*pRect);
+ aRect.nLeft-=2;
+ aRect.nRight+=2;
+ aRect.nTop-=3;
+ aClipRgn.Union( aRect );
+ }
+ if( !aClipRgn.IsEmpty() )
+ Invalidate( aClipRgn );
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Control::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::Notify( NotifyEvent& rNEvt )
+{
+ long nRet = 0;
+
+ if ( rNEvt.GetType() == EVENT_KEYINPUT )
+ nRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
+
+ return nRet ? nRet : Control::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ActivatePage()
+{
+ maActivateHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::DeactivatePage()
+{
+ if ( maDeactivateHdl.IsSet() )
+ return maDeactivateHdl.Call( this );
+ else
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetTabPageSizePixel( const Size& rSize )
+{
+ ImplFreeLayoutData();
+
+ Size aNewSize( rSize );
+ aNewSize.Width() += TAB_OFFSET*2;
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT,
+ aNewSize.Width(), aNewSize.Height() );
+ aNewSize.Height() += aRect.Top()+TAB_OFFSET;
+ Window::SetOutputSizePixel( aNewSize );
+}
+
+// -----------------------------------------------------------------------
+
+Size TabControl::GetTabPageSizePixel() const
+{
+ Rectangle aRect = ((TabControl*)this)->ImplGetTabRect( TAB_PAGERECT );
+ return aRect.GetSize();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::InsertPage( const ResId& rResId, USHORT nPos )
+{
+ GetRes( rResId.SetRT( RSC_TABCONTROLITEM ) );
+
+ ULONG nObjMask = ReadLongRes();
+ USHORT nItemId = 1;
+
+ // ID
+ if ( nObjMask & RSC_TABCONTROLITEM_ID )
+ nItemId = sal::static_int_cast<USHORT>(ReadLongRes());
+
+ // Text
+ XubString aTmpStr;
+ if( nObjMask & RSC_TABCONTROLITEM_TEXT )
+ aTmpStr = ReadStringRes();
+ InsertPage( nItemId, aTmpStr, nPos );
+
+ // PageResID
+ if ( nObjMask & RSC_TABCONTROLITEM_PAGERESID )
+ {
+ ImplTabItem& rItem = mpTabCtrlData->maItemList[ GetPagePos( nItemId ) ];
+ rItem.mnTabPageResId = sal::static_int_cast<USHORT>(ReadLongRes());
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::InsertPage( USHORT nPageId, const XubString& rText,
+ USHORT nPos )
+{
+ DBG_ASSERT( nPageId, "TabControl::InsertPage(): PageId == 0" );
+ DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND,
+ "TabControl::InsertPage(): PageId already exists" );
+
+ // insert new page item
+ ImplTabItem* pItem = NULL;
+ if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
+ {
+ mpTabCtrlData->maItemList.push_back( ImplTabItem() );
+ pItem = &mpTabCtrlData->maItemList.back();
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->InsertEntry( rText );
+ }
+ else
+ {
+ std::vector< ImplTabItem >::iterator new_it =
+ mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() );
+ pItem = &(*new_it);
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
+ }
+ if( mpTabCtrlData->mpListBox )
+ {
+ if( ! mnCurPageId )
+ mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
+ mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
+ }
+
+ // set current page id
+ if ( !mnCurPageId )
+ mnCurPageId = nPageId;
+
+ // init new page item
+ pItem->mnId = nPageId;
+ pItem->mpTabPage = NULL;
+ pItem->mnTabPageResId = 0;
+ pItem->mnHelpId = 0;
+ pItem->maText = rText;
+ pItem->mbFullVisible = FALSE;
+
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+
+ ImplFreeLayoutData();
+ if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
+ Resize();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_INSERTED, (void*) (ULONG)nPageId );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::RemovePage( USHORT nPageId )
+{
+ USHORT nPos = GetPagePos( nPageId );
+
+ // does the item exist ?
+ if ( nPos != TAB_PAGE_NOTFOUND )
+ {
+ //remove page item
+ std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
+ bool bIsCurrentPage = (it->mnId == mnCurPageId);
+ mpTabCtrlData->maItemList.erase( it );
+ if( mpTabCtrlData->mpListBox )
+ {
+ mpTabCtrlData->mpListBox->RemoveEntry( nPos );
+ mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
+ }
+
+ // If current page is removed, than first page gets the current page
+ if ( bIsCurrentPage )
+ {
+ mnCurPageId = 0;
+
+ if( ! mpTabCtrlData->maItemList.empty() )
+ {
+ // don't do this by simply setting mnCurPageId to pFirstItem->mnId
+ // this leaves a lot of stuff (such trivias as _showing_ the new current page) undone
+ // instead, call SetCurPageId
+ // without this, the next (outside) call to SetCurPageId with the id of the first page
+ // will result in doing nothing (as we assume that nothing changed, then), and the page
+ // will never be shown.
+ // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
+
+ SetCurPageId( mpTabCtrlData->maItemList[0].mnId );
+ }
+ }
+
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+
+ ImplFreeLayoutData();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVED, (void*) (ULONG) nPageId );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Clear()
+{
+ // clear item list
+ mpTabCtrlData->maItemList.clear();
+ mnCurPageId = 0;
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->Clear();
+
+ ImplFreeLayoutData();
+
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVEDALL );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::EnablePage( USHORT i_nPageId, bool i_bEnable )
+{
+ ImplTabItem* pItem = ImplGetItem( i_nPageId );
+
+ if ( pItem && pItem->mbEnabled != i_bEnable )
+ {
+ pItem->mbEnabled = i_bEnable;
+ mbFormat = TRUE;
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
+ i_bEnable ? 0 : (LISTBOX_ENTRY_FLAG_DISABLE_SELECTION | LISTBOX_ENTRY_FLAG_DRAW_DISABLED) );
+ if( pItem->mnId == mnCurPageId )
+ {
+ // SetCurPageId will change to an enabled page
+ SetCurPageId( mnCurPageId );
+ }
+ else if ( IsUpdateMode() )
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPageCount() const
+{
+ return (USHORT)mpTabCtrlData->maItemList.size();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPageId( USHORT nPos ) const
+{
+ if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
+ return mpTabCtrlData->maItemList[ nPos ].mnId;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPagePos( USHORT nPageId ) const
+{
+ for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( it->mnId == nPageId )
+ return (USHORT)(it - mpTabCtrlData->maItemList.begin());
+ }
+
+ return TAB_PAGE_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPageId( const Point& rPos ) const
+{
+ for( size_t i = 0; i < mpTabCtrlData->maItemList.size(); ++i )
+ {
+ if ( ((TabControl*)this)->ImplGetTabRect( static_cast<USHORT>(i) ).IsInside( rPos ) )
+ return mpTabCtrlData->maItemList[ i ].mnId;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetCurPageId( USHORT nPageId )
+{
+ USHORT nPos = GetPagePos( nPageId );
+ while( nPos != TAB_PAGE_NOTFOUND &&
+ ! mpTabCtrlData->maItemList[nPos].mbEnabled )
+ {
+ nPos++;
+ if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
+ nPos = 0;
+ if( mpTabCtrlData->maItemList[nPos].mnId == nPageId )
+ break;
+ }
+
+ if( nPos != TAB_PAGE_NOTFOUND )
+ {
+ nPageId = mpTabCtrlData->maItemList[nPos].mnId;
+ if ( nPageId == mnCurPageId )
+ {
+ if ( mnActPageId )
+ mnActPageId = nPageId;
+ return;
+ }
+
+ if ( mnActPageId )
+ mnActPageId = nPageId;
+ else
+ {
+ mbFormat = TRUE;
+ USHORT nOldId = mnCurPageId;
+ mnCurPageId = nPageId;
+ ImplChangeTabPage( nPageId, nOldId );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetCurPageId() const
+{
+ if ( mnActPageId )
+ return mnActPageId;
+ else
+ return mnCurPageId;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetFirstPageId( USHORT )
+{
+ return; // was only required for single line
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SelectTabPage( USHORT nPageId )
+{
+ if ( nPageId && (nPageId != mnCurPageId) )
+ {
+ ImplFreeLayoutData();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_DEACTIVATE, (void*) (ULONG) mnCurPageId );
+ if ( DeactivatePage() )
+ {
+ mnActPageId = nPageId;
+ ActivatePage();
+ // Page koennte im Activate-Handler umgeschaltet wurden sein
+ nPageId = mnActPageId;
+ mnActPageId = 0;
+ SetCurPageId( nPageId );
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
+ ImplCallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, (void*) (ULONG) nPageId );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetTabPage( USHORT nPageId, TabPage* pTabPage )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem && (pItem->mpTabPage != pTabPage) )
+ {
+ if ( pTabPage )
+ {
+ DBG_ASSERT( !pTabPage->IsVisible(), "TabControl::SetTabPage() - Page is visible" );
+
+ if ( IsDefaultSize() )
+ SetTabPageSizePixel( pTabPage->GetSizePixel() );
+
+ // Erst hier setzen, damit Resize nicht TabPage umpositioniert
+ pItem->mpTabPage = pTabPage;
+ if ( pItem->mnId == mnCurPageId )
+ ImplChangeTabPage( pItem->mnId, 0 );
+ }
+ else
+ pItem->mpTabPage = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TabPage* TabControl::GetTabPage( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ return pItem->mpTabPage;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetTabPageResId( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ return pItem->mnTabPageResId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetPageText( USHORT nPageId, const XubString& rText )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem && pItem->maText != rText )
+ {
+ pItem->maText = rText;
+ mbFormat = TRUE;
+ if( mpTabCtrlData->mpListBox )
+ {
+ USHORT nPos = GetPagePos( nPageId );
+ mpTabCtrlData->mpListBox->RemoveEntry( nPos );
+ mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
+ }
+ if ( IsUpdateMode() )
+ Invalidate();
+ ImplFreeLayoutData();
+ ImplCallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED, (void*) (ULONG) nPageId );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString TabControl::GetPageText( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ return pItem->maText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetHelpText( USHORT nPageId, const XubString& rText )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ pItem->maHelpText = rText;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& TabControl::GetHelpText( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ {
+ if ( !pItem->maHelpText.Len() && pItem->mnHelpId )
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ pItem->maHelpText = pHelp->GetHelpText( pItem->mnHelpId, this );
+ }
+
+ return pItem->maHelpText;
+ }
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetHelpId( USHORT nPageId, ULONG nHelpId )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ pItem->mnHelpId = nHelpId;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG TabControl::GetHelpId( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ return pItem->mnHelpId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetPageImage( USHORT i_nPageId, const Image& i_rImage )
+{
+ ImplTabItem* pItem = ImplGetItem( i_nPageId );
+
+ if ( pItem )
+ {
+ pItem->maTabImage = i_rImage;
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Image* TabControl::GetPageImage( USHORT i_nPageId ) const
+{
+ const ImplTabItem* pItem = ImplGetItem( i_nPageId );
+ return pItem ? &pItem->maTabImage : NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::GetCharacterBounds( USHORT nPageId, long nIndex ) const
+{
+ Rectangle aRet;
+
+ if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
+ FillLayoutData();
+
+ if( HasLayoutData() )
+ {
+ std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPageId );
+ if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
+ {
+ Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( it->second );
+ if( (aPair.B() - aPair.A()) >= nIndex )
+ aRet = mpControlData->mpLayoutData->GetCharacterBounds( aPair.A() + nIndex );
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::GetIndexForPoint( const Point& rPoint, USHORT& rPageId ) const
+{
+ long nRet = -1;
+
+ if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
+ FillLayoutData();
+
+ if( HasLayoutData() )
+ {
+ int nIndex = mpControlData->mpLayoutData->GetIndexForPoint( rPoint );
+ if( nIndex != -1 )
+ {
+ // what line (->pageid) is this index in ?
+ int nLines = mpControlData->mpLayoutData->GetLineCount();
+ int nLine = -1;
+ while( ++nLine < nLines )
+ {
+ Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( nLine );
+ if( aPair.A() <= nIndex && aPair.B() >= nIndex )
+ {
+ nRet = nIndex - aPair.A();
+ rPageId = (USHORT)mpTabCtrlData->maLayoutLineToPageId[ nLine ];
+ break;
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::FillLayoutData() const
+{
+ mpTabCtrlData->maLayoutLineToPageId.clear();
+ mpTabCtrlData->maLayoutPageIdToLine.clear();
+ const_cast<TabControl*>(this)->ImplPaint( Rectangle(), true );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::GetTabPageBounds( USHORT nPage ) const
+{
+ Rectangle aRet;
+
+ if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
+ FillLayoutData();
+
+ if( HasLayoutData() )
+ {
+ std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPage );
+ if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
+ {
+ if( it->second >= 0 && it->second < static_cast<int>(mpTabCtrlData->maTabRectangles.size()) )
+ {
+ aRet = mpTabCtrlData->maTabRectangles[ it->second ];
+ aRet.Union( const_cast<TabControl*>(this)->ImplGetTabRect( TAB_PAGERECT ) );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::GetTabBounds( USHORT nPageId ) const
+{
+ Rectangle aRet;
+
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+ if(pItem)
+ aRet = pItem->maRect;
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetItemsOffset( const Point& rOffs )
+{
+ if( mpTabCtrlData )
+ mpTabCtrlData->maItemsOffset = rOffs;
+}
+
+Point TabControl::GetItemsOffset() const
+{
+ if( mpTabCtrlData )
+ return mpTabCtrlData->maItemsOffset;
+ else
+ return Point();
+}
+
+// -----------------------------------------------------------------------
+
+Size TabControl::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return mpTabCtrlData ? mpTabCtrlData->maMinSize : Size();
+ default:
+ return Control::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetMinimumSizePixel( const Size& i_rSize )
+{
+ if( mpTabCtrlData )
+ mpTabCtrlData->maMinSize = i_rSize;
+}
+
+// -----------------------------------------------------------------------
+
+
diff --git a/vcl/source/fontsubset/cff.cxx b/vcl/source/fontsubset/cff.cxx
new file mode 100644
index 000000000000..cb565122ea63
--- /dev/null
+++ b/vcl/source/fontsubset/cff.cxx
@@ -0,0 +1,2417 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <cstdio>
+#include <cstring>
+#include <assert.h>
+
+#include <vcl/fontsubset.hxx>
+#include <vcl/strhelper.hxx>
+
+//#define IGNORE_HINTS
+
+typedef unsigned char U8;
+typedef unsigned short U16;
+typedef long long S64;
+
+typedef sal_Int32 GlyphWidth;
+
+typedef float RealType;
+typedef RealType ValType;
+#include <vector>
+typedef std::vector<ValType> ValVector;
+
+// ====================================================================
+
+static const char* pStringIds[] = {
+/*0*/ ".notdef", "space", "exclam", "quotedbl",
+ "numbersign", "dollar", "percent", "ampersand",
+ "quoteright", "parenleft", "parenright", "asterisk",
+ "plus", "comma", "hyphen", "period",
+/*16*/ "slash", "zero", "one", "two",
+ "three", "four", "five", "six",
+ "seven", "eight", "nine", "colon",
+ "semicolon", "less", "equal", "greater",
+/*32*/ "question", "at", "A", "B",
+ "C", "D", "E", "F",
+ "G", "H", "I", "J",
+ "K", "L", "M", "N",
+/*48*/ "O", "P", "Q", "R",
+ "S", "T", "U", "V",
+ "W", "X", "Y", "Z",
+ "bracketleft", "backslash", "bracketright", "asciicircum",
+/*64*/ "underscore", "quoteleft", "a", "b",
+ "c", "d", "e", "f",
+ "g", "h", "i", "j",
+ "k", "l", "m", "n",
+/*80*/ "o", "p", "q", "r",
+ "s", "t", "u", "v",
+ "w", "x", "y", "z",
+ "braceleft", "bar", "braceright", "asciitilde",
+/*96*/ "exclamdown", "cent", "sterlin", "fraction",
+ "yen", "florin", "section", "currency",
+ "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
+ "guilsinglright", "fi", "fl", "endash",
+/*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
+ "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
+ "guillemotright", "ellipsis", "perthousand", "questiondown",
+ "grave", "acute", "circumflex", "tilde",
+/*128*/ "macron", "breve", "dotaccent", "dieresis",
+ "ring", "cedilla", "hungarumlaut", "ogonek",
+ "caron", "endash", "AE", "ordfeminine",
+ "Lslash", "Oslash", "OE", "ordmasculine",
+/*144*/ "ae", "dotlessi", "lslash", "oslash",
+ "oe", "germandbls", "onesuperior", "logicalnot",
+ "mu", "trademark", "Eth", "onehalf",
+ "plusminus", "Thorn", "onequarter", "divide",
+/*160*/ "brokenbar", "degree", "thorn", "threequarters",
+ "twosuperior", "registered", "minus", "eth",
+ "multiply", "threesuperior", "copyright", "Aacute",
+ "Acircumflex", "Adieresis", "Agrave", "Aring",
+/*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
+ "Edieresis", "Egrave", "Iacute", "Icircumflex",
+ "Idieresis", "Igrave", "Ntilde", "Oacute",
+ "Ocircumflex", "Odieresis", "Ograve", "Otilde",
+/*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
+ "Ugrave", "Yacute", "Ydieresis", "Zcaron",
+ "aacute", "acircumflex", "adieresis", "agrave",
+ "aring", "atilde", "ccedilla", "eacute",
+/*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
+ "icircumflex", "idieresis", "igrave", "ntilde",
+ "oacute", "ocircumflex", "odieresis", "ograve",
+ "otilde", "scaron", "uacute", "ucircumflex",
+/*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
+ "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
+ "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
+ "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
+/*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
+ "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
+ "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
+ "questionsmall", "asuperior", "bsuperior", "centsuperior",
+/*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
+ "msuperior", "nsuperior", "osuperior", "rsuperior",
+ "ssuperior", "tsuperior", "ff", "ffi",
+ "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
+/*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
+ "Csmall", "Dsmall", "Esmall", "Fsmall",
+ "Gsmall", "Hsmall", "Ismall", "Jsmall",
+ "Ksmall", "Lsmall", "Msmall", "Nsmall",
+/*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
+ "Ssmall", "Tsmall", "Usmall", "Vsmall",
+ "Wsmall", "Xsmall", "Ysmall", "Zsmall",
+ "colonmonetary", "onefitted", "rupia", "Tildesmall",
+/*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
+ "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
+ "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
+ "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
+/*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
+ "onethird", "twothirds", "zerosuperior", "foursuperior",
+ "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
+ "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
+/*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
+ "seveninferior", "eightinferior", "nineinferior", "centinferior",
+ "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
+ "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
+/*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
+ "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
+ "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
+ "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
+/*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
+ "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
+ "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
+ "001.001", "001.002", "001.003", "Black",
+/*384*/ "Bold", "Book", "Light", "Medium",
+ "Regular", "Roman", "Semibold"
+};
+
+// --------------------------------------------------------------------
+
+#if 0 // TODO: use them
+static const char* pStdEncNames[] = {
+ "ISOAdobe", "Expert", "ExpertSubSet"
+};
+#endif
+
+// --------------------------------------------------------------------
+
+// TOP DICT keywords (also covers PRIV DICT keywords)
+static const char* pDictOps[] = {
+ "sVersion", "sNotice", "sFullName", "sFamilyName",
+ "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
+ "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
+ "xESC", "nUniqueID", "aXUID", "nCharset",
+ "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
+ "nDefaultWidthX", "nNominalWidthX", NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ "shortint", "longint", "BCD", NULL
+};
+
+// --------------------------------------------------------------------
+
+// TOP DICT escapes (also covers PRIV DICT escapes)
+static const char* pDictEscs[] = {
+ "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
+ "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
+ "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
+ "dStemSnapH", "dStemSnapV", "bForceBold", NULL,
+ NULL, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
+ "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, "rROS", "nCIDFontVersion",
+ "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
+ "nFDArray", "nFDSelect", "sFontName"
+};
+
+// --------------------------------------------------------------------
+
+static const char* pType1Ops[] = {
+ NULL, "2hstem", NULL, "2vstem",
+ "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
+ "Crrcurveto", "0closepath", "Lcallsubr", "0return",
+ "xT1ESC", "2hsbw", "0endchar", NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, "2rmoveto", "1hmoveto", NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, "4vhcurveto", "4hvcurveto"
+};
+
+// --------------------------------------------------------------------
+
+static const char* pT1EscOps[] = {
+ "0dotsection", "6vstem3", "6hstem3", NULL,
+ NULL, NULL, "5seac", "4sbw",
+ NULL, "1abs", "2add", "2sub",
+ "2div", NULL, NULL, NULL,
+ "Gcallothersubr", "1pop", NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, "2setcurrentpoint"
+};
+
+// --------------------------------------------------------------------
+
+struct TYPE1OP
+{
+ enum OPS
+ {
+ HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
+ HLINETO=6, VLINETO=7, RCURVETO=8, CLOSEPATH=9,
+ CALLSUBR=10, RETURN=11, T1ESC=12, HSBW=13,
+ ENDCHAR=14, RMOVETO=21, HMOVETO=22, VHCURVETO=30,
+ HVCURVETO=31
+ };
+
+ enum ESCS
+ {
+ DOTSECTION=0, VSTEM3=1, HSTEM3=2, SEAC=6,
+ SBW=7, ABS=9, ADD=10, SUB=11,
+ DIV=12, CALLOTHERSUBR=16, POP=17, SETCURRENTPOINT=33
+ };
+};
+
+// --------------------------------------------------------------------
+
+static const char* pType2Ops[] = {
+ NULL, "hhstem", NULL, "vvstem",
+ "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
+ "Crrcurveto", NULL, "Lcallsubr", "Xreturn",
+ "xT2ESC", NULL, "eendchar", NULL,
+ NULL, NULL, "Hhstemhm", "Khintmask",
+ "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
+ ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
+ ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
+};
+
+// --------------------------------------------------------------------
+
+static const char* pT2EscOps[] = {
+ NULL, NULL, NULL, "2and",
+ "2or", "1not", NULL, NULL,
+ NULL, "1abs", "2add", "2sub",
+ "2div", NULL, "1neg", "2eq",
+ NULL, NULL, "1drop", NULL,
+ "1put", "1get", "4ifelse", "0random",
+ "2mul", NULL, "1sqrt", "1dup",
+ "2exch", "Iindex", "Rroll", NULL,
+ NULL, NULL, "7hflex", "Fflex",
+ "9hflex1", "fflex1"
+};
+
+// --------------------------------------------------------------------
+
+struct TYPE2OP
+{
+ enum OPS
+ {
+ HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
+ HLINETO=6, VLINETO=7, RCURVETO=8, CALLSUBR=10,
+ RETURN=11, T2ESC=12, ENDCHAR=14, HSTEMHM=18,
+ HINTMASK=19, CNTRMASK=20, RMOVETO=21, HMOVETO=22,
+ VSTEMHM=23, RCURVELINE=24, RLINECURVE=25, VVCURVETO=26,
+ HHCURVETO=27, SHORTINT=28, CALLGSUBR=29, VHCURVETO=30,
+ HVCURVETO=31
+ };
+
+ enum ESCS
+ {
+ AND=3, OR=4, NOT=5, ABS=9,
+ ADD=10, SUB=11, DIV=12, NEG=14,
+ EQ=15, DROP=18, PUT=20, GET=21,
+ IFELSE=22, RANDOM=23, MUL=24, SQRT=26,
+ DUP=27, EXCH=28, INDEX=29, ROLL=30,
+ HFLEX=34, FLEX=35, HFLEX1=36, FLEX1=37
+ };
+};
+
+// ====================================================================
+
+struct CffGlobal
+{
+ explicit CffGlobal();
+
+ int mnNameIdxBase;
+ int mnNameIdxCount;
+ int mnStringIdxBase;
+ int mnStringIdxCount;
+ bool mbCIDFont;
+ int mnCharStrBase;
+ int mnCharStrCount;
+ int mnEncodingBase;
+ int mnCharsetBase;
+ int mnGlobalSubrBase;
+ int mnGlobalSubrCount;
+ int mnGlobalSubrBias;
+ int mnFDSelectBase;
+ int mnFontDictBase;
+ int mnFDAryCount;
+
+ ValVector maFontBBox;
+ ValVector maFontMatrix;
+
+ int mnFontNameSID;
+ int mnFullNameSID;
+ int mnFamilyNameSID;
+};
+
+// ====================================================================
+
+struct CffLocal
+{
+ explicit CffLocal();
+
+ int mnPrivDictBase;
+ int mnPrivDictSize;
+ int mnLocalSubrOffs;
+ int mnLocalSubrBase;
+ int mnLocalSubrCount;
+ int mnLocalSubrBias;
+
+ ValType maNominalWidth;
+ ValType maDefaultWidth;
+
+ // ATM hinting related values
+ ValType maStemStdHW;
+ ValType maStemStdVW;
+ ValVector maStemSnapH;
+ ValVector maStemSnapV;
+ ValVector maBlueValues;
+ ValVector maOtherBlues;
+ ValVector maFamilyBlues;
+ ValVector maFamilyOtherBlues;
+ RealType mfBlueScale;
+ RealType mfBlueShift;
+ RealType mfBlueFuzz;
+ RealType mfExpFactor;
+ int mnLangGroup;
+ bool mbForceBold;
+};
+
+// ====================================================================
+
+class SubsetterContext
+{
+public:
+ virtual ~SubsetterContext( void);
+ virtual bool emitAsType1( class Type1Emitter&,
+ const long* pGlyphIDs, const U8* pEncoding,
+ GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ) = 0;
+};
+
+// --------------------------------------------------------------------
+
+SubsetterContext::~SubsetterContext( void)
+{}
+
+// ====================================================================
+
+class CffSubsetterContext
+: public SubsetterContext
+, private CffGlobal
+{
+public:
+ static const int NMAXSTACK = 48; // see CFF.appendixB
+ static const int NMAXHINTS = 2*96; // see CFF.appendixB
+ static const int NMAXTRANS = 32; // see CFF.appendixB
+public:
+ explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
+ virtual ~CffSubsetterContext( void);
+
+ void initialCffRead( void);
+ bool emitAsType1( class Type1Emitter&,
+ const long* pGlyphIDs, const U8* pEncoding,
+ GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
+
+ // used by charstring converter
+ void setCharStringType( int);
+ void fakeLocalSubrCount( int nLocalSubrs ) { maCffLocal[0].mnLocalSubrCount=nLocalSubrs;}
+protected:
+ int convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
+private:
+ void convertOneTypeOp( void);
+ void convertOneTypeEsc( void);
+ void callType2Subr( bool bGlobal, int nSubrNumber);
+ long getReadOfs( void) const { return (long)(mpReadPtr - mpBasePtr);}
+
+ const U8* mpBasePtr;
+ const U8* mpBaseEnd;
+
+ const U8* mpReadPtr;
+ const U8* mpReadEnd;
+
+ U8* mpWritePtr;
+ bool mbSawError;
+ bool mbNeedClose;
+ bool mbIgnoreHints;
+ long mnCntrMask;
+
+private:
+ int seekIndexData( int nIndexBase, int nDataIndex);
+ void seekIndexEnd( int nIndexBase);
+
+private:
+ const char** mpCharStringOps;
+ const char** mpCharStringEscs;
+
+ CffLocal maCffLocal[16];
+ CffLocal* mpCffLocal;
+
+ void readDictOp( void);
+ RealType readRealVal( void);
+ const char* getString( int nStringID);
+ int getFDSelect( int nGlyphIndex) const;
+ int getGlyphSID( int nGlyphIndex) const;
+ const char* getGlyphName( int nGlyphIndex);
+
+ void read2push( void);
+ void pop2write( void);
+ void writeType1Val( ValType);
+ void writeTypeOp( int nTypeOp);
+ void writeTypeEsc( int nTypeOp);
+ void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
+ void pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
+ void popAll2Write( int nTypeOp);
+
+public: // TODO: is public really needed?
+ // accessing the value stack
+ // TODO: add more checks
+ void push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;}
+ ValType popVal( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
+ ValType peekVal( void) const { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);}
+ ValType getVal( int nIndex) const { return mnValStack[ nIndex];}
+ int popInt( void);
+ int peekInt( void) const;
+ int getInt( int nIndex) const;
+ int size( void) const { return mnStackIdx;}
+ bool empty( void) const { return !mnStackIdx;}
+ void clear( void) { mnStackIdx = 0;}
+
+ // accessing the charstring hints
+ void addHints( bool bVerticalHints);
+ int getHorzHintCount( void) const { return (mnHorzHintSize/2);}
+ int getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;}
+ void getHintPair( int nIndex, ValType* nMin, ValType* nEnd) const;
+
+ // accessing other charstring specifics
+ bool hasCharWidth( void) const { return (maCharWidth > 0);}
+ ValType getCharWidth( void) const { return maCharWidth;}
+ void setNominalWidth( ValType aWidth) { mpCffLocal->maNominalWidth = aWidth;}
+ void setDefaultWidth( ValType aWidth) { mpCffLocal->maDefaultWidth = aWidth;}
+ void updateWidth( bool bUseFirstVal);
+
+private:
+ // typeop exceution context
+ int mnStackIdx;
+ ValType mnValStack[ NMAXSTACK+4];
+ ValType mnTransVals[ NMAXTRANS];
+
+ int mnHintSize;
+ int mnHorzHintSize;
+ ValType mnHintStack[ NMAXHINTS];
+
+ ValType maCharWidth;
+};
+
+// --------------------------------------------------------------------
+
+CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
+: mpBasePtr( pBasePtr)
+, mpBaseEnd( pBasePtr+nBaseLen)
+, mnStackIdx(0)
+, mnHintSize(0)
+, mnHorzHintSize(0)
+, maCharWidth(-1)
+{
+// setCharStringType( 1);
+ // TODO: new CffLocal[ mnFDAryCount];
+ mpCffLocal = &maCffLocal[0];
+}
+
+// --------------------------------------------------------------------
+
+CffSubsetterContext::~CffSubsetterContext( void)
+{
+ // TODO: delete[] maCffLocal;
+}
+
+// --------------------------------------------------------------------
+
+inline int CffSubsetterContext::popInt( void)
+{
+ const ValType aVal = popVal();
+ const int nInt = static_cast<int>(aVal);
+ assert( nInt == aVal);
+ return nInt;
+}
+
+// --------------------------------------------------------------------
+
+inline int CffSubsetterContext::peekInt( void) const
+{
+ const ValType aVal = peekVal();
+ const int nInt = static_cast<int>(aVal);
+ assert( nInt == aVal);
+ return nInt;
+}
+
+// --------------------------------------------------------------------
+
+inline int CffSubsetterContext::getInt( int nIndex) const
+{
+ const ValType aVal = getVal( nIndex);
+ const int nInt = static_cast<int>(aVal);
+ assert( nInt == aVal);
+ return nInt;
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
+{
+#if 1 // TODO: is this still needed?
+ // the first value is not a hint but the charwidth
+ if( hasCharWidth())
+ return;
+#endif
+ if( bUseFirstVal) {
+ maCharWidth = mpCffLocal->maNominalWidth + mnValStack[0];
+ // remove bottom stack entry
+ --mnStackIdx;
+ for( int i = 0; i < mnStackIdx; ++i)
+ mnValStack[ i] = mnValStack[ i+1];
+ } else {
+ maCharWidth = mpCffLocal->maDefaultWidth;
+ }
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::addHints( bool bVerticalHints)
+{
+ // the first charstring value may a charwidth instead of a charwidth
+ updateWidth( (mnStackIdx & 1) != 0);
+ // return early (e.g. no implicit hints for hintmask)
+ if( !mnStackIdx)
+ return;
+
+ // copy the remaining values to the hint arrays
+ // assert( (mnStackIdx & 1) == 0); // depends on called subrs
+ if( mnStackIdx & 1) --mnStackIdx;//#######
+ // TODO: if( !bSubr) assert( mnStackIdx >= 2);
+
+ assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
+
+#ifdef IGNORE_HINTS
+ mnHintSize += mnStackIdx;
+#else
+ ValType nHintOfs = 0;
+ for( int i = 0; i < mnStackIdx; ++i) {
+ nHintOfs += mnValStack[ i ];
+ mnHintStack[ mnHintSize++] = nHintOfs;
+ }
+#endif // IGNORE_HINTS
+ if( !bVerticalHints)
+ mnHorzHintSize = mnHintSize;
+
+ // clear all values from the stack
+ mnStackIdx = 0;
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::getHintPair( int nIndex, ValType* pMin, ValType* pEnd) const
+{
+ nIndex *= 2;
+ assert( nIndex < mnHintSize);
+ assert( nIndex >= 0);
+ const ValType* pHint = &mnHintStack[ nIndex ];
+ *pMin = pHint[0];
+ *pEnd = pHint[1];
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::setCharStringType( int nVal)
+{
+ switch( nVal) {
+ case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break;
+ case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break;
+ default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break;
+ }
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::readDictOp( void)
+{
+ ValType nVal = 0;
+ int nInt = 0;
+ const U8 c = *mpReadPtr;
+ if( c <= 21 ) {
+ int nOpId = *(mpReadPtr++);
+ const char* pCmdName;
+ if( nOpId != 12)
+ pCmdName = pDictOps[ nOpId];
+ else {
+ const U8 nExtId = *(mpReadPtr++);
+ pCmdName = pDictEscs[ nExtId];
+ nOpId = 900 + nExtId;
+ }
+
+ //TODO: if( nStackIdx > 0)
+ switch( *pCmdName) {
+ default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break;
+ case 'b': // bool
+ nInt = popInt();
+ switch( nOpId) {
+ case 915: mpCffLocal->mbForceBold = nInt; break; // "ForceBold"
+ default: break; // TODO: handle more boolean dictops?
+ }
+ break;
+ case 'n': // dict-op number
+ nVal = popVal();
+ nInt = static_cast<int>(nVal);
+ switch( nOpId) {
+ case 10: mpCffLocal->maStemStdHW = nVal; break; // "StdHW"
+ case 11: mpCffLocal->maStemStdVW = nVal; break; // "StdVW"
+ case 15: mnCharsetBase = nInt; break; // "charset"
+ case 16: mnEncodingBase = nInt; break; // "nEncoding"
+ case 17: mnCharStrBase = nInt; break; // "nCharStrings"
+ case 19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs"
+ case 20: setDefaultWidth( nVal ); break; // "defaultWidthX"
+ case 21: setNominalWidth( nVal ); break; // "nominalWidthX"
+ case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale"
+ case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift"
+ case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz"
+ case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor"
+ case 917: mpCffLocal->mnLangGroup = nInt; break; // "LanguageGroup"
+ case 936: mnFontDictBase = nInt; break; // "nFDArray"
+ case 937: mnFDSelectBase = nInt; break; // "nFDSelect"
+ default: break; // TODO: handle more numeric dictops?
+ }
+ break;
+ case 'a': { // array
+ switch( nOpId) {
+ case 5: maFontBBox.clear(); break; // "FontBBox"
+ case 907: maFontMatrix.clear(); break; // "FontMatrix"
+ default: break; // TODO: reset other arrays?
+ }
+ for( int i = 0; i < size(); ++i ) {
+ nVal = getVal(i);
+ switch( nOpId) {
+ case 5: maFontBBox.push_back( nVal); break; // "FontBBox"
+ case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
+ default: break; // TODO: handle more array dictops?
+ }
+ }
+ clear();
+ } break;
+ case 'd': { // delta array
+ nVal = 0;
+ for( int i = 0; i < size(); ++i ) {
+ nVal += getVal(i);
+ switch( nOpId) {
+ case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues"
+ case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues"
+ case 8: mpCffLocal->maFamilyBlues.push_back( nVal); break; // "FamilyBlues"
+ case 9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
+ case 912: mpCffLocal->maStemSnapH.push_back( nVal); break; // "StemSnapH"
+ case 913: mpCffLocal->maStemSnapV.push_back( nVal); break; // "StemSnapV"
+ default: break; // TODO: handle more delta-array dictops?
+ }
+ }
+ clear();
+ } break;
+ case 's': // stringid (SID)
+ nInt = popInt();
+ switch( nOpId ) {
+ case 2: mnFullNameSID = nInt; break; // "FullName"
+ case 3: mnFamilyNameSID = nInt; break; // "FamilyName"
+ case 938: mnFontNameSID = nInt; break; // "FontName"
+ default: break; // TODO: handle more string dictops?
+ }
+ break;
+ case 'P': // private dict
+ mpCffLocal->mnPrivDictBase = popInt();
+ mpCffLocal->mnPrivDictSize = popInt();
+ break;
+ case 'r': { // ROS operands
+ int nSid1 = popInt();
+ int nSid2 = popInt();
+ (void)nSid1; // TODO: use
+ (void)nSid2; // TODO: use
+ nVal = popVal();
+ mbCIDFont = true;
+ } break;
+ case 't': // CharstringType
+ nInt = popInt();
+ setCharStringType( nInt );
+ break;
+ }
+
+ return;
+ }
+
+ if( (c >= 32) || (c == 28) ) {
+// --mpReadPtr;
+ read2push();
+ } else if( c == 29 ) { // longint
+ ++mpReadPtr; // skip 29
+ int nS32 = mpReadPtr[0] << 24;
+ nS32 += mpReadPtr[1] << 16;
+ nS32 += mpReadPtr[2] << 8;
+ nS32 += mpReadPtr[3] << 0;
+ if( (sizeof(nS32) != 4) && (nS32 & (1<<31)))
+ nS32 |= (~0U) << 31; // assuming 2s complement
+ mpReadPtr += 4;
+ nVal = static_cast<ValType>(nS32);
+ push( nVal );
+ } else if( c == 30) { // real number
+ ++mpReadPtr; // skip 30
+ const RealType fReal = readRealVal();
+ // push value onto stack
+ nVal = fReal;
+ push( nVal);
+ }
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::read2push()
+{
+ ValType aVal = 0;
+
+ const U8*& p = mpReadPtr;
+ const U8 c = *p;
+ if( c == 28 ) {
+ short nS16 = (p[1] << 8) + p[2];
+ if( (sizeof(nS16) != 2) && (nS16 & (1<<15)))
+ nS16 |= (~0U) << 15; // assuming 2s complement
+ aVal = nS16;
+ p += 3;
+ } else if( c <= 246 ) { // -107..+107
+ aVal = static_cast<ValType>(p[0] - 139);
+ p += 1;
+ } else if( c <= 250 ) { // +108..+1131
+ aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124);
+ p += 2;
+ } else if( c <= 254 ) { // -108..-1131
+ aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1]));
+ p += 2;
+ } else /*if( c == 255)*/ { // Fixed16.16
+ int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4];
+ if( (sizeof(nS32) != 2) && (nS32 & (1<<31)))
+ nS32 |= (~0U) << 31; // assuming 2s complement
+ aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000));
+ p += 5;
+ }
+
+ push( aVal);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::writeType1Val( ValType aVal)
+{
+ U8* pOut = mpWritePtr;
+
+ int nInt = static_cast<int>(aVal);
+ static const int nOutCharstrType = 1;
+ if( (nInt != aVal) && (nOutCharstrType == 2)) {
+ // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
+ *(pOut++) = 255; // Fixed 16.16
+ *(pOut++) = static_cast<U8>(nInt >> 8);
+ *(pOut++) = static_cast<U8>(nInt);
+ nInt = static_cast<int>(aVal * 0x10000) & 0xFFFF;
+ *(pOut++) = static_cast<U8>(nInt >> 8);
+ *(pOut++) = static_cast<U8>(nInt);
+ } else if( (nInt >= -107) && (nInt <= +107)) {
+ *(pOut++) = static_cast<U8>(nInt + 139); // -107..+107
+ } else if( (nInt >= -1131) && (nInt <= +1131)) {
+ if( nInt >= 0)
+ nInt += 63124; // +108..+1131
+ else
+ nInt = 64148 - nInt; // -108..-1131
+ *(pOut++) = static_cast<U8>(nInt >> 8);
+ *(pOut++) = static_cast<U8>(nInt);
+ } else if( nOutCharstrType == 1) {
+ // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
+ *(pOut++) = 255;
+ *(pOut++) = static_cast<U8>(nInt >> 24);
+ *(pOut++) = static_cast<U8>(nInt >> 16);
+ *(pOut++) = static_cast<U8>(nInt >> 8);
+ *(pOut++) = static_cast<U8>(nInt);
+ }
+
+ mpWritePtr = pOut;
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::pop2write( void)
+{
+ const ValType aVal = popVal();
+ writeType1Val( aVal);
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
+{
+ *(mpWritePtr++) = static_cast<U8>(nTypeOp);
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
+{
+ *(mpWritePtr++) = TYPE1OP::T1ESC;
+ *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
+{
+ for( int i = 0; i < mnStackIdx;) {
+ for( int j = 0; j < nArgsPerTypo; ++j) {
+ const ValType aVal = mnValStack[i+j];
+ writeType1Val( aVal);
+ }
+ i += nArgsPerTypo;
+ writeTypeOp( nTypeOp);
+ nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto
+ }
+ clear();
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::popAll2Write( int nTypeOp)
+{
+ // pop in reverse order, then write
+ for( int i = 0; i < mnStackIdx; ++i) {
+ const ValType aVal = mnValStack[i];
+ writeType1Val( aVal);
+ }
+ clear();
+ writeTypeOp( nTypeOp);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::writeCurveTo( int nStackPos,
+ int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
+{
+ // get the values from the stack
+ const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0;
+ const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0;
+ const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0;
+ const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0;
+ const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0;
+ const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0;
+
+ // emit the curveto operator and operands
+ // TODO: determine the most efficient curveto operator
+ // TODO: depending on type1op or type2op target
+ writeType1Val( nDX1 );
+ writeType1Val( nDY1 );
+ writeType1Val( nDX2 );
+ writeType1Val( nDY2 );
+ writeType1Val( nDX3 );
+ writeType1Val( nDY3 );
+ writeTypeOp( TYPE1OP::RCURVETO );
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::convertOneTypeOp( void)
+{
+ const int nType2Op = *(mpReadPtr++);
+
+ int i, nInt; // prevent WAE for declarations inside switch cases
+ // convert each T2op
+ switch( nType2Op) {
+ case TYPE2OP::T2ESC:
+ convertOneTypeEsc();
+ break;
+ case TYPE2OP::HSTEM:
+ case TYPE2OP::VSTEM:
+ addHints( nType2Op == TYPE2OP::VSTEM );
+#ifndef IGNORE_HINTS
+ for( i = 0; i < mnHintSize; i+=2 ) {
+ writeType1Val( mnHintStack[i]);
+ writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
+ writeTypeOp( nType2Op );
+ }
+#endif // IGNORE_HINTS
+ break;
+ case TYPE2OP::HSTEMHM:
+ case TYPE2OP::VSTEMHM:
+ addHints( nType2Op == TYPE2OP::VSTEMHM);
+ break;
+ case TYPE2OP::CNTRMASK:
+ // TODO: replace cntrmask with vstem3/hstem3
+ addHints( true);
+#ifdef IGNORE_HINTS
+ mpReadPtr += (mnHintSize + 15) / 16;
+ mbIgnoreHints = true;
+#else
+ {
+ U8 nMaskBit = 0;
+ U8 nMaskByte = 0;
+ for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
+ if( !nMaskBit) {
+ nMaskByte = *(mpReadPtr++);
+ nMaskBit = 0x80;
+ }
+ if( !(nMaskByte & nMaskBit))
+ continue;
+ if( i >= 8*(int)sizeof(mnCntrMask))
+ mbIgnoreHints = true;
+ if( mbIgnoreHints)
+ continue;
+ mnCntrMask |= (1U << i);
+ }
+ }
+#endif
+ break;
+ case TYPE2OP::HINTMASK:
+ addHints( true);
+#ifdef IGNORE_HINTS
+ mpReadPtr += (mnHintSize + 15) / 16;
+#else
+ {
+ long nHintMask = 0;
+ int nCntrBits[2] = {0,0};
+ U8 nMaskBit = 0;
+ U8 nMaskByte = 0;
+ for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
+ if( !nMaskBit) {
+ nMaskByte = *(mpReadPtr++);
+ nMaskBit = 0x80;
+ }
+ if( !(nMaskByte & nMaskBit))
+ continue;
+ if( i >= 8*(int)sizeof(nHintMask))
+ mbIgnoreHints = true;
+ if( mbIgnoreHints)
+ continue;
+ nHintMask |= (1U << i);
+ nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
+ }
+
+ mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
+ mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
+ if( mbIgnoreHints)
+ break;
+
+ for( i = 0; i < mnHintSize; i+=2) {
+ if( !(nHintMask & (1U << i)))
+ continue;
+ writeType1Val( mnHintStack[i]);
+ writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
+ const bool bHorz = (i < mnHorzHintSize);
+ if( !nCntrBits[ bHorz])
+ writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
+ else if( !--nCntrBits[ bHorz])
+ writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
+ }
+ }
+#endif
+ break;
+ case TYPE2OP::CALLSUBR:
+ case TYPE2OP::CALLGSUBR:
+ {
+ nInt = popInt();
+ const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
+ callType2Subr( bGlobal, nInt);
+ }
+ break;
+ case TYPE2OP::RETURN:
+ // TODO: check that we are in a subroutine
+ return;
+ case TYPE2OP::VMOVETO:
+ case TYPE2OP::HMOVETO:
+ if( mbNeedClose)
+ writeTypeOp( TYPE1OP::CLOSEPATH);
+ else
+ updateWidth( size() > 1);
+ mbNeedClose = true;
+ pop2MultiWrite( 1, nType2Op);
+ break;
+ case TYPE2OP::VLINETO:
+ case TYPE2OP::HLINETO:
+ pop2MultiWrite( 1, nType2Op,
+ TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
+ break;
+ case TYPE2OP::RMOVETO:
+ // TODO: convert rmoveto to vlineto/hlineto if possible
+ if( mbNeedClose)
+ writeTypeOp( TYPE1OP::CLOSEPATH);
+ else
+ updateWidth( size() > 2);
+ mbNeedClose = true;
+ pop2MultiWrite( 2, nType2Op);
+ break;
+ case TYPE2OP::RLINETO:
+ // TODO: convert rlineto to vlineto/hlineto if possible
+ pop2MultiWrite( 2, nType2Op);
+ break;
+ case TYPE2OP::RCURVETO:
+ // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
+ pop2MultiWrite( 6, nType2Op);
+ break;
+ case TYPE2OP::RCURVELINE:
+ i = 0;
+ while( (i += 6) <= mnStackIdx)
+ writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
+ i -= 6;
+ while( (i += 2) <= mnStackIdx) {
+ writeType1Val( mnValStack[i-2]);
+ writeType1Val( mnValStack[i-1]);
+ writeTypeOp( TYPE2OP::RLINETO);
+ }
+ clear();
+ break;
+ case TYPE2OP::RLINECURVE:
+ i = 0;
+ while( (i += 2) <= mnStackIdx-6) {
+ writeType1Val( mnValStack[i-2]);
+ writeType1Val( mnValStack[i-1]);
+ writeTypeOp( TYPE2OP::RLINETO);
+ }
+ i -= 2;
+ while( (i += 6) <= mnStackIdx)
+ writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
+ clear();
+ break;
+ case TYPE2OP::VHCURVETO:
+ case TYPE2OP::HVCURVETO:
+ {
+ bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
+ i = 0;
+ nInt = 0;
+ if( mnStackIdx & 1 )
+ nInt = static_cast<int>(mnValStack[ --mnStackIdx ]);
+ while( (i += 4) <= mnStackIdx) {
+ // TODO: use writeCurveTo()
+ if( bVert ) writeType1Val( 0 );
+ writeType1Val( mnValStack[i-4] );
+ if( !bVert ) writeType1Val( 0);
+ writeType1Val( mnValStack[i-3] );
+ writeType1Val( mnValStack[i-2] );
+ if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
+ writeType1Val( mnValStack[i-1] );
+ if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
+ bVert = !bVert;
+ writeTypeOp( TYPE2OP::RCURVETO);
+ }
+ }
+ clear();
+ break;
+ case TYPE2OP::HHCURVETO:
+ i = (mnStackIdx & 1);
+ while( (i += 4) <= mnStackIdx) {
+ if( i != 5)
+ writeCurveTo( i, -4, 0, -3, -2, -1, 0);
+ else
+ writeCurveTo( i, -4, -5, -3, -2, -1, 0);
+ }
+ clear();
+ break;
+ case TYPE2OP::VVCURVETO:
+ i = (mnStackIdx & 1);
+ while( (i += 4) <= mnStackIdx) {
+ if( i != 5)
+ writeCurveTo( i, 0, -4, -3, -2, 0, -1);
+ else
+ writeCurveTo( i, -5, -4, -3, -2, 0, -1);
+ }
+ clear();
+ break;
+ case TYPE2OP::ENDCHAR:
+ if( mbNeedClose)
+ writeTypeOp( TYPE1OP::CLOSEPATH);
+ else
+ updateWidth( size() >= 1);
+ // mbNeedClose = true;
+ writeTypeOp( TYPE1OP::ENDCHAR);
+ break;
+ default:
+ if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
+ --mpReadPtr;
+ read2push();
+ } else {
+ popAll2Write( nType2Op);
+ assert( false); // TODO?
+ }
+ break;
+ }
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::convertOneTypeEsc( void)
+{
+ const int nType2Esc = *(mpReadPtr++);
+ ValType* pTop = &mnValStack[ mnStackIdx-1];
+ // convert each T2op
+ switch( nType2Esc) {
+ case TYPE2OP::AND:
+ assert( mnStackIdx >= 2 );
+ pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1]));
+ --mnStackIdx;
+ break;
+ case TYPE2OP::OR:
+ assert( mnStackIdx >= 2 );
+ pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1]));
+ --mnStackIdx;
+ break;
+ case TYPE2OP::NOT:
+ assert( mnStackIdx >= 1 );
+ pTop[0] = (pTop[0] == 0);
+ break;
+ case TYPE2OP::ABS:
+ assert( mnStackIdx >= 1 );
+ if( pTop[0] >= 0)
+ break;
+ // fall through
+ case TYPE2OP::NEG:
+ assert( mnStackIdx >= 1 );
+ pTop[0] = -pTop[0];
+ break;
+ case TYPE2OP::ADD:
+ assert( mnStackIdx >= 2 );
+ pTop[0] += pTop[-1];
+ --mnStackIdx;
+ break;
+ case TYPE2OP::SUB:
+ assert( mnStackIdx >= 2 );
+ pTop[0] -= pTop[-1];
+ --mnStackIdx;
+ break;
+ case TYPE2OP::MUL:
+ assert( mnStackIdx >= 2 );
+ if( pTop[-1])
+ pTop[0] *= pTop[-1];
+ --mnStackIdx;
+ break;
+ case TYPE2OP::DIV:
+ assert( mnStackIdx >= 2 );
+ if( pTop[-1])
+ pTop[0] /= pTop[-1];
+ --mnStackIdx;
+ break;
+ case TYPE2OP::EQ:
+ assert( mnStackIdx >= 2 );
+ pTop[0] = (pTop[0] == pTop[-1]);
+ --mnStackIdx;
+ break;
+ case TYPE2OP::DROP:
+ assert( mnStackIdx >= 1 );
+ --mnStackIdx;
+ break;
+ case TYPE2OP::PUT: {
+ assert( mnStackIdx >= 2 );
+ const int nIdx = static_cast<int>(pTop[0]);
+ assert( nIdx >= 0 );
+ assert( nIdx < NMAXTRANS );
+ mnTransVals[ nIdx] = pTop[-1];
+ mnStackIdx -= 2;
+ break;
+ }
+ case TYPE2OP::GET: {
+ assert( mnStackIdx >= 1 );
+ const int nIdx = static_cast<int>(pTop[0]);
+ assert( nIdx >= 0 );
+ assert( nIdx < NMAXTRANS );
+ pTop[0] = mnTransVals[ nIdx ];
+ break;
+ }
+ case TYPE2OP::IFELSE: {
+ assert( mnStackIdx >= 4 );
+ if( pTop[-1] > pTop[0] )
+ pTop[-3] = pTop[-2];
+ mnStackIdx -= 3;
+ break;
+ }
+ case TYPE2OP::RANDOM:
+ pTop[+1] = 1234; // TODO
+ ++mnStackIdx;
+ break;
+ case TYPE2OP::SQRT:
+ // TODO: implement
+ break;
+ case TYPE2OP::DUP:
+ assert( mnStackIdx >= 1 );
+ pTop[+1] = pTop[0];
+ ++mnStackIdx;
+ break;
+ case TYPE2OP::EXCH: {
+ assert( mnStackIdx >= 2 );
+ const ValType nVal = pTop[0];
+ pTop[0] = pTop[-1];
+ pTop[-1] = nVal;
+ break;
+ }
+ case TYPE2OP::INDEX: {
+ assert( mnStackIdx >= 1 );
+ const int nVal = static_cast<int>(pTop[0]);
+ assert( nVal >= 0 );
+ assert( nVal < mnStackIdx-1 );
+ pTop[0] = pTop[-1-nVal];
+ break;
+ }
+ case TYPE2OP::ROLL: {
+ assert( mnStackIdx >= 1 );
+ const int nNum = static_cast<int>(pTop[0]);
+ assert( nNum >= 0);
+ assert( nNum < mnStackIdx-2 );
+ (void)nNum; // TODO: implement
+ const int nOfs = static_cast<int>(pTop[-1]);
+ mnStackIdx -= 2;
+ (void)nOfs;// TODO: implement
+ break;
+ }
+ case TYPE2OP::HFLEX1: {
+ assert( mnStackIdx == 9);
+#if 0 // emulate hflex1 as straight line
+ const ValType* pX = &mnValStack[ mnStackIdx];
+ const ValType fDX = pX[-9] + pX[-7] + pX[-5] + pX[-4] + pX[-3] + pX[-1];
+ writeType1Val( fDX);
+ writeTypeOp( TYPE1OP::HLINETO);
+#else // emulate hflex1 as two curves
+ writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, 0);
+ writeCurveTo( mnStackIdx, -4, 0, -3, -2, -1, 0);
+ // TODO: emulate hflex1 using othersubr call
+#endif
+ mnStackIdx -= 9;
+ }
+ break;
+ case TYPE2OP::HFLEX: {
+ assert( mnStackIdx == 7);
+ ValType* pX = &mnValStack[ mnStackIdx];
+#if 0 // emulate hflex as straight line
+ const ValType fDX = pX[-7] + pX[-6] + pX[-4] + pX[-3] + pX[-2] + pX[-1];
+ writeType1Val( fDX);
+ writeTypeOp( TYPE1OP::HLINETO);
+#else // emulate hflex as two curves
+ pX[+1] = -pX[-5]; // temp: +dy5==-dy2
+ writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, 0);
+ writeCurveTo( mnStackIdx, -3, 0, -2, +1, -1, 0);
+ // TODO: emulate hflex using othersubr call
+#endif
+ mnStackIdx -= 7;
+ }
+ break;
+ case TYPE2OP::FLEX: {
+ assert( mnStackIdx == 13 );
+ writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 );
+ writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2 );
+ const ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
+ (void)nFlexDepth; // ignoring nFlexDepth
+ mnStackIdx -= 13;
+ }
+ break;
+ case TYPE2OP::FLEX1: {
+ assert( mnStackIdx == 11 );
+ // write the first part of the flex1-hinted curve
+ writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 );
+
+ // determine if nD6 is horizontal or vertical
+ const int i = mnStackIdx;
+ ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3];
+ if( nDeltaX < 0 ) nDeltaX = -nDeltaX;
+ ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2];
+ if( nDeltaY < 0 ) nDeltaY = -nDeltaY;
+ const bool bVertD6 = (nDeltaY > nDeltaX);
+
+ // write the second part of the flex1-hinted curve
+ if( !bVertD6 )
+ writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0);
+ else
+ writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1);
+ mnStackIdx -= 11;
+ }
+ break;
+ default:
+ fprintf( stderr,"unhandled type2esc %d\n", nType2Esc);
+ assert( false);
+ break;
+ }
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
+{
+ const U8* const pOldReadPtr = mpReadPtr;
+ const U8* const pOldReadEnd = mpReadEnd;
+
+ int nLen = 0;
+ if( bGlobal ) {
+ nSubrNumber += mnGlobalSubrBias;
+ nLen = seekIndexData( mnGlobalSubrBase, nSubrNumber);
+ } else {
+ nSubrNumber += mpCffLocal->mnLocalSubrBias;
+ nLen = seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
+ }
+
+ while( mpReadPtr < mpReadEnd)
+ convertOneTypeOp();
+
+ mpReadPtr = pOldReadPtr;
+ mpReadEnd = pOldReadEnd;
+}
+
+// --------------------------------------------------------------------
+
+static const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
+
+int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
+{
+ mpCffLocal = pCffLocal;
+
+ // prepare the charstring conversion
+ mpWritePtr = pT1Ops;
+#if 1 // TODO: update caller
+ U8 aType1Ops[ MAX_T1OPS_SIZE];
+ if( !pT1Ops)
+ mpWritePtr = aType1Ops;
+ *const_cast<U8**>(&pT1Ops) = mpWritePtr;
+#else
+ assert( pT1Ops);
+#endif
+
+ // prepend random seed for T1crypt
+ *(mpWritePtr++) = 0x48;
+ *(mpWritePtr++) = 0x44;
+ *(mpWritePtr++) = 0x55;
+ *(mpWritePtr++) = ' ';
+#if 1 // convert the Type2 charstring to Type1
+ mpReadPtr = pT2Ops;
+ mpReadEnd = pT2Ops + nT2Len;
+ // prepend "hsbw" or "sbw"
+ // TODO: only emit hsbw when charwidth is known
+ // TODO: remove charwidth from T2 stack
+ writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
+ writeType1Val( 1000/*###getCharWidth()###*/);
+ writeTypeOp( TYPE1OP::HSBW);
+mbSawError = false;
+mbNeedClose = false;
+mbIgnoreHints = false;
+mnHintSize=mnHorzHintSize=mnStackIdx=0; maCharWidth=-1;//#######
+mnCntrMask = 0;
+ while( mpReadPtr < mpReadEnd)
+ convertOneTypeOp();
+// if( bActivePath)
+// writeTypeOp( TYPE1OP::CLOSEPATH);
+// if( bSubRoutine)
+// writeTypeOp( TYPE1OP::RETURN);
+if( mbSawError) {
+ mpWritePtr = pT1Ops+4;
+ // create an "idiotproof" charstring
+ writeType1Val( 0);
+ writeType1Val( 800);
+ writeTypeOp( TYPE1OP::HSBW);
+ writeType1Val( 50);
+ writeTypeOp( TYPE1OP::HMOVETO);
+ writeType1Val( 650);
+ writeType1Val( 100);
+ writeTypeOp( TYPE1OP::RLINETO);
+ writeType1Val( -350);
+ writeType1Val( 700);
+ writeTypeOp( TYPE1OP::RLINETO);
+#if 0
+ writeType1Val( -300);
+ writeType1Val( -800);
+ writeTypeOp( TYPE1OP::RLINETO);
+#else
+ writeTypeOp( TYPE1OP::CLOSEPATH);
+#endif
+ writeTypeOp( TYPE1OP::ENDCHAR);
+}
+#else // useful for manually encoding charstrings
+ mpWritePtr = pT1Ops;
+ mpWritePtr += sprintf( (char*)mpWritePtr, "OOo_\x8b\x8c\x0c\x10\x0b");
+#endif
+ const int nType1Len = mpWritePtr - pT1Ops;
+
+ // encrypt the Type1 charstring
+ int nRDCryptR = 4330; // TODO: mnRDCryptSeed;
+ for( U8* p = pT1Ops; p < mpWritePtr; ++p) {
+ *p ^= (nRDCryptR >> 8);
+ nRDCryptR = (*(U8*)p + nRDCryptR) * 52845 + 22719;
+ }
+
+ return nType1Len;
+}
+
+// --------------------------------------------------------------------
+
+RealType CffSubsetterContext::readRealVal()
+{
+ // TODO: more thorough number validity test
+ bool bComma = false;
+ int nExpVal = 0;
+ int nExpSign = 0;
+ S64 nNumber = 0;
+ RealType fReal = +1.0;
+ for(;;){
+ const U8 c = *(mpReadPtr++); // read nibbles
+ // parse high nibble
+ const U8 nH = c >> 4U;
+ if( nH <= 9) {
+ nNumber = nNumber * 10 + nH;
+ --nExpVal;
+ } else if( nH == 10) { // comma
+ nExpVal = 0;
+ bComma = true;
+ } else if( nH == 11) { // +exp
+ fReal *= nNumber;
+ nExpSign = +1;
+ nNumber = 0;
+ } else if( nH == 12) { // -exp
+ fReal *= nNumber;
+ nExpSign = -1;
+ nNumber = 0;
+ } else if( nH == 13) { // reserved
+ // TODO: ignore or error?
+ } else if( nH == 14) // minus
+ fReal = -fReal;
+ else if( nH == 15) // end
+ break;
+ // parse low nibble
+ const U8 nL = c & 0x0F;
+ if( nL <= 9) {
+ nNumber = nNumber * 10 + nL;
+ --nExpVal;
+ } else if( nL == 10) { // comma
+ nExpVal = 0;
+ bComma = true;
+ } else if( nL == 11) { // +exp
+ fReal *= nNumber;
+ nNumber = 0;
+ nExpSign = +1;
+ } else if( nL == 12) { // -exp
+ fReal *= nNumber;
+ nNumber = 0;
+ nExpSign = -1;
+ } else if( nL == 13) { // reserved
+ // TODO: ignore or error?
+ } else if( nL == 14) // minus
+ fReal = -fReal;
+ else if( nL == 15) // end
+ break;
+ }
+
+ // merge exponents
+ if( !bComma)
+ nExpVal = 0;
+ if( !nExpSign) { fReal *= nNumber;}
+ else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);}
+ else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);}
+
+ // apply exponents
+ if( !nExpVal) { /*nothing to apply*/}
+ else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;}
+ else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;}
+ return fReal;
+}
+
+// --------------------------------------------------------------------
+
+// prepare to access an element inside a CFF/CID index table
+int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
+{
+ assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
+ if( nDataIndex < 0)
+ return -1;
+ mpReadPtr = mpBasePtr + nIndexBase;
+ const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+ if( nDataIndex >= nDataCount)
+ return -1;
+ const int nDataOfsSz = mpReadPtr[2];
+ mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
+ int nOfs1 = 0;
+ switch( nDataOfsSz) {
+ default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return -1;
+ case 1: nOfs1 = mpReadPtr[0]; break;
+ case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
+ case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
+ case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
+ }
+ mpReadPtr += nDataOfsSz;
+
+ int nOfs2 = 0;
+ switch( nDataOfsSz) {
+ case 1: nOfs2 = mpReadPtr[0]; break;
+ case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
+ case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
+ case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
+ }
+
+ mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1;
+ mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
+ assert( nOfs1 >= 0);
+ assert( nOfs2 >= nOfs1);
+ assert( mpReadPtr <= mpBaseEnd);
+ assert( mpReadEnd <= mpBaseEnd);
+ return (nOfs2 - nOfs1);
+}
+
+// --------------------------------------------------------------------
+
+// skip over a CFF/CID index table
+void CffSubsetterContext::seekIndexEnd( int nIndexBase)
+{
+ assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
+ mpReadPtr = mpBasePtr + nIndexBase;
+ const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+ const int nDataOfsSz = mpReadPtr[2];
+ mpReadPtr += 3 + nDataOfsSz * nDataCount;
+ assert( mpReadPtr <= mpBaseEnd);
+ int nEndOfs = 0;
+ switch( nDataOfsSz) {
+ default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return;
+ case 1: nEndOfs = mpReadPtr[0]; break;
+ case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
+ case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break;
+ case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
+ }
+ mpReadPtr += nDataOfsSz;
+ mpReadPtr += nEndOfs - 1;
+ mpReadEnd = mpBaseEnd;
+ assert( nEndOfs >= 0);
+ assert( mpReadEnd <= mpBaseEnd);
+}
+
+// ====================================================================
+
+// initialize FONTDICT specific values
+CffLocal::CffLocal( void)
+: mnPrivDictBase( 0)
+, mnPrivDictSize( 0)
+, mnLocalSubrOffs( 0)
+, mnLocalSubrBase( 0)
+, mnLocalSubrCount( 0)
+, mnLocalSubrBias( 0)
+, maNominalWidth( 0)
+, maDefaultWidth( 0)
+, maStemStdHW( 0)
+, maStemStdVW( 0)
+, mfBlueScale( 0.0)
+, mfBlueShift( 0.0)
+, mfBlueFuzz( 0.0)
+, mfExpFactor( 0.0)
+, mnLangGroup( 0)
+, mbForceBold( false)
+{
+ maStemSnapH.clear();
+ maStemSnapV.clear();
+ maBlueValues.clear();
+ maOtherBlues.clear();
+ maFamilyBlues.clear();
+ maFamilyOtherBlues.clear();
+}
+
+// --------------------------------------------------------------------
+
+CffGlobal::CffGlobal( void)
+: mnNameIdxBase( 0)
+, mnNameIdxCount( 0)
+, mnStringIdxBase( 0)
+, mnStringIdxCount( 0)
+, mbCIDFont( false)
+, mnCharStrBase( 0)
+, mnCharStrCount( 0)
+, mnEncodingBase( 0)
+, mnCharsetBase( 0)
+, mnGlobalSubrBase( 0)
+, mnGlobalSubrCount( 0)
+, mnGlobalSubrBias( 0)
+, mnFDSelectBase( 0)
+, mnFontDictBase( 0)
+, mnFDAryCount( 1)
+, mnFontNameSID( 0)
+, mnFullNameSID( 0)
+, mnFamilyNameSID( 0)
+{
+ maFontBBox.clear();
+ // TODO; maFontMatrix.clear();
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::initialCffRead( void)
+{
+ // get the CFFHeader
+ mpReadPtr = mpBasePtr;
+ const U8 nVerMajor = *(mpReadPtr++);
+ const U8 nVerMinor = *(mpReadPtr++);
+ const U8 nHeaderSize = *(mpReadPtr++);
+ const U8 nOffsetSize = *(mpReadPtr++);
+ // TODO: is the version number useful for anything else?
+ assert( (nVerMajor == 1) && (nVerMinor == 0));
+ (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
+
+ // prepare access to the NameIndex
+ mnNameIdxBase = nHeaderSize;
+ mpReadPtr = mpBasePtr + nHeaderSize;
+ mnNameIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+ seekIndexEnd( mnNameIdxBase);
+
+ // get the TopDict index
+ const long nTopDictBase = getReadOfs();
+ const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+ if( nTopDictCount) {
+ for( int i = 0; i < nTopDictCount; ++i) {
+ seekIndexData( nTopDictBase, i);
+ while( mpReadPtr < mpReadEnd)
+ readDictOp();
+ assert( mpReadPtr == mpReadEnd);
+ }
+ }
+
+ // prepare access to the String index
+ mnStringIdxBase = getReadOfs();
+ mnStringIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+ seekIndexEnd( mnStringIdxBase);
+
+ // prepare access to the GlobalSubr index
+ mnGlobalSubrBase = getReadOfs();
+ mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+ mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768;
+ // skip past the last GlobalSubr entry
+// seekIndexEnd( mnGlobalSubrBase);
+
+ // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
+// seekEncodingsEnd( mnEncodingBase);
+ // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
+// seekCharsetsEnd( mnCharStrBase);
+ // get/skip FDSelect (CID only) data
+
+ // prepare access to the CharStrings index (we got the base from TOPDICT)
+ mpReadPtr = mpBasePtr + mnCharStrBase;
+ mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+// seekIndexEnd( mnCharStrBase);
+
+ // read the FDArray index (CID only)
+ if( mbCIDFont) {
+// assert( mnFontDictBase == tellRel());
+ mpReadPtr = mpBasePtr + mnFontDictBase;
+ mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
+ assert( mnFDAryCount < (int)(sizeof(maCffLocal)/sizeof(*maCffLocal)));
+
+ // read FDArray details to get access to the PRIVDICTs
+ for( int i = 0; i < mnFDAryCount; ++i) {
+ mpCffLocal = &maCffLocal[i];
+ seekIndexData( mnFontDictBase, i);
+ while( mpReadPtr < mpReadEnd)
+ readDictOp();
+ assert( mpReadPtr == mpReadEnd);
+ }
+ }
+
+ for( int i = 0; i < mnFDAryCount; ++i) {
+ mpCffLocal = &maCffLocal[i];
+
+ // get the PrivateDict index
+ // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
+ if( mpCffLocal->mnPrivDictSize != 0) {
+ assert( mpCffLocal->mnPrivDictSize > 0);
+ // get the PrivDict data
+ mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase;
+ mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize;
+ assert( mpReadEnd <= mpBaseEnd);
+ // read PrivDict details
+ while( mpReadPtr < mpReadEnd)
+ readDictOp();
+ }
+
+ // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
+ if( mpCffLocal->mnLocalSubrOffs) {
+ // read LocalSubrs summary
+ mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs;
+ mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase;
+ const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1];
+ mpCffLocal->mnLocalSubrCount = nSubrCount;
+ mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768;
+// seekIndexEnd( mpCffLocal->mnLocalSubrBase);
+ }
+ }
+
+ // ignore the Notices info
+}
+
+// --------------------------------------------------------------------
+
+// get a cstring from a StringID
+const char* CffSubsetterContext::getString( int nStringID)
+{
+ // get a standard string if possible
+ const static int nStdStrings = sizeof(pStringIds)/sizeof(*pStringIds);
+ if( (nStringID >= 0) && (nStringID < nStdStrings))
+ return pStringIds[ nStringID];
+
+ // else get the string from the StringIndex table
+ const U8* pReadPtr = mpReadPtr;
+ const U8* pReadEnd = mpReadEnd;
+ nStringID -= nStdStrings;
+ int nLen = seekIndexData( mnStringIdxBase, nStringID);
+ // assert( nLen >= 0);
+ // TODO: just return the undecorated name
+ // TODO: get rid of static char buffer
+ static char aNameBuf[ 2560];
+ if( nLen < 0) {
+ sprintf( aNameBuf, "name[%d].notfound!", nStringID);
+ } else {
+ const int nMaxLen = sizeof(aNameBuf) - 1;
+ if( nLen >= nMaxLen)
+ nLen = nMaxLen;
+ for( int i = 0; i < nLen; ++i)
+ aNameBuf[i] = *(mpReadPtr++);
+ aNameBuf[ nLen] = '\0';
+ }
+ mpReadPtr = pReadPtr;
+ mpReadEnd = pReadEnd;
+ return aNameBuf;
+}
+
+// --------------------------------------------------------------------
+
+// access a CID's FDSelect table
+int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
+{
+ assert( nGlyphIndex >= 0);
+ assert( nGlyphIndex < mnCharStrCount);
+ if( !mbCIDFont)
+ return 0;
+
+ const U8* pReadPtr = mpBasePtr + mnFDSelectBase;
+ const U8 nFDSelFormat = *(pReadPtr++);
+ switch( nFDSelFormat) {
+ case 0: { // FDSELECT format 0
+ pReadPtr += nGlyphIndex;
+ const U8 nFDIdx = *(pReadPtr++);
+ return nFDIdx;
+ } //break;
+ case 3: { // FDSELECT format 3
+ const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1];
+ assert( nRangeCount > 0);
+ assert( nRangeCount <= mnCharStrCount);
+ U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3];
+ assert( nPrev == 0);
+ pReadPtr += 4;
+ // TODO? binary search
+ for( int i = 0; i < nRangeCount; ++i) {
+ const U8 nFDIdx = pReadPtr[0];
+ const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2];
+ assert( nPrev < nNext);
+ if( nGlyphIndex < nNext)
+ return nFDIdx;
+ pReadPtr += 3;
+ nPrev = nNext;
+ }
+ } break;
+ default: // invalid FDselect format
+ fprintf( stderr, "invalid CFF.FdselType=%d\n", nFDSelFormat);
+ break;
+ }
+
+ assert( false);
+ return -1;
+}
+
+// --------------------------------------------------------------------
+
+int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
+{
+ if( nGlyphIndex == 0)
+ return 0; // ".notdef"
+ assert( nGlyphIndex >= 0);
+ assert( nGlyphIndex < mnCharStrCount);
+ if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount))
+ return -1;
+
+ // get the SID/CID from the Charset table
+ const U8* pReadPtr = mpBasePtr + mnCharsetBase;
+ const U8 nCSetFormat = *(pReadPtr++);
+ int nGlyphsToSkip = nGlyphIndex - 1;
+ switch( nCSetFormat) {
+ case 0: // charset format 0
+ pReadPtr += 2 * nGlyphsToSkip;
+ nGlyphsToSkip = 0;
+ break;
+ case 1: // charset format 1
+ while( nGlyphsToSkip >= 0) {
+ const int nLeft = pReadPtr[2];
+ if( nGlyphsToSkip <= nLeft)
+ break;
+ nGlyphsToSkip -= nLeft + 1;
+ pReadPtr += 3;
+ }
+ break;
+ case 2: // charset format 2
+ while( nGlyphsToSkip >= 0) {
+ const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3];
+ if( nGlyphsToSkip <= nLeft)
+ break;
+ nGlyphsToSkip -= nLeft + 1;
+ pReadPtr += 4;
+ }
+ break;
+ default:
+ fprintf( stderr, "ILLEGAL CFF-Charset format %d\n", nCSetFormat);
+ return -2;
+ }
+
+ int nSID = (pReadPtr[0]<<8) + pReadPtr[1];
+ nSID += nGlyphsToSkip;
+ // NOTE: for CID-fonts the resulting SID is interpreted as CID
+ return nSID;
+}
+
+// --------------------------------------------------------------------
+
+// NOTE: the result becomes invalid with the next call to this method
+const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
+{
+ // the first glyph is always the .notdef glyph
+ const char* pGlyphName = ".notdef";
+ if( nGlyphIndex == 0)
+ return pGlyphName;
+
+ // prepare a result buffer
+ // TODO: get rid of static buffer
+ static char aDefaultGlyphName[64];
+ pGlyphName = aDefaultGlyphName;
+
+ // get the glyph specific name
+ const int nSID = getGlyphSID( nGlyphIndex);
+ if( nSID < 0) // default glyph name
+ sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex);
+ else if( mbCIDFont) // default glyph name in CIDs
+ sprintf( aDefaultGlyphName, "cid%03d", nSID);
+ else { // glyph name from string table
+ const char* pSidName = getString( nSID);
+ // check validity of glyph name
+ if( pSidName) {
+ const char* p = pSidName;
+ while( (*p >= '0') && (*p <= 'z')) ++p;
+ if( (p >= pSidName+1) && (*p == '\0'))
+ pGlyphName = pSidName;
+ }
+ // if needed invent a fallback name
+ if( pGlyphName != pSidName)
+ sprintf( aDefaultGlyphName, "bad%03d", nSID);
+ }
+
+ return pGlyphName;
+}
+
+// --------------------------------------------------------------------
+
+class Type1Emitter
+{
+public:
+ explicit Type1Emitter( const char* pOutFileName, bool bPfbSubset = true);
+ explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset = true);
+ /*virtual*/ ~Type1Emitter( void);
+ void setSubsetName( const char* );
+
+ void emitRawData( const char* pData, int nLength) const;
+ void emitAllRaw( void);
+ void emitAllHex( void);
+ void emitAllCrypted( void);
+ int tellPos( void) const;
+ void updateLen( int nTellPos, int nLength);
+ void emitValVector( const char* pLineHead, const char* pLineTail, const ValVector&);
+private:
+ FILE* mpFileOut;
+ bool mbCloseOutfile;
+ char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
+ int mnEECryptR;
+public:
+ char* mpPtr;
+
+ char maSubsetName[256];
+ bool mbPfbSubset;
+ int mnHexLineCol;
+};
+
+// --------------------------------------------------------------------
+
+Type1Emitter::Type1Emitter( const char* pPfbFileName, bool bPfbSubset)
+: mpFileOut( NULL)
+, mbCloseOutfile( true)
+, mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
+, mpPtr( maBuffer)
+, mbPfbSubset( bPfbSubset)
+, mnHexLineCol( 0)
+{
+ mpFileOut = fopen( pPfbFileName, "wb");
+ maSubsetName[0] = '\0';
+}
+
+// --------------------------------------------------------------------
+
+Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset)
+: mpFileOut( pOutFile)
+, mbCloseOutfile( false)
+, mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
+, mpPtr( maBuffer)
+, mbPfbSubset( bPfbSubset)
+, mnHexLineCol( 0)
+{
+ maSubsetName[0] = '\0';
+}
+
+// --------------------------------------------------------------------
+
+Type1Emitter::~Type1Emitter( void)
+{
+ if( !mpFileOut)
+ return;
+ if( mbCloseOutfile )
+ fclose( mpFileOut);
+ mpFileOut = NULL;
+}
+
+// --------------------------------------------------------------------
+
+void Type1Emitter::setSubsetName( const char* pSubsetName)
+{
+ maSubsetName[0] = '\0';
+ if( pSubsetName)
+ strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName));
+ maSubsetName[sizeof(maSubsetName)-1] = '\0';
+}
+
+// --------------------------------------------------------------------
+
+int Type1Emitter::tellPos( void) const
+{
+ int nTellPos = ftell( mpFileOut);
+ return nTellPos;
+}
+
+// --------------------------------------------------------------------
+
+void Type1Emitter::updateLen( int nTellPos, int nLength)
+{
+ // update PFB segment header length
+ U8 cData[4];
+ cData[0] = static_cast<U8>(nLength >> 0);
+ cData[1] = static_cast<U8>(nLength >> 8);
+ cData[2] = static_cast<U8>(nLength >> 16);
+ cData[3] = static_cast<U8>(nLength >> 24);
+ const int nCurrPos = ftell( mpFileOut);
+ fseek( mpFileOut, nTellPos, SEEK_SET);
+ fwrite( cData, 1, sizeof(cData), mpFileOut);
+ fseek( mpFileOut, nCurrPos, SEEK_SET);
+}
+
+// --------------------------------------------------------------------
+
+inline void Type1Emitter::emitRawData( const char* pData, int nLength) const
+{
+ fwrite( pData, 1, nLength, mpFileOut);
+}
+
+// --------------------------------------------------------------------
+
+inline void Type1Emitter::emitAllRaw( void)
+{
+ // writeout raw data
+ assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
+ emitRawData( maBuffer, mpPtr - maBuffer);
+ // reset the raw buffer
+ mpPtr = maBuffer;
+}
+
+// --------------------------------------------------------------------
+
+inline void Type1Emitter::emitAllHex( void)
+{
+ assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
+ for( const char* p = maBuffer; p < mpPtr;) {
+ // convert binary chunk to hex
+ char aHexBuf[0x4000];
+ char* pOut = aHexBuf;
+ while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
+ // convert each byte to hex
+ char cNibble = (*p >> 4) & 0x0F;
+ cNibble += (cNibble < 10) ? '0' : 'A'-10;
+ *(pOut++) = cNibble;
+ cNibble = *(p++) & 0x0F;
+ cNibble += (cNibble < 10) ? '0' : 'A'-10;
+ *(pOut++) = cNibble;
+ // limit the line length
+ if( (++mnHexLineCol & 0x3F) == 0)
+ *(pOut++) = '\n';
+ }
+ // writeout hex-converted chunk
+ emitRawData( aHexBuf, pOut-aHexBuf);
+ }
+ // reset the raw buffer
+ mpPtr = maBuffer;
+}
+
+// --------------------------------------------------------------------
+
+void Type1Emitter::emitAllCrypted( void)
+{
+ // apply t1crypt
+ for( char* p = maBuffer; p < mpPtr; ++p) {
+ *p ^= (mnEECryptR >> 8);
+ mnEECryptR = (*(U8*)p + mnEECryptR) * 52845 + 22719;
+ }
+
+ // emit the t1crypt result
+ if( mbPfbSubset)
+ emitAllRaw();
+ else
+ emitAllHex();
+}
+
+// --------------------------------------------------------------------
+
+// #i110387# quick-and-dirty double->ascii conversion
+// needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
+// also strip off trailing zeros in fraction while we are at it
+inline int dbl2str( char* pOut, double fVal, int nPrecision=6)
+{
+ const int nLen = psp::getValueOfDouble( pOut, fVal, nPrecision);
+ return nLen;
+}
+
+// --------------------------------------------------------------------
+
+void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
+ const ValVector& rVector)
+{
+ // ignore empty vectors
+ if( rVector.empty())
+ return;
+
+ // emit the line head
+ mpPtr += sprintf( mpPtr, pLineHead);
+ // emit the vector values
+ ValVector::value_type aVal = 0;
+ for( ValVector::const_iterator it = rVector.begin();;) {
+ aVal = *it;
+ if( ++it == rVector.end() )
+ break;
+ mpPtr += dbl2str( mpPtr, aVal);
+ *(mpPtr++) = ' ';
+ }
+ // emit the last value
+ mpPtr += dbl2str( mpPtr, aVal);
+ // emit the line tail
+ mpPtr += sprintf( mpPtr, pLineTail);
+}
+
+// --------------------------------------------------------------------
+
+bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
+ const long* pReqGlyphIDs, const U8* pReqEncoding,
+ GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
+{
+ // prepare some fontdirectory details
+ static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
+ static int nUniqueId = nUniqueIdBase;
+ ++nUniqueId;
+
+ char* pFontName = rEmitter.maSubsetName;
+ if( !*pFontName ) {
+ if( mnFontNameSID) {
+ // get the fontname directly if available
+ strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName));
+ } else if( mnFullNameSID) {
+ // approximate fontname as fullname-whitespace
+ const char* pI = getString( mnFullNameSID);
+ char* pO = pFontName;
+ const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
+ while( pO < pLimit) {
+ const char c = *(pI++);
+ if( c != ' ')
+ *(pO++) = c;
+ if( !c)
+ break;
+ }
+ *pO = '\0';
+ } else {
+ // fallback name of last resort
+ strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
+ }
+ }
+ const char* pFullName = pFontName;
+ const char* pFamilyName = pFontName;
+
+ char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
+
+ // create a PFB+Type1 header
+ if( rEmitter.mbPfbSubset ) {
+ static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
+ rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
+ }
+
+ pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
+ // emit TOPDICT
+#if 0 // improve PS Type1 caching?
+ nOfs += sprintf( &aT1Str[nOfs],
+ "FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n"
+ "/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n"
+ "{save true}{false}ifelse}\n{false}ifelse\n",
+ pFamilyName, pFamilyName, nUniqueId);
+#endif
+ pOut += sprintf( pOut,
+ "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
+ "/FontType 1 def\n"
+ "/PaintType 0 def\n");
+ pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
+ pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
+ // emit FontMatrix
+ if( maFontMatrix.size() == 6)
+ rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix);
+ else // emit default FontMatrix if needed
+ pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
+ // emit FontBBox
+ if( maFontBBox.size() == 4)
+ rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox);
+ else // emit default FontBBox if needed
+ pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n");
+ // emit FONTINFO into TOPDICT
+ pOut += sprintf( pOut,
+ "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
+ " /FullName (%s) readonly def\n"
+ " /FamilyName (%s) readonly def\n"
+ "end readonly def\n",
+ pFullName, pFamilyName);
+#if 0 // TODO: use an standard Type1 encoding if possible
+ pOut += sprintf( pOut,
+ "/Encoding StandardEncoding def\n");
+#else
+ pOut += sprintf( pOut,
+ "/Encoding 256 array\n"
+ "0 1 255 {1 index exch /.notdef put} for\n");
+ for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
+ const char* pGlyphName = getGlyphName( pReqGlyphIDs[i]);
+ pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
+ }
+ pOut += sprintf( pOut, "readonly def\n");
+#endif
+ pOut += sprintf( pOut,
+ // TODO: more topdict entries
+ "currentdict end\n"
+ "currentfile eexec\n");
+
+ // emit PFB header
+ rEmitter.emitAllRaw();
+ if( rEmitter.mbPfbSubset) {
+ // update PFB header segment
+ const int nPfbHeaderLen = rEmitter.tellPos() - 6;
+ rEmitter.updateLen( 2, nPfbHeaderLen);
+
+ // prepare start of eexec segment
+ rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
+ }
+ const int nEExecSegTell = rEmitter.tellPos();
+
+ // which always starts with a privdict
+ // count the privdict entries
+ int nPrivEntryCount = 9;
+#if !defined(IGNORE_HINTS)
+ // emit blue hints only if non-default values
+ nPrivEntryCount += !mpCffLocal->maOtherBlues.empty();
+ nPrivEntryCount += !mpCffLocal->maFamilyBlues.empty();
+ nPrivEntryCount += !mpCffLocal->maFamilyOtherBlues.empty();
+ nPrivEntryCount += (mpCffLocal->mfBlueScale != 0.0);
+ nPrivEntryCount += (mpCffLocal->mfBlueShift != 0.0);
+ nPrivEntryCount += (mpCffLocal->mfBlueFuzz != 0.0);
+ // emit stem hints only if non-default values
+ nPrivEntryCount += (mpCffLocal->maStemStdHW != 0);
+ nPrivEntryCount += (mpCffLocal->maStemStdVW != 0);
+ nPrivEntryCount += !mpCffLocal->maStemSnapH.empty();
+ nPrivEntryCount += !mpCffLocal->maStemSnapV.empty();
+ // emit other hints only if non-default values
+ nPrivEntryCount += (mpCffLocal->mfExpFactor != 0.0);
+ nPrivEntryCount += (mpCffLocal->mnLangGroup != 0);
+ nPrivEntryCount += (mpCffLocal->mnLangGroup == 1);
+ nPrivEntryCount += (mpCffLocal->mbForceBold != false);
+#endif // IGNORE_HINTS
+ // emit the privdict header
+ pOut += sprintf( pOut,
+ "\110\104\125 "
+ "dup\n/Private %d dict dup begin\n"
+ "/RD{string currentfile exch readstring pop}executeonly def\n"
+ "/ND{noaccess def}executeonly def\n"
+ "/NP{noaccess put}executeonly def\n"
+ "/MinFeature{16 16}ND\n"
+ "/password 5839 def\n", // TODO: mnRDCryptSeed?
+ nPrivEntryCount);
+
+#if defined(IGNORE_HINTS)
+ pOut += sprintf( pOut, "/BlueValues []ND\n"); // BlueValues are mandatory
+#else
+ // emit blue hint related privdict entries
+ if( !mpCffLocal->maBlueValues.empty())
+ rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
+ else
+ pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
+ rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
+ rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
+ rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
+
+ if( mpCffLocal->mfBlueScale) {
+ pOut += sprintf( pOut, "/BlueScale ");
+ pOut += dbl2str( pOut, mpCffLocal->mfBlueScale, 6);
+ pOut += sprintf( pOut, " def\n");
+ }
+ if( mpCffLocal->mfBlueShift) { // default BlueShift==7
+ pOut += sprintf( pOut, "/BlueShift ");
+ pOut += dbl2str( pOut, mpCffLocal->mfBlueShift);
+ pOut += sprintf( pOut, " def\n");
+ }
+ if( mpCffLocal->mfBlueFuzz) { // default BlueFuzz==1
+ pOut += sprintf( pOut, "/BlueFuzz ");
+ pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz);
+ pOut += sprintf( pOut, " def\n");
+ }
+
+ // emit stem hint related privdict entries
+ if( mpCffLocal->maStemStdHW) {
+ pOut += sprintf( pOut, "/StdHW [");
+ pOut += dbl2str( pOut, mpCffLocal->maStemStdHW);
+ pOut += sprintf( pOut, "] def\n");
+ }
+ if( mpCffLocal->maStemStdVW) {
+ pOut += sprintf( pOut, "/StdVW [");
+ pOut += dbl2str( pOut, mpCffLocal->maStemStdVW);
+ pOut += sprintf( pOut, "] def\n");
+ }
+ rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
+ rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
+
+ // emit other hints
+ if( mpCffLocal->mbForceBold)
+ pOut += sprintf( pOut, "/ForceBold true def\n");
+ if( mpCffLocal->mnLangGroup != 0)
+ pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
+ if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
+ pOut += sprintf( pOut, "/RndStemUp false def\n");
+ if( mpCffLocal->mfExpFactor) {
+ pOut += sprintf( pOut, "/ExpansionFactor ");
+ pOut += dbl2str( pOut, mpCffLocal->mfExpFactor);
+ pOut += sprintf( pOut, " def\n");
+ }
+#endif // IGNORE_HINTS
+
+ // emit remaining privdict entries
+ pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
+ // TODO?: more privdict entries?
+
+ static const char aOtherSubrs[] =
+ "/OtherSubrs\n"
+ "% Dummy code for faking flex hints\n"
+ "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
+ "{1183615869 systemdict /internaldict get exec\n"
+ "dup /startlock known\n"
+ "{/startlock get exec}\n"
+ "{dup /strtlck known\n"
+ "{/strtlck get exec}\n"
+ "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
+ "] ND\n";
+ memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
+ pOut += sizeof(aOtherSubrs)-1;
+
+ // emit used GlobalSubr charstrings
+ // these are the just the default subrs
+ // TODO: do we need them as the flex hints are resolved differently?
+ static const char aSubrs[] =
+ "/Subrs 5 array\n"
+ "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
+ "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
+ "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
+ "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
+ "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
+ "ND\n";
+ memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
+ pOut += sizeof(aSubrs)-1;
+
+ // TODO: emit more GlobalSubr charstrings?
+ // TODO: emit used LocalSubr charstrings?
+
+ // emit the CharStrings for the requested glyphs
+ pOut += sprintf( pOut,
+ "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
+ rEmitter.emitAllCrypted();
+ for( int i = 0; i < nGlyphCount; ++i) {
+ const int nGlyphId = pReqGlyphIDs[i];
+ assert( (nGlyphId >= 0) && (nGlyphId < mnCharStrCount));
+ // get privdict context matching to the glyph
+ const int nFDSelect = getFDSelect( nGlyphId);
+ mpCffLocal = &maCffLocal[ nFDSelect];
+ // convert the Type2op charstring to its Type1op counterpart
+ const int nT2Len = seekIndexData( mnCharStrBase, nGlyphId);
+ assert( nT2Len > 0);
+ U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
+ const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
+ // get the glyph name
+ const char* pGlyphName = getGlyphName( nGlyphId);
+ // emit the encrypted Type1op charstring
+ pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
+ memcpy( pOut, aType1Ops, nT1Len);
+ pOut += nT1Len;
+ pOut += sprintf( pOut, " ND\n");
+ rEmitter.emitAllCrypted();
+ // provide individual glyphwidths if requested
+ if( pGlyphWidths ) {
+ ValType aCharWidth = getCharWidth();
+ if( maFontMatrix.size() >= 4)
+ aCharWidth *= 1000.0F * maFontMatrix[0];
+ pGlyphWidths[i] = static_cast<GlyphWidth>(aCharWidth);
+ }
+ }
+ pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
+ pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
+ pOut += sprintf( pOut, "mark currentfile closefile\n");
+ rEmitter.emitAllCrypted();
+
+ // mark stop of eexec encryption
+ if( rEmitter.mbPfbSubset) {
+ const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
+ rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
+ }
+
+ // create PFB footer
+ static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "0000000000000000000000000000000000000000000000000000000000000000\n"
+ "cleartomark\n"
+ "\x80\x03";
+ if( rEmitter.mbPfbSubset)
+ rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
+ else
+ rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
+
+ // provide details to the subset requesters, TODO: move into own method?
+ // note: Top and Bottom are flipped between Type1 and VCL
+ // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
+ ValType fXFactor = 1.0;
+ ValType fYFactor = 1.0;
+ if( maFontMatrix.size() >= 4) {
+ fXFactor = 1000.0F * maFontMatrix[0];
+ fYFactor = 1000.0F * maFontMatrix[3];
+ }
+ rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<long>(maFontBBox[0] * fXFactor),
+ static_cast<long>(maFontBBox[1] * fYFactor) ),
+ Point( static_cast<long>(maFontBBox[2] * fXFactor),
+ static_cast<long>(maFontBBox[3] * fYFactor) ) );
+ // PDF-Spec says the values below mean the ink bounds!
+ // TODO: use better approximations for these ink bounds
+ rFSInfo.m_nAscent = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
+ rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top(); // for all letters
+ rFSInfo.m_nCapHeight = rFSInfo.m_nAscent; // for top-flat capital letters
+
+ rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA;
+ rFSInfo.m_aPSName = String( rEmitter.maSubsetName, RTL_TEXTENCODING_UTF8 );
+
+ return true;
+}
+
+// ====================================================================
+
+bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths )
+{
+ CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
+ aCff.initialCffRead();
+
+ // emit Type1 subset from the CFF input
+ // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
+ const bool bPfbSubset = (0 != (mnReqFontTypeMask & FontSubsetInfo::TYPE1_PFB));
+ Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
+ aType1Emitter.setSubsetName( mpReqFontName);
+ bool bRC = aCff.emitAsType1( aType1Emitter,
+ mpReqGlyphIds, mpReqEncodedIds,
+ pOutGlyphWidths, mnReqGlyphCount, *this);
+ return bRC;
+}
+
+// ====================================================================
+
diff --git a/vcl/source/fontsubset/fontsubset.cxx b/vcl/source/fontsubset/fontsubset.cxx
new file mode 100644
index 000000000000..64cf243c6a9d
--- /dev/null
+++ b/vcl/source/fontsubset/fontsubset.cxx
@@ -0,0 +1,185 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/fontsubset.hxx>
+#include <sft.hxx>
+#include <tools/debug.hxx>
+
+// ====================================================================
+
+FontSubsetInfo::FontSubsetInfo()
+: m_nAscent( 0)
+, m_nDescent( 0)
+, m_nCapHeight( 0)
+, m_nFontType( FontSubsetInfo::NO_FONT)
+, mpInFontBytes( NULL)
+, mnInByteLength( 0)
+, meInFontType( FontSubsetInfo::NO_FONT)
+, mpSftTTFont( NULL)
+{}
+
+// --------------------------------------------------------------------
+
+FontSubsetInfo::~FontSubsetInfo()
+{}
+
+// --------------------------------------------------------------------
+
+// prepare subsetting for fonts where the input font file is mapped
+bool FontSubsetInfo::LoadFont(
+ FontSubsetInfo::FontType eInFontType,
+ const unsigned char* pInFontBytes, int nInByteLength)
+{
+ DBG_ASSERT( (mpSftTTFont == NULL), "Subset from SFT and from mapped font-file requested");
+ meInFontType = eInFontType;
+ mpInFontBytes = pInFontBytes;
+ mnInByteLength = nInByteLength;
+ return (mnInByteLength > 0);
+}
+
+// --------------------------------------------------------------------
+
+// prepare subsetting for fonts that are known to the SFT-parser
+bool FontSubsetInfo::LoadFont( vcl::_TrueTypeFont* pSftTTFont )
+{
+ DBG_ASSERT( (mpInFontBytes == NULL), "Subset from SFT and from mapped font-file requested");
+ mpSftTTFont = pSftTTFont;
+ meInFontType = ANY_SFNT;
+ return (mpSftTTFont == NULL);
+}
+
+// --------------------------------------------------------------------
+
+bool FontSubsetInfo::CreateFontSubset(
+ int nReqFontTypeMask,
+ FILE* pOutFile, const char* pReqFontName,
+ const long* pReqGlyphIds, const sal_uInt8* pReqEncodedIds, int nReqGlyphCount,
+ sal_Int32* pOutGlyphWidths)
+{
+ // prepare request details needed by all underlying subsetters
+ mnReqFontTypeMask = nReqFontTypeMask;
+ mpOutFile = pOutFile;
+ mpReqFontName = pReqFontName;
+ mpReqGlyphIds = pReqGlyphIds;
+ mpReqEncodedIds = pReqEncodedIds;
+ mnReqGlyphCount = nReqGlyphCount;
+
+ // TODO: move the glyphid/encid/notdef reshuffling from the callers to here
+
+ // dispatch to underlying subsetters
+ bool bOK = false;
+
+ // TODO: better match available input-type to possible subset-types
+ switch( meInFontType) {
+ case SFNT_TTF:
+ case SFNT_CFF:
+ case ANY_SFNT:
+ bOK = CreateFontSubsetFromSfnt( pOutGlyphWidths);
+ break;
+ case CFF_FONT:
+ bOK = CreateFontSubsetFromCff( pOutGlyphWidths);
+ break;
+ case TYPE1_PFA:
+ case TYPE1_PFB:
+ case ANY_TYPE1:
+ bOK = CreateFontSubsetFromType1( pOutGlyphWidths);
+ break;
+ // fall trough
+ case NO_FONT:
+ // fall trough
+ default:
+ DBG_ERROR( "unhandled type in CreateFontSubset()");
+ break;
+ }
+
+ return bOK;
+}
+
+// --------------------------------------------------------------------
+
+// TODO: move function to sft.cxx to replace dummy implementation
+bool FontSubsetInfo::CreateFontSubsetFromSfnt( sal_Int32* pOutGlyphWidths )
+{
+ // handle SFNT_CFF fonts
+ int nCffLength = 0;
+ const sal_uInt8* pCffBytes = NULL;
+ if( GetSfntTable( mpSftTTFont, O_CFF, &pCffBytes, &nCffLength))
+ {
+ LoadFont( CFF_FONT, pCffBytes, nCffLength);
+ const bool bOK = CreateFontSubsetFromCff( pOutGlyphWidths);
+ return bOK;
+ }
+
+ // handle SFNT_TTF fonts
+ // by forwarding the subset request to AG's sft subsetter
+#if 1 // TODO: remove conversion tp 16bit glyphids when sft-subsetter has been updated
+ sal_uInt16 aShortGlyphIds[256];
+ for( int i = 0; i < mnReqGlyphCount; ++i)
+ aShortGlyphIds[i] = (sal_uInt16)mpReqGlyphIds[i];
+ // remove const_cast when sft-subsetter is const-correct
+ sal_uInt8* pEncArray = const_cast<sal_uInt8*>( mpReqEncodedIds );
+#endif
+ int nSFTErr = vcl::SF_BADARG;
+ if( (mnReqFontTypeMask & TYPE42_FONT) != 0 )
+ {
+ nSFTErr = CreateT42FromTTGlyphs( mpSftTTFont, mpOutFile, mpReqFontName,
+ aShortGlyphIds, pEncArray, mnReqGlyphCount );
+ }
+ else if( (mnReqFontTypeMask & TYPE3_FONT) != 0 )
+ {
+ nSFTErr = CreateT3FromTTGlyphs( mpSftTTFont, mpOutFile, mpReqFontName,
+ aShortGlyphIds, pEncArray, mnReqGlyphCount,
+ 0 /* 0 = horizontal, 1 = vertical */ );
+ }
+ else if( (mnReqFontTypeMask & SFNT_TTF) != 0 )
+ {
+ // TODO: use CreateTTFromTTGlyphs()
+ // TODO: move functionality from callers here
+ }
+
+ return (nSFTErr != vcl::SF_OK);
+}
+
+// --------------------------------------------------------------------
+
+// TODO: replace dummy implementation
+bool FontSubsetInfo::CreateFontSubsetFromType1( sal_Int32* pOutGlyphWidths)
+{
+#if 0
+ // TODO: replace dummy implementation when someone needs this
+#else
+ (void)pOutGlyphWidths;
+ fprintf(stderr,"CreateFontSubsetFromType1: replace dummy implementation\n");
+#endif
+ return false;
+}
+
+// ====================================================================
+
diff --git a/vcl/source/fontsubset/gsub.cxx b/vcl/source/fontsubset/gsub.cxx
new file mode 100644
index 000000000000..37650003eefa
--- /dev/null
+++ b/vcl/source/fontsubset/gsub.cxx
@@ -0,0 +1,360 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "sft.hxx"
+
+#include "gsub.h"
+
+#include <osl/diagnose.h>
+
+#include <vector>
+#include <map>
+#include <algorithm>
+
+namespace vcl
+{
+
+typedef sal_uInt32 ULONG;
+typedef sal_uInt32 UINT32;
+typedef sal_uInt16 USHORT;
+typedef sal_uInt8 FT_Byte;
+
+typedef std::map<USHORT,USHORT> GlyphSubstitution;
+
+
+inline long NEXT_Long( const unsigned char* &p )
+{
+ long nVal = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
+ p += 4;
+ return nVal;
+}
+
+inline USHORT NEXT_UShort( const unsigned char* &p )
+{
+ USHORT nVal = (p[0]<<8) + p[1];
+ p += 2;
+ return nVal;
+}
+
+#define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
+
+int ReadGSUB( struct _TrueTypeFont* pTTFile,
+ int nRequestedScript, int nRequestedLangsys )
+{
+ const FT_Byte* pGsubBase = (FT_Byte*)pTTFile->tables[ O_gsub ];
+ if( !pGsubBase )
+ return -1;
+
+ // #129682# check offsets inside GSUB table
+ const FT_Byte* pGsubLimit = pGsubBase + pTTFile->tlens[ O_gsub ];
+
+ // parse GSUB header
+ const FT_Byte* pGsubHeader = pGsubBase;
+ const ULONG nVersion = NEXT_Long( pGsubHeader );
+ const USHORT nOfsScriptList = NEXT_UShort( pGsubHeader );
+ const USHORT nOfsFeatureTable = NEXT_UShort( pGsubHeader );
+ const USHORT nOfsLookupList = NEXT_UShort( pGsubHeader );
+
+ // sanity check the GSUB header
+ if( nVersion != 0x00010000 )
+ if( nVersion != 0x00001000 ) // workaround for SunBatang etc.
+ return -1; // unknown format or broken
+
+ typedef std::vector<ULONG> ReqFeatureTagList;
+ ReqFeatureTagList aReqFeatureTagList;
+
+ aReqFeatureTagList.push_back( MKTAG("vert") );
+
+ typedef std::vector<USHORT> UshortList;
+ UshortList aFeatureIndexList;
+ UshortList aFeatureOffsetList;
+
+ // parse Script Table
+ const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
+ const USHORT nCntScript = NEXT_UShort( pScriptHeader );
+ if( pGsubLimit < pScriptHeader + 6 * nCntScript )
+ return false;
+ for( USHORT nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
+ {
+ const ULONG nTag = NEXT_Long( pScriptHeader ); // e.g. hani/arab/kana/hang
+ const USHORT nOfsScriptTable= NEXT_UShort( pScriptHeader );
+ if( (nTag != (USHORT)nRequestedScript) && (nRequestedScript != 0) )
+ continue;
+
+ const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable;
+ if( pGsubLimit < pScriptTable + 4 )
+ return false;
+ const USHORT nDefaultLangsysOfs = NEXT_UShort( pScriptTable );
+ const USHORT nCntLangSystem = NEXT_UShort( pScriptTable );
+ USHORT nLangsysOffset = 0;
+ if( pGsubLimit < pScriptTable + 6 * nCntLangSystem )
+ return false;
+ for( USHORT nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
+ {
+ const ULONG nInnerTag = NEXT_Long( pScriptTable ); // e.g. KOR/ZHS/ZHT/JAN
+ const USHORT nOffset= NEXT_UShort( pScriptTable );
+ if( (nInnerTag != (USHORT)nRequestedLangsys) && (nRequestedLangsys != 0) )
+ continue;
+ nLangsysOffset = nOffset;
+ break;
+ }
+
+ if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
+ {
+ const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
+ if( pGsubLimit < pLangSys + 6 )
+ return false;
+ /*const USHORT nLookupOrder =*/ NEXT_UShort( pLangSys );
+ const USHORT nReqFeatureIdx = NEXT_UShort( pLangSys );
+ const USHORT nCntFeature = NEXT_UShort( pLangSys );
+ if( pGsubLimit < pLangSys + 2 * nCntFeature )
+ return false;
+ aFeatureIndexList.push_back( nReqFeatureIdx );
+ for( USHORT i = 0; i < nCntFeature; ++i )
+ {
+ const USHORT nFeatureIndex = NEXT_UShort( pLangSys );
+ aFeatureIndexList.push_back( nFeatureIndex );
+ }
+ }
+
+ if( nLangsysOffset != 0 )
+ {
+ const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
+ if( pGsubLimit < pLangSys + 6 )
+ return false;
+ /*const USHORT nLookupOrder =*/ NEXT_UShort( pLangSys );
+ const USHORT nReqFeatureIdx = NEXT_UShort( pLangSys );
+ const USHORT nCntFeature = NEXT_UShort( pLangSys );
+ if( pGsubLimit < pLangSys + 2 * nCntFeature )
+ return false;
+ aFeatureIndexList.push_back( nReqFeatureIdx );
+ for( USHORT i = 0; i < nCntFeature; ++i )
+ {
+ const USHORT nFeatureIndex = NEXT_UShort( pLangSys );
+ aFeatureIndexList.push_back( nFeatureIndex );
+ }
+ }
+ }
+
+ if( !aFeatureIndexList.size() )
+ return true;
+
+ UshortList aLookupIndexList;
+ UshortList aLookupOffsetList;
+
+ // parse Feature Table
+ const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
+ if( pGsubLimit < pFeatureHeader + 2 )
+ return false;
+ const USHORT nCntFeature = NEXT_UShort( pFeatureHeader );
+ if( pGsubLimit < pFeatureHeader + 6 * nCntFeature )
+ return false;
+ for( USHORT nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
+ {
+ const ULONG nTag = NEXT_Long( pFeatureHeader ); // e.g. locl/vert/trad/smpl/liga/fina/...
+ const USHORT nOffset= NEXT_UShort( pFeatureHeader );
+
+ // ignore unneeded feature lookups
+ if( aFeatureIndexList[0] != nFeatureIndex ) // do not ignore the required feature
+ {
+ const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
+ if( !nRequested ) // ignore features that are not requested
+ continue;
+ const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
+ if( !nAvailable ) // some fonts don't provide features they request!
+ continue;
+ }
+
+ const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
+ if( pGsubLimit < pFeatureTable + 2 )
+ return false;
+ const USHORT nCntLookups = NEXT_UShort( pFeatureTable );
+ if( pGsubLimit < pFeatureTable + 2 * nCntLookups )
+ return false;
+ for( USHORT i = 0; i < nCntLookups; ++i )
+ {
+ const USHORT nLookupIndex = NEXT_UShort( pFeatureTable );
+ aLookupIndexList.push_back( nLookupIndex );
+ }
+ if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
+ aLookupIndexList.push_back( 0 );
+ }
+
+ // parse Lookup List
+ const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
+ if( pGsubLimit < pLookupHeader + 2 )
+ return false;
+ const USHORT nCntLookupTable = NEXT_UShort( pLookupHeader );
+ if( pGsubLimit < pLookupHeader + 2 * nCntLookupTable )
+ return false;
+ for( USHORT nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
+ {
+ const USHORT nOffset = NEXT_UShort( pLookupHeader );
+ if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
+ aLookupOffsetList.push_back( nOffset );
+ }
+
+ UshortList::const_iterator it = aLookupOffsetList.begin();
+ for(; it != aLookupOffsetList.end(); ++it )
+ {
+ const USHORT nOfsLookupTable = *it;
+ const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
+ if( pGsubLimit < pLookupTable + 6 )
+ return false;
+ const USHORT eLookupType = NEXT_UShort( pLookupTable );
+ /*const USHORT eLookupFlag =*/ NEXT_UShort( pLookupTable );
+ const USHORT nCntLookupSubtable = NEXT_UShort( pLookupTable );
+
+ // TODO: switch( eLookupType )
+ if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst
+ continue;
+
+ if( pGsubLimit < pLookupTable + 2 * nCntLookupSubtable )
+ return false;
+ for( USHORT nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
+ {
+ const USHORT nOfsSubLookupTable = NEXT_UShort( pLookupTable );
+ const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
+ if( pGsubLimit < pSubLookup + 6 )
+ return false;
+ const USHORT nFmtSubstitution = NEXT_UShort( pSubLookup );
+ const USHORT nOfsCoverage = NEXT_UShort( pSubLookup );
+
+ typedef std::pair<USHORT,USHORT> GlyphSubst;
+ typedef std::vector<GlyphSubst> SubstVector;
+ SubstVector aSubstVector;
+
+ const FT_Byte* pCoverage = pGsubBase
+ + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
+ if( pGsubLimit < pCoverage + 4 )
+ return false;
+ const USHORT nFmtCoverage = NEXT_UShort( pCoverage );
+ switch( nFmtCoverage )
+ {
+ case 1: // Coverage Format 1
+ {
+ const USHORT nCntGlyph = NEXT_UShort( pCoverage );
+ if( pGsubLimit < pCoverage + 2 * nCntGlyph )
+ // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 2;
+ return false;
+ aSubstVector.reserve( nCntGlyph );
+ for( USHORT i = 0; i < nCntGlyph; ++i )
+ {
+ const USHORT nGlyphId = NEXT_UShort( pCoverage );
+ aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
+ }
+ }
+ break;
+
+ case 2: // Coverage Format 2
+ {
+ const USHORT nCntRange = NEXT_UShort( pCoverage );
+ if( pGsubLimit < pCoverage + 6 * nCntRange )
+ // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 6;
+ return false;
+ for( int i = nCntRange; --i >= 0; )
+ {
+ const UINT32 nGlyph0 = NEXT_UShort( pCoverage );
+ const UINT32 nGlyph1 = NEXT_UShort( pCoverage );
+ const USHORT nCovIdx = NEXT_UShort( pCoverage );
+ for( UINT32 j = nGlyph0; j <= nGlyph1; ++j )
+ aSubstVector.push_back( GlyphSubst( static_cast<USHORT>(j + nCovIdx), 0 ) );
+ }
+ }
+ break;
+ }
+
+ SubstVector::iterator subst_it( aSubstVector.begin() );
+
+ switch( nFmtSubstitution )
+ {
+ case 1: // Single Substitution Format 1
+ {
+ const USHORT nDeltaGlyphId = NEXT_UShort( pSubLookup );
+
+ for(; subst_it != aSubstVector.end(); ++subst_it )
+ (*subst_it).second = (*subst_it).first + nDeltaGlyphId;
+ }
+ break;
+
+ case 2: // Single Substitution Format 2
+ {
+ const USHORT nCntGlyph = NEXT_UShort( pSubLookup );
+ for( int i = nCntGlyph; (subst_it != aSubstVector.end()) && (--i>=0); ++subst_it )
+ {
+ if( pGsubLimit < pSubLookup + 2 )
+ return false;
+ const USHORT nGlyphId = NEXT_UShort( pSubLookup );
+ (*subst_it).second = nGlyphId;
+ }
+ }
+ break;
+ }
+
+ // now apply the glyph substitutions that have been collected in this subtable
+ if( aSubstVector.size() > 0 )
+ {
+ GlyphSubstitution* pGSubstitution = new GlyphSubstitution;
+ pTTFile->pGSubstitution = (void*)pGSubstitution;
+ for( subst_it = aSubstVector.begin(); subst_it != aSubstVector.end(); ++subst_it )
+ (*pGSubstitution)[ (*subst_it).first ] = (*subst_it).second;
+ }
+ }
+ }
+ return true;
+}
+
+void ReleaseGSUB(struct _TrueTypeFont* pTTFile)
+{
+ GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
+ if( pGlyphSubstitution )
+ delete pGlyphSubstitution;
+}
+
+int UseGSUB( struct _TrueTypeFont* pTTFile, int nGlyph, int /*wmode*/ )
+{
+ GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
+ if( pGlyphSubstitution != 0 )
+ {
+ GlyphSubstitution::const_iterator it( pGlyphSubstitution->find( sal::static_int_cast<USHORT>(nGlyph) ) );
+ if( it != pGlyphSubstitution->end() )
+ nGlyph = (*it).second;
+ }
+
+ return nGlyph;
+}
+
+int HasVerticalGSUB( struct _TrueTypeFont* pTTFile )
+{
+ GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
+ return pGlyphSubstitution ? +1 : 0;
+}
+
+}
diff --git a/vcl/source/fontsubset/gsub.h b/vcl/source/fontsubset/gsub.h
new file mode 100644
index 000000000000..9d552ce45701
--- /dev/null
+++ b/vcl/source/fontsubset/gsub.h
@@ -0,0 +1,44 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _PSP_GSUB_H
+#define _PSP_GSUB_H
+
+namespace vcl
+{
+
+int HasVerticalGSUB( struct vcl::_TrueTypeFont* pTTFile );
+
+int UseGSUB( struct vcl::_TrueTypeFont* pTTFile, int nGlyph, int wmode );
+
+int ReadGSUB( struct vcl::_TrueTypeFont* pTTFile, int nRequestedScript, int nRequestedLangsys );
+
+void ReleaseGSUB( struct vcl::_TrueTypeFont* pTTFile );
+
+}
+
+#endif /* _PSP_GSUB_H */
diff --git a/vcl/source/fontsubset/list.c b/vcl/source/fontsubset/list.c
new file mode 100644
index 000000000000..3b55b4dfee15
--- /dev/null
+++ b/vcl/source/fontsubset/list.c
@@ -0,0 +1,541 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/*[]---------------------------------------------------[]*/
+/*| |*/
+/*| list.c - bidirectional list class |*/
+/*| |*/
+/*| |*/
+/*| Author: Alexander Gelfenbain |*/
+/*[]---------------------------------------------------[]*/
+
+#include <stdlib.h>
+
+#if OSL_DEBUG_LEVEL == 0
+# ifndef NDEBUG
+# define NDEBUG
+# endif
+#endif
+
+#include <assert.h>
+
+#ifdef MALLOC_TRACE
+#include <stdio.h>
+#include </usr/local/include/malloc.h>
+#endif
+/* #define TEST */
+#include "list.h"
+
+/*- private data types */
+typedef struct _lnode {
+ struct _lnode *next;
+ struct _lnode *prev;
+
+ void *value;
+
+} lnode;
+
+struct _list {
+ lnode *head, *tail, *cptr;
+ size_t aCount;
+ list_destructor eDtor;
+};
+
+/*- private methods */
+
+static lnode *newNode(void *el)
+{
+ lnode *ptr = malloc(sizeof(lnode));
+ assert(ptr != 0);
+
+ ptr->value = el;
+
+ return ptr;
+}
+
+static lnode *appendPrim(list this, void *el)
+{
+ lnode *ptr = newNode(el);
+ lnode **flink, *blink;
+
+ if (this->tail != 0) {
+ flink = &(this->tail->next);
+ blink = this->tail;
+ } else {
+ flink = &this->head;
+ blink = 0;
+ this->cptr = ptr; /*- list was empty - set current to this element */
+ }
+
+ *flink = ptr;
+ this->tail = ptr;
+
+ ptr->prev = blink;
+ ptr->next = 0;
+
+ this->aCount++;
+ return ptr;
+}
+#ifdef TEST
+static lnode *prependPrim(list this, void *el)
+{
+ lnode *ptr = newNode(el);
+ lnode *flink, **blink;
+
+ if (this->head != 0) {
+ blink = &(this->head->prev);
+ flink = this->head;
+ } else {
+ blink = &this->tail;
+ flink = 0;
+ this->cptr = ptr; /*- list was empty - set current to this element */
+ }
+
+ *blink = ptr;
+ this->head = ptr;
+
+ ptr->next = flink;
+ ptr->prev = 0;
+
+ this->aCount++;
+ return ptr;
+}
+#endif
+
+/*- public methods */
+list listNewEmpty(void) /*- default ctor */
+{
+ list this = malloc(sizeof(struct _list));
+ assert(this != 0);
+
+ this->aCount = 0;
+ this->eDtor = 0;
+ this->head = this->tail = this->cptr = 0;
+
+ return this;
+}
+
+#ifdef TEST
+list listNewCopy(list l) /*- copy ctor */
+{
+ lnode *ptr, *c;
+ list this;
+ assert(l != 0);
+
+ this = malloc(sizeof(struct _list));
+ assert(this != 0);
+
+ ptr = l->head;
+
+ this->aCount = 0;
+ this->eDtor = 0;
+ this->head = this->tail = this->cptr = 0;
+
+ while (ptr) {
+ c = appendPrim(this, ptr->value);
+ if (ptr == l->cptr) this->cptr = c;
+ ptr = ptr->next;
+ }
+
+ return this;
+}
+#endif
+
+void listDispose(list this) /*- dtor */
+{
+ assert(this != 0);
+ listClear(this);
+ free(this);
+}
+
+void listSetElementDtor(list this, list_destructor f)
+{
+ assert(this != 0);
+ this->eDtor = f;
+}
+
+/* calling this function on an empty list is a run-time error */
+void *listCurrent(list this)
+{
+ assert(this != 0);
+ assert(this->cptr != 0);
+ return this->cptr->value;
+}
+
+int listCount(list this)
+{
+ assert(this != 0);
+ return this->aCount;
+}
+
+int listIsEmpty(list this)
+{
+ assert(this != 0);
+ return this->aCount == 0;
+}
+
+
+#ifdef TEST
+int listAtFirst(list this)
+{
+ assert(this != 0);
+ return this->cptr == this->head;
+}
+
+int listAtLast(list this)
+{
+ assert(this != 0);
+ return this->cptr == this->tail;
+}
+
+int listPosition(list this)
+{
+ int res = 0;
+ lnode *ptr;
+ assert(this != 0);
+
+ ptr = this->head;
+
+ while (ptr != this->cptr) {
+ ptr = ptr->next;
+ res++;
+ }
+
+ return res;
+}
+#endif
+int listFind(list this, void *el)
+{
+ lnode *ptr;
+ assert(this != 0);
+
+ ptr = this->head;
+
+ while (ptr) {
+ if (ptr->value == el) {
+ this->cptr = ptr;
+ return 1;
+ }
+ ptr = ptr->next;
+ }
+
+ return 0;
+}
+
+int listNext(list this)
+{
+ return listSkipForward(this, 1);
+}
+
+int listSkipForward(list this, int n)
+{
+ int m = 0;
+ assert(this != 0);
+
+ if (this->cptr == 0) return 0;
+
+ while (n != 0) {
+ if (this->cptr->next == 0) break;
+ this->cptr = this->cptr->next;
+ n--;
+ m++;
+ }
+ return m;
+}
+
+int listToFirst(list this)
+{
+ assert(this != 0);
+
+ if (this->cptr != this->head) {
+ this->cptr = this->head;
+ return 1;
+ }
+ return 0;
+}
+
+int listToLast(list this)
+{
+ assert(this != 0);
+
+ if (this->cptr != this->tail) {
+ this->cptr = this->tail;
+ return 1;
+ }
+ return 0;
+}
+
+int listPositionAt(list this, int n) /*- returns the actual position number */
+{
+ int m = 0;
+ assert(this != 0);
+
+ this->cptr = this->head;
+ while (n != 0) {
+ if (this->cptr->next == 0) break;
+ this->cptr = this->cptr->next;
+ n--;
+ m++;
+ }
+ return m;
+}
+
+list listAppend(list this, void *el)
+{
+ assert(this != 0);
+
+ appendPrim(this, el);
+ return this;
+}
+#ifdef TEST
+list listPrepend(list this, void *el)
+{
+ assert(this != 0);
+
+ prependPrim(this, el);
+ return this;
+}
+
+list listInsertAfter(list this, void *el)
+{
+ lnode *ptr;
+ assert(this != 0);
+
+ if (this->cptr == 0) return listAppend(this, el);
+
+ ptr = newNode(el);
+
+ ptr->prev = this->cptr;
+ ptr->next = this->cptr->next;
+ this->cptr->next = ptr;
+
+ if (ptr->next != 0) {
+ ptr->next->prev = ptr;
+ } else {
+ this->tail = ptr;
+ }
+ this->aCount++;
+ return this;
+}
+
+list listInsertBefore(list this, void *el)
+{
+ lnode *ptr;
+ assert(this != 0);
+
+ if (this->cptr == 0) return listAppend(this, el);
+
+ ptr = newNode(el);
+
+ ptr->prev = this->cptr->prev;
+ ptr->next = this->cptr;
+ this->cptr->prev = ptr;
+
+ if (ptr->prev != 0) {
+ ptr->prev->next = ptr;
+ } else {
+ this->head = ptr;
+ }
+ this->aCount++;
+ return this;
+}
+#endif
+list listRemove(list this)
+{
+ lnode *ptr = 0;
+ if (this->cptr == 0) return this;
+
+ if (this->cptr->next != 0) {
+ ptr = this->cptr->next;
+ this->cptr->next->prev = this->cptr->prev;
+ } else {
+ this->tail = this->cptr->prev;
+ }
+
+ if (this->cptr->prev != 0) {
+ if (ptr == 0) ptr = this->cptr->prev;
+ this->cptr->prev->next = this->cptr->next;
+ } else {
+ this->head = this->cptr->next;
+ }
+
+ if (this->eDtor) this->eDtor(this->cptr->value); /* call the dtor callback */
+
+ free(this->cptr);
+ this->aCount--;
+ this->cptr = ptr;
+ return this;
+}
+
+list listClear(list this)
+{
+ lnode *node = this->head, *ptr;
+
+ while (node) {
+ ptr = node->next;
+ if (this->eDtor) this->eDtor(node->value); /* call the dtor callback */
+ free(node);
+ this->aCount--;
+ node = ptr;
+ }
+
+ this->head = this->tail = this->cptr = 0;
+ assert(this->aCount == 0);
+ return this;
+}
+
+#ifdef TEST
+
+void listForAll(list this, void (*f)(void *))
+{
+ lnode *ptr = this->head;
+ while (ptr) {
+ f(ptr->value);
+ ptr = ptr->next;
+ }
+}
+
+
+#include <stdio.h>
+
+void printlist(list l)
+{
+ int saved;
+ assert(l != 0);
+ saved = listPosition(l);
+
+ printf("[ ");
+
+ if (!listIsEmpty(l)) {
+ listToFirst(l);
+ do {
+ printf("%d ", (int) listCurrent(l));
+ } while (listNext(l));
+ }
+
+ printf("]\n");
+
+ listPositionAt(l, saved);
+}
+
+void printstringlist(list l)
+{
+ int saved;
+ assert(l != 0);
+ saved = listPosition(l);
+
+ printf("[ ");
+
+ if (!listIsEmpty(l)) {
+ listToFirst(l);
+ do {
+ printf("'%s' ", (char *) listCurrent(l));
+ } while (listNext(l));
+ }
+
+ printf("]\n");
+
+ listPositionAt(l, saved);
+}
+
+void printstat(list l)
+{
+ printf("count: %d, position: %d, isEmpty: %d, atFirst: %d, atLast: %d.\n",
+ listCount(l), listPosition(l), listIsEmpty(l), listAtFirst(l), listAtLast(l));
+}
+
+void allfunc(void *e)
+{
+ printf("%d ", e);
+}
+
+void edtor(void *ptr)
+{
+ printf("element dtor: 0x%08x\n", ptr);
+ free(ptr);
+}
+
+int main()
+{
+ list l1, l2;
+ char *ptr;
+ int i;
+
+#ifdef MALLOC_TRACE
+ mal_leaktrace(1);
+ mal_debug(2);
+#endif
+
+ l1 = listNewEmpty();
+ printstat(l1);
+
+ listAppend(l1, 1);
+ printstat(l1);
+
+ listAppend(l1, 2);
+ printstat(l1);
+
+ listAppend(l1, 3);
+ printstat(l1);
+
+ printlist(l1);
+
+ listToFirst(l1);
+ listInsertBefore(l1, -5);
+ printlist(l1);
+
+ l2 = listNewCopy(l1);
+ printlist(l2);
+
+ listForAll(l2, allfunc);
+ printf("\n");
+
+ listClear(l1);
+ listSetElementDtor(l1, edtor);
+
+ for(i=0; i<10; i++) {
+ ptr = malloc(20);
+ snprintf(ptr, 20, "element # %d", i);
+ listAppend(l1, ptr);
+ }
+
+ printstringlist(l1);
+
+
+ listDispose(l1);
+ listDispose(l2);
+
+#ifdef MALLOC_TRACE
+ mal_dumpleaktrace(stdout);
+#endif
+
+
+ return 0;
+}
+#endif
+
+
diff --git a/vcl/source/fontsubset/makefile.mk b/vcl/source/fontsubset/makefile.mk
new file mode 100644
index 000000000000..25dde00af521
--- /dev/null
+++ b/vcl/source/fontsubset/makefile.mk
@@ -0,0 +1,51 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=fontsubset
+
+# --- Settings -----------------------------------------------------
+ENABLE_EXCEPTIONS=true
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES=\
+ $(SLO)$/list.obj \
+ $(SLO)$/sft.obj \
+ $(SLO)$/cff.obj \
+ $(SLO)$/fontsubset.obj \
+ $(SLO)$/xlat.obj \
+ $(SLO)$/ttcr.obj \
+ $(SLO)$/gsub.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx
new file mode 100644
index 000000000000..43f24e5026ea
--- /dev/null
+++ b/vcl/source/fontsubset/sft.cxx
@@ -0,0 +1,3359 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+/*
+ * Sun Font Tools
+ *
+ * Author: Alexander Gelfenbain
+ *
+ */
+
+#if OSL_DEBUG_LEVEL == 0
+# ifndef NDEBUG
+# define NDEBUG
+# endif
+#endif
+#include <assert.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#ifdef UNX
+#include <sys/mman.h>
+#include <sys/stat.h>
+#endif
+#include "sft.hxx"
+#include "gsub.h"
+#if ! (defined(NO_TTCR) && defined(NO_TYPE42))
+#include "ttcr.hxx"
+#endif
+#ifndef NO_MAPPERS /* include MapChar() and MapString() */
+#include "xlat.hxx"
+#endif
+#ifndef NO_TYPE3 /* include CreateT3FromTTGlyphs() */
+#include <rtl/crc.h>
+#endif
+
+#include <osl/endian.h>
+#include <algorithm>
+
+#ifdef TEST7
+#include <ctype.h>
+#endif
+
+namespace vcl
+{
+
+/*- module identification */
+
+static const char *modname = "SunTypeTools-TT";
+static const char *modver = "1.0";
+static const char *modextra = "gelf";
+
+/*- private functions, constants and data types */ /*FOLD00*/
+
+enum PathSegmentType {
+ PS_NOOP = 0,
+ PS_MOVETO = 1,
+ PS_LINETO = 2,
+ PS_CURVETO = 3,
+ PS_CLOSEPATH = 4
+};
+
+struct PSPathElement
+{
+ PathSegmentType type;
+ int x1, y1;
+ int x2, y2;
+ int x3, y3;
+
+ PSPathElement( PathSegmentType i_eType ) : type( i_eType ),
+ x1( 0 ), y1( 0 ),
+ x2( 0 ), y2( 0 ),
+ x3( 0 ), y3( 0 )
+ {
+ }
+};
+
+/*- In horisontal writing mode right sidebearing is calculated using this formula
+ *- rsb = aw - (lsb + xMax - xMin) -*/
+typedef struct {
+ sal_Int16 xMin;
+ sal_Int16 yMin;
+ sal_Int16 xMax;
+ sal_Int16 yMax;
+ sal_uInt16 aw; /*- Advance Width (horisontal writing mode) */
+ sal_Int16 lsb; /*- Left sidebearing (horisontal writing mode) */
+ sal_uInt16 ah; /*- advance height (vertical writing mode) */
+ sal_Int16 tsb; /*- top sidebearing (vertical writing mode) */
+} TTGlyphMetrics;
+
+#define HFORMAT_LINELEN 64
+
+typedef struct {
+ FILE *o;
+ char buffer[HFORMAT_LINELEN];
+ int bufpos;
+ int total;
+} HexFmt;
+
+typedef struct {
+ sal_uInt32 nGlyphs; /* number of glyphs in the font + 1 */
+ sal_uInt32 *offs; /* array of nGlyphs offsets */
+} GlyphOffsets;
+
+/* private tags */
+static const sal_uInt32 TTFontClassTag = 0x74746663; /* 'ttfc' */
+
+static const sal_uInt32 T_true = 0x74727565; /* 'true' */
+static const sal_uInt32 T_ttcf = 0x74746366; /* 'ttcf' */
+static const sal_uInt32 T_otto = 0x4f54544f; /* 'OTTO' */
+
+/* standard TrueType table tags */
+#define T_maxp 0x6D617870
+#define T_glyf 0x676C7966
+#define T_head 0x68656164
+#define T_loca 0x6C6F6361
+#define T_name 0x6E616D65
+#define T_hhea 0x68686561
+#define T_hmtx 0x686D7478
+#define T_cmap 0x636D6170
+#define T_vhea 0x76686561
+#define T_vmtx 0x766D7478
+#define T_OS2 0x4F532F32
+#define T_post 0x706F7374
+#define T_kern 0x6B65726E
+#define T_cvt 0x63767420
+#define T_prep 0x70726570
+#define T_fpgm 0x6670676D
+#define T_gsub 0x47535542
+#define T_CFF 0x43464620
+
+#define LAST_URANGE_BIT 69
+const char *ulcodes[LAST_URANGE_BIT+2] = {
+ /* 0 */ "Basic Latin",
+ /* 1 */ "Latin-1 Supplement",
+ /* 2 */ "Latin Extended-A",
+ /* 3 */ "Latin Extended-B",
+ /* 4 */ "IPA Extensions",
+ /* 5 */ "Spacing Modifier Letters",
+ /* 6 */ "Combining Diacritical Marks",
+ /* 7 */ "Basic Greek",
+ /* 8 */ "Greek Symbols And Coptic",
+ /* 9 */ "Cyrillic",
+ /* 10 */ "Armenian",
+ /* 11 */ "Basic Hebrew",
+ /* 12 */ "Hebrew Extended (A and B blocks combined)",
+ /* 13 */ "Basic Arabic",
+ /* 14 */ "Arabic Extended",
+ /* 15 */ "Devanagari",
+ /* 16 */ "Bengali",
+ /* 17 */ "Gurmukhi",
+ /* 18 */ "Gujarati",
+ /* 19 */ "Oriya",
+ /* 20 */ "Tamil",
+ /* 21 */ "Telugu",
+ /* 22 */ "Kannada",
+ /* 23 */ "Malayalam",
+ /* 24 */ "Thai",
+ /* 25 */ "Lao",
+ /* 26 */ "Basic Georgian",
+ /* 27 */ "Georgian Extended",
+ /* 28 */ "Hangul Jamo",
+ /* 29 */ "Latin Extended Additional",
+ /* 30 */ "Greek Extended",
+ /* 31 */ "General Punctuation",
+ /* 32 */ "Superscripts And Subscripts",
+ /* 33 */ "Currency Symbols",
+ /* 34 */ "Combining Diacritical Marks For Symbols",
+ /* 35 */ "Letterlike Symbols",
+ /* 36 */ "Number Forms",
+ /* 37 */ "Arrows",
+ /* 38 */ "Mathematical Operators",
+ /* 39 */ "Miscellaneous Technical",
+ /* 40 */ "Control Pictures",
+ /* 41 */ "Optical Character Recognition",
+ /* 42 */ "Enclosed Alphanumerics",
+ /* 43 */ "Box Drawing",
+ /* 44 */ "Block Elements",
+ /* 45 */ "Geometric Shapes",
+ /* 46 */ "Miscellaneous Symbols",
+ /* 47 */ "Dingbats",
+ /* 48 */ "CJK Symbols And Punctuation",
+ /* 49 */ "Hiragana",
+ /* 50 */ "Katakana",
+ /* 51 */ "Bopomofo",
+ /* 52 */ "Hangul Compatibility Jamo",
+ /* 53 */ "CJK Miscellaneous",
+ /* 54 */ "Enclosed CJK Letters And Months",
+ /* 55 */ "CJK Compatibility",
+ /* 56 */ "Hangul",
+ /* 57 */ "Reserved for Unicode SubRanges",
+ /* 58 */ "Reserved for Unicode SubRanges",
+ /* 59 */ "CJK Unified Ideographs",
+ /* 60 */ "Private Use Area",
+ /* 61 */ "CJK Compatibility Ideographs",
+ /* 62 */ "Alphabetic Presentation Forms",
+ /* 63 */ "Arabic Presentation Forms-A",
+ /* 64 */ "Combining Half Marks",
+ /* 65 */ "CJK Compatibility Forms",
+ /* 66 */ "Small Form Variants",
+ /* 67 */ "Arabic Presentation Forms-B",
+ /* 68 */ "Halfwidth And Fullwidth Forms",
+ /* 69 */ "Specials",
+ /*70-127*/ "Reserved for Unicode SubRanges"
+};
+
+
+
+/*- inline functions */ /*FOLD01*/
+#ifdef __GNUC__
+#define _inline static __inline__
+#else
+#define _inline static
+#endif
+
+_inline void *smalloc(size_t size)
+{
+ void *res = malloc(size);
+ assert(res != 0);
+ return res;
+}
+
+_inline void *scalloc(size_t n, size_t size)
+{
+ void *res = calloc(n, size);
+ assert(res != 0);
+ return res;
+}
+
+_inline sal_uInt32 mkTag(sal_uInt8 a, sal_uInt8 b, sal_uInt8 c, sal_uInt8 d) {
+ return (a << 24) | (b << 16) | (c << 8) | d;
+}
+
+/*- Data access macros for data stored in big-endian or little-endian format */
+_inline sal_Int16 GetInt16(const sal_uInt8 *ptr, size_t offset, int bigendian)
+{
+ sal_Int16 t;
+ assert(ptr != 0);
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
+ } else {
+ t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+_inline sal_uInt16 GetUInt16(const sal_uInt8 *ptr, size_t offset, int bigendian)
+{
+ sal_uInt16 t;
+ assert(ptr != 0);
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
+ } else {
+ t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+_inline sal_Int32 GetInt32(const sal_uInt8 *ptr, size_t offset, int bigendian)
+{
+ sal_Int32 t;
+ assert(ptr != 0);
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
+ (ptr+offset)[2] << 8 | (ptr+offset)[3];
+ } else {
+ t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
+ (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+_inline sal_uInt32 GetUInt32(const sal_uInt8 *ptr, size_t offset, int bigendian)
+{
+ sal_uInt32 t;
+ assert(ptr != 0);
+
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
+ (ptr+offset)[2] << 8 | (ptr+offset)[3];
+ } else {
+ t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
+ (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+_inline void PutInt16(sal_Int16 val, sal_uInt8 *ptr, size_t offset, int bigendian)
+{
+ assert(ptr != 0);
+
+ if (bigendian) {
+ ptr[offset] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset+1] = (sal_uInt8)(val & 0xFF);
+ } else {
+ ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset] = (sal_uInt8)(val & 0xFF);
+ }
+
+}
+
+#if defined(OSL_BIGENDIAN)
+#define Int16FromMOTA(a) (a)
+#define Int32FromMOTA(a) (a)
+#else
+static sal_uInt16 Int16FromMOTA(sal_uInt16 a) {
+ return (sal_uInt16) (((sal_uInt8)((a) >> 8)) | ((sal_uInt8)(a) << 8));
+}
+static sal_uInt32 Int32FromMOTA(sal_uInt32 a) {
+ return ((a>>24)&0xFF) | (((a>>8)&0xFF00) | ((a&0xFF00)<<8) | ((a&0xFF)<<24));
+}
+#endif
+
+_inline F16Dot16 fixedMul(F16Dot16 a, F16Dot16 b)
+{
+ unsigned int a1, b1;
+ unsigned int a2, b2;
+ F16Dot16 res;
+ int sign;
+
+ sign = (a & 0x80000000) ^ (b & 0x80000000);
+ if (a < 0) a = -a;
+ if (b < 0) b = -b;
+
+ a1 = a >> 16;
+ b1 = a & 0xFFFF;
+ a2 = b >> 16;
+ b2 = b & 0xFFFF;
+
+ res = a1 * a2;
+
+ /* if (res > 0x7FFF) assert(!"fixedMul: F16Dot16 overflow"); */
+
+ res <<= 16;
+ res += a1 * b2 + b1 * a2 + ((b1 * b2) >> 16);
+
+ return sign ? -res : res;
+}
+
+
+_inline F16Dot16 fixedDiv(F16Dot16 a, F16Dot16 b)
+{
+ unsigned int f, r;
+ F16Dot16 res;
+ int sign;
+
+ sign = (a & 0x80000000) ^ (b & 0x80000000);
+ if (a < 0) a = -a;
+ if (b < 0) b = -b;
+
+ f = a / b;
+ r = a % b;
+
+ /* if (f > 0x7FFFF) assert(!"fixedDiv: F16Dot16 overflow"); */
+
+ while (r > 0xFFFF) {
+ r >>= 1;
+ b >>= 1;
+ }
+
+ res = (f << 16) + (r << 16) / b;
+
+ return sign ? -res : res;
+}
+
+/*- returns a * b / c -*/
+/* XXX provide a real implementation that preserves accuracy */
+_inline F16Dot16 fixedMulDiv(F16Dot16 a, F16Dot16 b, F16Dot16 c)
+{
+ F16Dot16 res;
+
+ res = fixedMul(a, b);
+ return fixedDiv(res, c);
+}
+
+/*- Translate units from TT to PS (standard 1/1000) -*/
+_inline int XUnits(int unitsPerEm, int n)
+{
+ return (n * 1000) / unitsPerEm;
+}
+
+_inline const char *UnicodeRangeName(sal_uInt16 bit)
+{
+ if (bit > LAST_URANGE_BIT) bit = LAST_URANGE_BIT+1;
+
+ return ulcodes[bit];
+}
+
+_inline const sal_uInt8* getTable( TrueTypeFont *ttf, sal_uInt32 ord)
+{
+ return (sal_uInt8*)ttf->tables[ord];
+}
+
+_inline sal_uInt32 getTableSize(TrueTypeFont *ttf, sal_uInt32 ord)
+{
+ return ttf->tlens[ord];
+}
+
+#ifndef NO_TYPE42
+/* Hex Formatter functions */
+static char HexChars[] = "0123456789ABCDEF";
+
+static HexFmt *HexFmtNew(FILE *outf)
+{
+ HexFmt* res = (HexFmt*)smalloc(sizeof(HexFmt));
+ res->bufpos = res->total = 0;
+ res->o = outf;
+ return res;
+}
+
+static void HexFmtFlush(HexFmt *_this)
+{
+ if (_this->bufpos) {
+ fwrite(_this->buffer, 1, _this->bufpos, _this->o);
+ _this->bufpos = 0;
+ }
+}
+
+
+_inline void HexFmtOpenString(HexFmt *_this)
+{
+ fputs("<\n", _this->o);
+}
+
+_inline void HexFmtCloseString(HexFmt *_this)
+{
+ HexFmtFlush(_this);
+ fputs("00\n>\n", _this->o);
+}
+
+_inline void HexFmtDispose(HexFmt *_this)
+{
+ HexFmtFlush(_this);
+ free(_this);
+}
+
+static void HexFmtBlockWrite(HexFmt *_this, const void *ptr, sal_uInt32 size)
+{
+ sal_uInt8 Ch;
+ sal_uInt32 i;
+
+ if (_this->total + size > 65534) {
+ HexFmtFlush(_this);
+ HexFmtCloseString(_this);
+ _this->total = 0;
+ HexFmtOpenString(_this);
+ }
+ for (i=0; i<size; i++) {
+ Ch = ((sal_uInt8 *) ptr)[i];
+ _this->buffer[_this->bufpos++] = HexChars[Ch >> 4];
+ _this->buffer[_this->bufpos++] = HexChars[Ch & 0xF];
+ if (_this->bufpos == HFORMAT_LINELEN) {
+ HexFmtFlush(_this);
+ fputc('\n', _this->o);
+ }
+
+ }
+ _this->total += size;
+}
+#endif
+
+
+
+/* Outline Extraction functions */ /*FOLD01*/
+
+/* fills the aw and lsb entries of the TTGlyphMetrics structure from hmtx table -*/
+static void GetMetrics(TrueTypeFont *ttf, sal_uInt32 glyphID, TTGlyphMetrics *metrics)
+{
+ const sal_uInt8* table = getTable( ttf, O_hmtx );
+
+ metrics->aw = metrics->lsb = metrics->ah = metrics->tsb = 0;
+ if (!table || !ttf->numberOfHMetrics) return;
+
+ if (glyphID < ttf->numberOfHMetrics) {
+ metrics->aw = GetUInt16(table, 4 * glyphID, 1);
+ metrics->lsb = GetInt16(table, 4 * glyphID + 2, 1);
+ } else {
+ metrics->aw = GetUInt16(table, 4 * (ttf->numberOfHMetrics - 1), 1);
+ metrics->lsb = GetInt16(table + ttf->numberOfHMetrics * 4, (glyphID - ttf->numberOfHMetrics) * 2, 1);
+ }
+
+ table = getTable(ttf, O_vmtx);
+ if( !table || !ttf->numOfLongVerMetrics )
+ return;
+
+ if (glyphID < ttf->numOfLongVerMetrics) {
+ metrics->ah = GetUInt16(table, 4 * glyphID, 1);
+ metrics->tsb = GetInt16(table, 4 * glyphID + 2, 1);
+ } else {
+ metrics->ah = GetUInt16(table, 4 * (ttf->numOfLongVerMetrics - 1), 1);
+ metrics->tsb = GetInt16(table + ttf->numOfLongVerMetrics * 4, (glyphID - ttf->numOfLongVerMetrics) * 2, 1);
+ }
+}
+
+static int GetTTGlyphOutline(TrueTypeFont *, sal_uInt32 , ControlPoint **, TTGlyphMetrics *, std::vector< sal_uInt32 >* );
+
+/* returns the number of control points, allocates the pointArray */
+static int GetSimpleTTOutline(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics) /*FOLD02*/
+{
+ const sal_uInt8* table = getTable( ttf, O_glyf );
+ sal_uInt8 flag, n;
+ sal_uInt16 t, lastPoint=0;
+ int i, j, z;
+
+ *pointArray = 0;
+
+ /* printf("GetSimpleTTOutline(%d)\n", glyphID); */
+
+ if( glyphID >= ttf->nglyphs ) /*- glyph is not present in the font */
+ return 0;
+ const sal_uInt8* ptr = table + ttf->goffsets[glyphID];
+ const sal_Int16 numberOfContours = GetInt16(ptr, 0, 1);
+ if( numberOfContours <= 0 ) /*- glyph is not simple */
+ return 0;
+
+ if (metrics) { /*- GetCompoundTTOutline() calls this function with NULL metrics -*/
+ metrics->xMin = GetInt16(ptr, 2, 1);
+ metrics->yMin = GetInt16(ptr, 4, 1);
+ metrics->xMax = GetInt16(ptr, 6, 1);
+ metrics->yMax = GetInt16(ptr, 8, 1);
+ GetMetrics(ttf, glyphID, metrics);
+ }
+
+ /* determine the last point and be extra safe about it. But probably this code is not needed */
+
+ for (i=0; i<numberOfContours; i++) {
+ if ((t = GetUInt16(ptr, 10+i*2, 1)) > lastPoint) lastPoint = t;
+ }
+
+ sal_uInt16 instLen = GetUInt16(ptr, 10 + numberOfContours*2, 1);
+ const sal_uInt8* p = ptr + 10 + 2 * numberOfContours + 2 + instLen;
+ ControlPoint* pa = (ControlPoint*)calloc(lastPoint+1, sizeof(ControlPoint));
+
+ i = 0;
+ while (i <= lastPoint) {
+ pa[i++].flags = (sal_uInt32) (flag = *p++);
+ if (flag & 8) { /*- repeat flag */
+ n = *p++;
+ for (j=0; j<n; j++) {
+ if (i > lastPoint) { /*- if the font is really broken */
+ free(pa);
+ return 0;
+ }
+ pa[i++].flags = flag;
+ }
+ }
+ }
+
+ /*- Process the X coordinate */
+ z = 0;
+ for (i = 0; i <= lastPoint; i++) {
+ if (pa[i].flags & 0x02) {
+ if (pa[i].flags & 0x10) {
+ z += (int) (*p++);
+ } else {
+ z -= (int) (*p++);
+ }
+ } else if ( !(pa[i].flags & 0x10)) {
+ z += GetInt16(p, 0, 1);
+ p += 2;
+ }
+ pa[i].x = (sal_Int16)z;
+ }
+
+ /*- Process the Y coordinate */
+ z = 0;
+ for (i = 0; i <= lastPoint; i++) {
+ if (pa[i].flags & 0x04) {
+ if (pa[i].flags & 0x20) {
+ z += *p++;
+ } else {
+ z -= *p++;
+ }
+ } else if ( !(pa[i].flags & 0x20)) {
+ z += GetInt16(p, 0, 1);
+ p += 2;
+ }
+ pa[i].y = (sal_Int16)z;
+ }
+
+ for (i=0; i<numberOfContours; i++) {
+ pa[GetUInt16(ptr, 10 + i * 2, 1)].flags |= 0x00008000; /*- set the end contour flag */
+ }
+
+ *pointArray = pa;
+ return lastPoint + 1;
+}
+
+static int GetCompoundTTOutline(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >& glyphlist) /*FOLD02*/
+{
+ sal_uInt16 flags, index;
+ sal_Int16 e, f, numberOfContours;
+ const sal_uInt8* table = getTable( ttf, O_glyf );
+ std::vector<ControlPoint> myPoints;
+ ControlPoint *nextComponent, *pa;
+ int i, np;
+ F16Dot16 a = 0x10000, b = 0, c = 0, d = 0x10000, m, n, abs1, abs2, abs3;
+
+ *pointArray = 0;
+ /* printf("GetCompoundTTOutline(%d)\n", glyphID); */
+
+ if (glyphID >= ttf->nglyphs) /*- incorrect glyphID */
+ return 0;
+
+ const sal_uInt8* ptr = table + ttf->goffsets[glyphID];
+ if ((numberOfContours = GetInt16(ptr, 0, 1)) != -1) /*- glyph is not compound */
+ return 0;
+
+ if (metrics) {
+ metrics->xMin = GetInt16(ptr, 2, 1);
+ metrics->yMin = GetInt16(ptr, 4, 1);
+ metrics->xMax = GetInt16(ptr, 6, 1);
+ metrics->yMax = GetInt16(ptr, 8, 1);
+ GetMetrics(ttf, glyphID, metrics);
+ }
+
+ ptr += 10;
+
+ do {
+ flags = GetUInt16(ptr, 0, 1);
+ /* printf("flags: 0x%X\n", flags); */
+ index = GetUInt16(ptr, 2, 1);
+ ptr += 4;
+
+ if( std::find( glyphlist.begin(), glyphlist.end(), index ) != glyphlist.end() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "Endless loop found in a compound glyph.\n");
+ fprintf(stderr, "%d -> ", index);
+ fprintf(stderr," [");
+ for( std::vector< sal_uInt32 >::const_iterator it = glyphlist.begin();
+ it != glyphlist.end(); ++it )
+ {
+ fprintf( stderr,"%d ", (int) *it );
+ }
+ fprintf(stderr,"]\n");
+ /**/
+#endif
+ }
+
+ glyphlist.push_back( index );
+
+#ifdef DEBUG2
+ fprintf(stderr,"glyphlist: += %d\n", index);
+#endif
+
+ if ((np = GetTTGlyphOutline(ttf, index, &nextComponent, 0, &glyphlist)) == 0)
+ {
+ /* XXX that probably indicates a corrupted font */
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "An empty compound!\n");
+ /* assert(!"An empty compound"); */
+#endif
+ }
+
+#ifdef DEBUG2
+ fprintf(stderr,"%d [", (int)glyphlist.size() );
+ for( std::vector< sal_uInt32 >::const_iterator it = glyphlist.begin();
+ it != glyphlist.end(); ++it )
+ {
+ fprintf( stderr,"%d ", (int) *it );
+ }
+ fprintf(stderr, "]\n");
+ if( ! glyphlist.empty() )
+ fprintf(stderr, "glyphlist: -= %d\n", (int) glyphlist.back());
+
+#endif
+ if( ! glyphlist.empty() )
+ glyphlist.pop_back();
+
+ if (flags & USE_MY_METRICS) {
+ if (metrics) GetMetrics(ttf, index, metrics);
+ }
+
+ if (flags & ARG_1_AND_2_ARE_WORDS) {
+ e = GetInt16(ptr, 0, 1);
+ f = GetInt16(ptr, 2, 1);
+ /* printf("ARG_1_AND_2_ARE_WORDS: %d %d\n", e & 0xFFFF, f & 0xFFFF); */
+ ptr += 4;
+ } else {
+ if (flags & ARGS_ARE_XY_VALUES) { /* args are signed */
+ e = (sal_Int8) *ptr++;
+ f = (sal_Int8) *ptr++;
+ /* printf("ARGS_ARE_XY_VALUES: %d %d\n", e & 0xFF, f & 0xFF); */
+ } else { /* args are unsigned */
+ /* printf("!ARGS_ARE_XY_VALUES\n"); */
+ e = *ptr++;
+ f = *ptr++;
+ }
+
+ }
+
+ a = d = 0x10000;
+ b = c = 0;
+
+ if (flags & WE_HAVE_A_SCALE) {
+#ifdef DEBUG2
+ fprintf(stderr, "WE_HAVE_A_SCALE\n");
+#endif
+ a = GetInt16(ptr, 0, 1) << 2;
+ d = a;
+ ptr += 2;
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+#ifdef DEBUG2
+ fprintf(stderr, "WE_HAVE_AN_X_AND_Y_SCALE\n");
+#endif
+ a = GetInt16(ptr, 0, 1) << 2;
+ d = GetInt16(ptr, 2, 1) << 2;
+ ptr += 4;
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+#ifdef DEBUG2
+ fprintf(stderr, "WE_HAVE_A_TWO_BY_TWO\n");
+#endif
+ a = GetInt16(ptr, 0, 1) << 2;
+ b = GetInt16(ptr, 2, 1) << 2;
+ c = GetInt16(ptr, 4, 1) << 2;
+ d = GetInt16(ptr, 6, 1) << 2;
+ ptr += 8;
+ }
+
+ abs1 = (a < 0) ? -a : a;
+ abs2 = (b < 0) ? -b : b;
+ m = (abs1 > abs2) ? abs1 : abs2;
+ abs3 = abs1 - abs2;
+ if (abs3 < 0) abs3 = -abs3;
+ if (abs3 <= 33) m *= 2;
+
+ abs1 = (c < 0) ? -c : c;
+ abs2 = (d < 0) ? -d : d;
+ n = (abs1 > abs2) ? abs1 : abs2;
+ abs3 = abs1 - abs2;
+ if (abs3 < 0) abs3 = -abs3;
+ if (abs3 <= 33) n *= 2;
+
+ if (!ARGS_ARE_XY_VALUES) { /* match the points */
+ assert(!"ARGS_ARE_XY_VALUES is not implemented!!!\n");
+ }
+
+#ifdef DEBUG2
+ fprintf(stderr, "a: %f, b: %f, c: %f, d: %f, e: %f, f: %f, m: %f, n: %f\n",
+ ((double) a) / 65536,
+ ((double) b) / 65536,
+ ((double) c) / 65536,
+ ((double) d) / 65536,
+ ((double) e) / 65536,
+ ((double) f) / 65536,
+ ((double) m) / 65536,
+ ((double) n) / 65536);
+#endif
+
+ for (i=0; i<np; i++) {
+ F16Dot16 t;
+ ControlPoint cp;
+ cp.flags = nextComponent[i].flags;
+ t = fixedMulDiv(a, nextComponent[i].x << 16, m) + fixedMulDiv(c, nextComponent[i].y << 16, m) + (e << 16);
+ cp.x = (sal_Int16)(fixedMul(t, m) >> 16);
+ t = fixedMulDiv(b, nextComponent[i].x << 16, n) + fixedMulDiv(d, nextComponent[i].y << 16, n) + (f << 16);
+ cp.y = (sal_Int16)(fixedMul(t, n) >> 16);
+
+#ifdef DEBUG2
+ fprintf(stderr, "( %d %d ) -> ( %d %d )\n", nextComponent[i].x, nextComponent[i].y, cp.x, cp.y);
+#endif
+
+ myPoints.push_back( cp );
+ }
+
+ free(nextComponent);
+
+ } while (flags & MORE_COMPONENTS);
+
+
+
+ np = myPoints.size();
+
+ pa = (ControlPoint*)calloc(np, sizeof(ControlPoint));
+ assert(pa != 0);
+
+ memcpy( pa, &myPoints[0], np*sizeof(ControlPoint) );
+
+ *pointArray = pa;
+ return np;
+}
+
+/* NOTE: GetTTGlyphOutline() returns -1 if the glyphID is incorrect,
+ * but Get{Simple|Compound}GlyphOutline returns 0 in such a case.
+ *
+ * NOTE: glyphlist is the stack of glyphs traversed while constructing
+ * a composite glyph. This is a safequard against endless recursion
+ * in corrupted fonts.
+ */
+static int GetTTGlyphOutline(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >* glyphlist)
+{
+ const sal_uInt8 *table = getTable( ttf, O_glyf );
+ sal_Int16 numberOfContours;
+ int res;
+ *pointArray = 0;
+
+ if (metrics) {
+ memset(metrics, 0, sizeof(TTGlyphMetrics)); /*- metrics is initialized to all zeroes */
+ }
+
+ if (glyphID >= ttf->nglyphs) return -1; /**/
+
+ const sal_uInt8* ptr = table + ttf->goffsets[glyphID];
+ int length = ttf->goffsets[glyphID+1] - ttf->goffsets[glyphID];
+
+ if (length == 0) { /*- empty glyphs still have hmtx and vmtx metrics values */
+ if (metrics) GetMetrics(ttf, glyphID, metrics);
+ return 0;
+ }
+
+ numberOfContours = GetInt16(ptr, 0, 1);
+
+ if (numberOfContours >= 0)
+ {
+ res=GetSimpleTTOutline(ttf, glyphID, pointArray, metrics);
+ }
+ else
+ {
+ std::vector< sal_uInt32 > aPrivList;
+ aPrivList.push_back( glyphID );
+ res = GetCompoundTTOutline(ttf, glyphID, pointArray, metrics, glyphlist ? *glyphlist : aPrivList );
+ }
+
+#ifdef DEBUG3
+ {
+ int i;
+ FILE *out = fopen("points.dat", "a");
+ assert(out != 0);
+ fprintf(out, "Glyph: %d\nPoints: %d\n", glyphID, res);
+ for (i=0; i<res; i++) {
+ fprintf(out, "%c ", ((*pointArray)[i].flags & 0x8000) ? 'X' : '.');
+ fprintf(out, "%c ", ((*pointArray)[i].flags & 1) ? '+' : '-');
+ fprintf(out, "%d %d\n", (*pointArray)[i].x, (*pointArray)[i].y);
+ }
+ fclose(out);
+ }
+#endif
+
+ return res;
+}
+
+#ifndef NO_TYPE3
+
+/*- returns the number of items in the path -*/
+
+static int BSplineToPSPath(ControlPoint *srcA, int srcCount, PSPathElement **path)
+{
+ std::vector< PSPathElement > aPathList;
+ int nPathCount = 0;
+ PSPathElement p( PS_NOOP );
+
+ int x0 = 0, y0 = 0, x1 = 0, y1 = 0, x2, y2, curx, cury;
+ int lastOff = 0; /*- last point was off-contour */
+ int scflag = 1; /*- start contour flag */
+ int ecflag = 0; /*- end contour flag */
+ int cp = 0; /*- current point */
+ int StartContour = 0, EndContour = 1;
+
+ *path = 0;
+
+ /* if (srcCount > 0) for(;;) */
+ while (srcCount > 0) { /*- srcCount does not get changed inside the loop. */
+ if (scflag) {
+ int l = cp;
+ StartContour = cp;
+ while (!(srcA[l].flags & 0x8000)) l++;
+ EndContour = l;
+ if (StartContour == EndContour) {
+ if (cp + 1 < srcCount) {
+ cp++;
+ continue;
+ } else {
+ break;
+ }
+ }
+ p = PSPathElement(PS_MOVETO);
+ if (!(srcA[cp].flags & 1)) {
+ if (!(srcA[EndContour].flags & 1)) {
+ p.x1 = x0 = (srcA[cp].x + srcA[EndContour].x + 1) / 2;
+ p.y1 = y0 = (srcA[cp].y + srcA[EndContour].y + 1) / 2;
+ } else {
+ p.x1 = x0 = srcA[EndContour].x;
+ p.y1 = y0 = srcA[EndContour].y;
+ }
+ } else {
+ p.x1 = x0 = srcA[cp].x;
+ p.y1 = y0 = srcA[cp].y;
+ cp++;
+ }
+ aPathList.push_back( p );
+ lastOff = 0;
+ scflag = 0;
+ }
+
+ curx = srcA[cp].x;
+ cury = srcA[cp].y;
+
+ if (srcA[cp].flags & 1)
+ {
+ if (lastOff)
+ {
+ p = PSPathElement(PS_CURVETO);
+ p.x1 = x0 + (2 * (x1 - x0) + 1) / 3;
+ p.y1 = y0 + (2 * (y1 - y0) + 1) / 3;
+ p.x2 = x1 + (curx - x1 + 1) / 3;
+ p.y2 = y1 + (cury - y1 + 1) / 3;
+ p.x3 = curx;
+ p.y3 = cury;
+ aPathList.push_back( p );
+ }
+ else
+ {
+ if (!(x0 == curx && y0 == cury))
+ { /* eliminate empty lines */
+ p = PSPathElement(PS_LINETO);
+ p.x1 = curx;
+ p.y1 = cury;
+ aPathList.push_back( p );
+ }
+ }
+ x0 = curx; y0 = cury; lastOff = 0;
+ }
+ else
+ {
+ if (lastOff)
+ {
+ x2 = (x1 + curx + 1) / 2;
+ y2 = (y1 + cury + 1) / 2;
+ p = PSPathElement(PS_CURVETO);
+ p.x1 = x0 + (2 * (x1 - x0) + 1) / 3;
+ p.y1 = y0 + (2 * (y1 - y0) + 1) / 3;
+ p.x2 = x1 + (x2 - x1 + 1) / 3;
+ p.y2 = y1 + (y2 - y1 + 1) / 3;
+ p.x3 = x2;
+ p.y3 = y2;
+ aPathList.push_back( p );
+ x0 = x2; y0 = y2;
+ x1 = curx; y1 = cury;
+ } else {
+ x1 = curx; y1 = cury;
+ }
+ lastOff = true;
+ }
+
+ if (ecflag) {
+ aPathList.push_back( PSPathElement(PS_CLOSEPATH) );
+ scflag = 1;
+ ecflag = 0;
+ cp = EndContour + 1;
+ if (cp >= srcCount) break;
+ continue;
+ }
+
+
+ if (cp == EndContour) {
+ cp = StartContour;
+ ecflag = true;
+ } else {
+ cp++;
+ }
+ }
+
+ if( (nPathCount = (int)aPathList.size()) > 0)
+ {
+ *path = (PSPathElement*)calloc(nPathCount, sizeof(PSPathElement));
+ assert(*path != 0);
+ memcpy( *path, &aPathList[0], nPathCount * sizeof(PSPathElement) );
+ }
+
+ return nPathCount;
+}
+
+#endif
+
+/*- Extracts a string from the name table and allocates memory for it -*/
+
+static char *nameExtract( const sal_uInt8* name, int nTableSize, int n, int dbFlag, sal_uInt16** ucs2result )
+{
+ int i;
+ char *res;
+ const sal_uInt8* ptr = name + GetUInt16(name, 4, 1) + GetUInt16(name + 6, 12 * n + 10, 1);
+ int len = GetUInt16(name+6, 12 * n + 8, 1);
+
+ // sanity check
+ if( (len <= 0) || ((ptr+len) > (name+nTableSize)) )
+ {
+ if( ucs2result )
+ *ucs2result = NULL;
+ return NULL;
+ }
+
+ if( ucs2result )
+ *ucs2result = NULL;
+ if (dbFlag) {
+ res = (char*)malloc(1 + len/2);
+ assert(res != 0);
+ for (i = 0; i < len/2; i++) res[i] = *(ptr + i * 2 + 1);
+ res[len/2] = 0;
+ if( ucs2result )
+ {
+ *ucs2result = (sal_uInt16*)malloc( len+2 );
+ for (i = 0; i < len/2; i++ ) (*ucs2result)[i] = GetUInt16( ptr, 2*i, 1 );
+ (*ucs2result)[len/2] = 0;
+ }
+ } else {
+ res = (char*)malloc(1 + len);
+ assert(res != 0);
+ memcpy(res, ptr, len);
+ res[len] = 0;
+ }
+
+ return res;
+}
+
+static int findname( const sal_uInt8 *name, sal_uInt16 n, sal_uInt16 platformID,
+ sal_uInt16 encodingID, sal_uInt16 languageID, sal_uInt16 nameID )
+{
+ int l = 0, r = n-1, i;
+ sal_uInt32 t1, t2;
+ sal_uInt32 m1, m2;
+
+ if (n == 0) return -1;
+
+ m1 = (platformID << 16) | encodingID;
+ m2 = (languageID << 16) | nameID;
+
+ do {
+ i = (l + r) >> 1;
+ t1 = GetUInt32(name + 6, i * 12 + 0, 1);
+ t2 = GetUInt32(name + 6, i * 12 + 4, 1);
+
+ if (! ((m1 < t1) || ((m1 == t1) && (m2 < t2)))) l = i + 1;
+ if (! ((m1 > t1) || ((m1 == t1) && (m2 > t2)))) r = i - 1;
+ } while (l <= r);
+
+ if (l - r == 2) {
+ return l - 1;
+ }
+
+ return -1;
+}
+
+/* XXX marlett.ttf uses (3, 0, 1033) instead of (3, 1, 1033) and does not have any Apple tables.
+ * Fix: if (3, 1, 1033) is not found - need to check for (3, 0, 1033)
+ *
+ * /d/fonts/ttzh_tw/Big5/Hanyi/ma6b5p uses (1, 0, 19) for English strings, instead of (1, 0, 0)
+ * and does not have (3, 1, 1033)
+ * Fix: if (1, 0, 0) and (3, 1, 1033) are not found need to look for (1, 0, *) - that will
+ * require a change in algorithm
+ *
+ * /d/fonts/fdltest/Korean/h2drrm has unsorted names and a an unknown (to me) Mac LanguageID,
+ * but (1, 0, 1042) strings usable
+ * Fix: change algorithm, and use (1, 0, *) if both standard Mac and MS strings are not found
+ */
+
+static void GetNames(TrueTypeFont *t)
+{
+ const sal_uInt8* table = getTable( t, O_name );
+ int nTableSize = getTableSize(t, O_name);
+
+ if (nTableSize < 4)
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "O_name table too small\n");
+#endif
+ return;
+ }
+
+ sal_uInt16 n = GetUInt16(table, 2, 1);
+ int i, r;
+ sal_Bool bPSNameOK = sal_True;
+
+ /* #129743# simple sanity check for name table entry count */
+ if( nTableSize <= n * 12 + 6 )
+ n = 0;
+
+ /* PostScript name: preferred Microsoft */
+ t->psname = NULL;
+ if ((r = findname(table, n, 3, 1, 0x0409, 6)) != -1)
+ t->psname = nameExtract(table, nTableSize, r, 1, NULL);
+ if ( ! t->psname && (r = findname(table, n, 1, 0, 0, 6)) != -1)
+ t->psname = nameExtract(table, nTableSize, r, 0, NULL);
+ if ( ! t->psname && (r = findname(table, n, 3, 0, 0x0409, 6)) != -1)
+ {
+ // some symbol fonts like Marlett have a 3,0 name!
+ t->psname = nameExtract(table, nTableSize, r, 1, NULL);
+ }
+ // for embedded font in Ghostscript PDFs
+ if ( ! t->psname && (r = findname(table, n, 2, 2, 0, 6)) != -1)
+ {
+ t->psname = nameExtract(table, nTableSize, r, 0, NULL);
+ }
+ if ( ! t->psname )
+ {
+ if ( t->fname )
+ {
+ char* pReverse = t->fname + strlen(t->fname);
+ /* take only last token of filename */
+ while(pReverse != t->fname && *pReverse != '/') pReverse--;
+ if(*pReverse == '/') pReverse++;
+ t->psname = strdup(pReverse);
+ assert(t->psname != 0);
+ for (i=strlen(t->psname) - 1; i > 0; i--)
+ {
+ /*- Remove the suffix -*/
+ if (t->psname[i] == '.' ) {
+ t->psname[i] = 0;
+ break;
+ }
+ }
+ }
+ else
+ t->psname = strdup( "Unknown" );
+ }
+
+ /* Font family and subfamily names: preferred Apple */
+ t->family = NULL;
+ if ((r = findname(table, n, 0, 0, 0, 1)) != -1)
+ t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
+ if ( ! t->family && (r = findname(table, n, 3, 1, 0x0409, 1)) != -1)
+ t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
+ if ( ! t->family && (r = findname(table, n, 1, 0, 0, 1)) != -1)
+ t->family = nameExtract(table, nTableSize, r, 0, NULL);
+ if ( ! t->family && (r = findname(table, n, 3, 1, 0x0411, 1)) != -1)
+ t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
+ if ( ! t->family && (r = findname(table, n, 3, 0, 0x0409, 1)) != -1)
+ t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
+ if ( ! t->family )
+ {
+ t->family = strdup(t->psname);
+ assert(t->family != 0);
+ }
+
+ t->subfamily = NULL;
+ t->usubfamily = NULL;
+ if ((r = findname(table, n, 1, 0, 0, 2)) != -1)
+ t->subfamily = nameExtract(table, nTableSize, r, 0, &t->usubfamily);
+ if ( ! t->subfamily && (r = findname(table, n, 3, 1, 0x0409, 2)) != -1)
+ t->subfamily = nameExtract(table, nTableSize, r, 1, &t->usubfamily);
+ if ( ! t->subfamily )
+ {
+ t->subfamily = strdup("");
+ }
+
+ /* #i60349# sanity check psname
+ * psname parctically has to be 7bit ascii and should not contains spaces
+ * there is a class of broken fonts which do not fullfill that at all, so let's try
+ * if the family name is 7bit ascii and take it instead if so
+ */
+ /* check psname */
+ for( i = 0; t->psname[i] != 0 && bPSNameOK; i++ )
+ if( t->psname[ i ] < 33 || (t->psname[ i ] & 0x80) )
+ bPSNameOK = sal_False;
+ if( bPSNameOK == sal_False )
+ {
+ sal_Bool bReplace = sal_True;
+ /* check if family is a suitable replacement */
+ if( t->ufamily && t->family )
+ {
+ for( i = 0; t->ufamily[ i ] != 0 && bReplace; i++ )
+ if( t->ufamily[ i ] < 33 || t->ufamily[ i ] > 127 )
+ bReplace = sal_False;
+ if( bReplace )
+ {
+ free( t->psname );
+ t->psname = strdup( t->family );
+ }
+ }
+ }
+}
+
+enum cmapType {
+ CMAP_NOT_USABLE = -1,
+ CMAP_MS_Symbol = 10,
+ CMAP_MS_Unicode = 11,
+ CMAP_MS_ShiftJIS = 12,
+ CMAP_MS_Big5 = 13,
+ CMAP_MS_PRC = 14,
+ CMAP_MS_Wansung = 15,
+ CMAP_MS_Johab = 16
+};
+
+#define MISSING_GLYPH_INDEX 0
+
+/*
+ * getGlyph[0246]() functions and freinds are implemented by:
+ * @author Manpreet Singh
+ * getGlyph12() function and friends by:
+ * @author HDU
+ */
+static sal_uInt32 getGlyph0(const sal_uInt8* cmap, sal_uInt32 c) {
+ if (c <= 255) {
+ return *(cmap + 6 + c);
+ } else {
+ return MISSING_GLYPH_INDEX;
+ }
+}
+
+typedef struct _subHeader2 {
+ sal_uInt16 firstCode;
+ sal_uInt16 entryCount;
+ sal_uInt16 idDelta;
+ sal_uInt16 idRangeOffset;
+} subHeader2;
+
+static sal_uInt32 getGlyph2(const sal_uInt8 *cmap, sal_uInt32 c) {
+ sal_uInt16 *CMAP2 = (sal_uInt16 *) cmap;
+ sal_uInt8 theHighByte;
+
+ sal_uInt8 theLowByte;
+ subHeader2* subHeader2s;
+ sal_uInt16* subHeader2Keys;
+ sal_uInt16 firstCode;
+ int k;
+ sal_uInt32 ToReturn;
+
+ theHighByte = (sal_uInt8)((c >> 8) & 0x00ff);
+ theLowByte = (sal_uInt8)(c & 0x00ff);
+ subHeader2Keys = CMAP2 + 3;
+ subHeader2s = (subHeader2 *)(subHeader2Keys + 256);
+ k = Int16FromMOTA(subHeader2Keys[theHighByte]) / 8;
+
+ if(k == 0) {
+ firstCode = Int16FromMOTA(subHeader2s[k].firstCode);
+ if(theLowByte >= firstCode && theLowByte < (firstCode + Int16FromMOTA(subHeader2s[k].entryCount))) {
+ return *((&(subHeader2s[0].idRangeOffset))
+ + (Int16FromMOTA(subHeader2s[0].idRangeOffset)/2) /* + offset */
+ + theLowByte /* + to_look */
+ - Int16FromMOTA(subHeader2s[0].firstCode)
+ );
+ } else {
+ return MISSING_GLYPH_INDEX;
+ }
+ } else if (k > 0) {
+ firstCode = Int16FromMOTA(subHeader2s[k].firstCode);
+ if(theLowByte >= firstCode && theLowByte < (firstCode + Int16FromMOTA(subHeader2s[k].entryCount))) {
+ ToReturn = *((&(subHeader2s[k].idRangeOffset))
+ + (Int16FromMOTA(subHeader2s[k].idRangeOffset)/2)
+ + theLowByte - firstCode);
+ if(ToReturn == 0) {
+ return MISSING_GLYPH_INDEX;
+ } else {
+ ToReturn += Int16FromMOTA(subHeader2s[k].idDelta);
+ return (ToReturn & 0xFFFF);
+ }
+ } else {
+ return MISSING_GLYPH_INDEX;
+ }
+ } else {
+ return MISSING_GLYPH_INDEX;
+ }
+}
+
+static sal_uInt32 getGlyph6(const sal_uInt8 *cmap, sal_uInt32 c) {
+ sal_uInt16 firstCode, lastCode, count;
+ sal_uInt16 *CMAP6 = (sal_uInt16 *) cmap;
+
+ firstCode = Int16FromMOTA(*(CMAP6 + 3));
+ count = Int16FromMOTA(*(CMAP6 + 4));
+ lastCode = firstCode + count - 1;
+ if (c < firstCode || c > lastCode) {
+ return MISSING_GLYPH_INDEX;
+ } else {
+ return *((CMAP6 + 5)/*glyphIdArray*/ + (c - firstCode));
+ }
+}
+
+static sal_uInt16 GEbinsearch(sal_uInt16 *ar, sal_uInt16 length, sal_uInt16 toSearch) {
+ signed int low, mid, high, lastfound = 0xffff;
+ sal_uInt16 res;
+ if(length == (sal_uInt16)0 || length == (sal_uInt16)0xFFFF) {
+ return (sal_uInt16)0xFFFF;
+ }
+ low = 0;
+ high = length - 1;
+ while(high >= low) {
+ mid = (high + low)/2;
+ res = Int16FromMOTA(*(ar+mid));
+ if(res >= toSearch) {
+ lastfound = mid;
+ high = --mid;
+ } else {
+ low = ++mid;
+ }
+ }
+ return (sal_uInt16)lastfound;
+}
+
+
+static sal_uInt32 getGlyph4(const sal_uInt8 *cmap, sal_uInt32 c) {
+ sal_uInt16 i;
+ int ToReturn;
+ sal_uInt16 segCount;
+ sal_uInt16 * startCode;
+ sal_uInt16 * endCode;
+ sal_uInt16 * idDelta;
+ /* sal_uInt16 * glyphIdArray; */
+ sal_uInt16 * idRangeOffset;
+ sal_uInt16 * glyphIndexArray;
+ sal_uInt16 *CMAP4 = (sal_uInt16 *) cmap;
+ /* sal_uInt16 GEbinsearch(sal_uInt16 *ar, sal_uInt16 length, sal_uInt16 toSearch); */
+
+ segCount = Int16FromMOTA(*(CMAP4 + 3))/2;
+ endCode = CMAP4 + 7;
+ i = GEbinsearch(endCode, segCount, (sal_uInt16)c);
+
+ if (i == (sal_uInt16) 0xFFFF) {
+ return MISSING_GLYPH_INDEX;
+ }
+ startCode = endCode + segCount + 1;
+
+ if(Int16FromMOTA(startCode[i]) > c) {
+ return MISSING_GLYPH_INDEX;
+ }
+ idDelta = startCode + segCount;
+ idRangeOffset = idDelta + segCount;
+ glyphIndexArray = idRangeOffset + segCount;
+
+ if(Int16FromMOTA(idRangeOffset[i]) != 0) {
+ c = Int16FromMOTA(*(&(idRangeOffset[i]) + (Int16FromMOTA(idRangeOffset[i])/2 + (c - Int16FromMOTA(startCode[i])))));
+ }
+
+ ToReturn = (Int16FromMOTA(idDelta[i]) + c) & 0xFFFF;
+ return ToReturn;
+}
+
+static sal_uInt32 getGlyph12(const sal_uInt8 *pCmap, sal_uInt32 cChar) {
+ const sal_uInt32* pCMAP12 = (const sal_uInt32*)pCmap;
+ int nLength = Int32FromMOTA( pCMAP12[1] );
+ int nGroups = Int32FromMOTA( pCMAP12[3] );
+ int nLower = 0;
+ int nUpper = nGroups;
+
+ if( nUpper > (nLength-16)/12 )
+ nUpper = (nLength-16)/12;
+
+ /* binary search in "segmented coverage" subtable */
+ while( nLower < nUpper ) {
+ int nIndex = (nLower + nUpper) / 2;
+ const sal_uInt32* pEntry = &pCMAP12[ 4 + 3*nIndex ];
+ sal_uInt32 cStart = Int32FromMOTA( pEntry[0] );
+ sal_uInt32 cLast = Int32FromMOTA( pEntry[1] );
+ if( cChar < cStart )
+ nUpper = nIndex;
+ else if( cChar > cLast )
+ nLower = nIndex + 1;
+ else { /* found matching entry! */
+ sal_uInt32 nGlyph = Int32FromMOTA( pEntry[2] );
+ nGlyph += cChar - cStart;
+ return nGlyph;
+ }
+ }
+
+ return MISSING_GLYPH_INDEX;
+}
+
+
+static void FindCmap(TrueTypeFont *ttf)
+{
+ const sal_uInt8* table = getTable(ttf, O_cmap);
+ sal_uInt32 table_size = getTableSize(ttf, O_cmap);
+ sal_uInt16 ncmaps = GetUInt16(table, 2, 1);
+ unsigned int i;
+ sal_uInt32 AppleUni = 0; // Apple Unicode
+ sal_uInt32 ThreeZero = 0; /* MS Symbol */
+ sal_uInt32 ThreeOne = 0; /* MS UCS-2 */
+ sal_uInt32 ThreeTwo = 0; /* MS ShiftJIS */
+ sal_uInt32 ThreeThree = 0; /* MS Big5 */
+ sal_uInt32 ThreeFour = 0; /* MS PRC */
+ sal_uInt32 ThreeFive = 0; /* MS Wansung */
+ sal_uInt32 ThreeSix = 0; /* MS Johab */
+
+ for (i = 0; i < ncmaps; i++) {
+ sal_uInt32 offset;
+ sal_uInt16 pID, eID;
+
+ /* sanity check, cmap entry must lie within table */
+ if( i*8+4 > table_size )
+ break;
+
+ pID = GetUInt16(table, 4 + i * 8, 1);
+ eID = GetUInt16(table, 6 + i * 8, 1);
+ offset = GetUInt32(table, 8 + i * 8, 1);
+
+ /* sanity check, cmap must lie within file */
+ if( (table - ttf->ptr) + offset > (sal_uInt32)ttf->fsize )
+ continue;
+
+ /* Unicode tables in Apple fonts */
+ if (pID == 0) {
+ AppleUni = offset;
+ }
+
+ if (pID == 3) {
+ switch (eID) {
+ case 0: ThreeZero = offset; break;
+ case 10: // UCS-4
+ case 1: ThreeOne = offset; break;
+ case 2: ThreeTwo = offset; break;
+ case 3: ThreeThree = offset; break;
+ case 4: ThreeFour = offset; break;
+ case 5: ThreeFive = offset; break;
+ case 6: ThreeSix = offset; break;
+ }
+ }
+ }
+
+ // fall back to AppleUnicode if there are no ThreeOne/Threezero tables
+ if( AppleUni && !ThreeZero && !ThreeOne)
+ ThreeOne = AppleUni;
+
+ if (ThreeOne) {
+ ttf->cmapType = CMAP_MS_Unicode;
+ ttf->cmap = table + ThreeOne;
+ } else if (ThreeTwo) {
+ ttf->cmapType = CMAP_MS_ShiftJIS;
+ ttf->cmap = table + ThreeTwo;
+ } else if (ThreeThree) {
+ ttf->cmapType = CMAP_MS_Big5;
+ ttf->cmap = table + ThreeThree;
+ } else if (ThreeFour) {
+ ttf->cmapType = CMAP_MS_PRC;
+ ttf->cmap = table + ThreeFour;
+ } else if (ThreeFive) {
+ ttf->cmapType = CMAP_MS_Wansung;
+ ttf->cmap = table + ThreeFive;
+ } else if (ThreeSix) {
+ ttf->cmapType = CMAP_MS_Johab;
+ ttf->cmap = table + ThreeSix;
+ } else if (ThreeZero) {
+ ttf->cmapType = CMAP_MS_Symbol;
+ ttf->cmap = table + ThreeZero;
+ } else {
+ ttf->cmapType = CMAP_NOT_USABLE;
+ ttf->cmap = 0;
+ }
+
+ if (ttf->cmapType != CMAP_NOT_USABLE) {
+ switch (GetUInt16(ttf->cmap, 0, 1)) {
+ case 0: ttf->mapper = getGlyph0; break;
+ case 2: ttf->mapper = getGlyph2; break;
+ case 4: ttf->mapper = getGlyph4; break;
+ case 6: ttf->mapper = getGlyph6; break;
+ case 12: ttf->mapper= getGlyph12; break;
+ default:
+#if OSL_DEBUG_LEVEL > 1
+ /*- if the cmap table is really broken */
+ printf("%s: %d is not a recognized cmap format.\n", ttf->fname, GetUInt16(ttf->cmap, 0, 1));
+#endif
+ ttf->cmapType = CMAP_NOT_USABLE;
+ ttf->cmap = 0;
+ ttf->mapper = 0;
+ }
+ }
+}
+
+static void GetKern(TrueTypeFont *ttf)
+{
+ const sal_uInt8* table = getTable(ttf, O_kern);
+ const sal_uInt8 *ptr;
+
+ if( !table )
+ goto badtable;
+
+ if (GetUInt16(table, 0, 1) == 0) { /* Traditional Microsoft style table with USHORT version and nTables fields */
+ ttf->nkern = GetUInt16(table, 2, 1);
+ ttf->kerntables = (const sal_uInt8**)calloc(ttf->nkern, sizeof(sal_uInt8 *));
+ assert(ttf->kerntables != 0);
+ memset(ttf->kerntables, 0, ttf->nkern * sizeof(sal_uInt8 *));
+ ttf->kerntype = KT_MICROSOFT;
+ ptr = table + 4;
+ for( unsigned i = 0; i < ttf->nkern; ++i) {
+ ttf->kerntables[i] = ptr;
+ ptr += GetUInt16(ptr, 2, 1);
+ /* sanity check */
+ if( ptr > ttf->ptr+ttf->fsize )
+ {
+ free( ttf->kerntables );
+ goto badtable;
+ }
+ }
+ return;
+ }
+
+ if (GetUInt32(table, 0, 1) == 0x00010000) { /* MacOS style kern tables: fixed32 version and sal_uInt32 nTables fields */
+ ttf->nkern = GetUInt32(table, 4, 1);
+ ttf->kerntables = (const sal_uInt8**)calloc(ttf->nkern, sizeof(sal_uInt8*));
+ assert(ttf->kerntables != 0);
+ memset(ttf->kerntables, 0, ttf->nkern * sizeof(sal_uInt8 *));
+ ttf->kerntype = KT_APPLE_NEW;
+ ptr = table + 8;
+ for( unsigned i = 0; i < ttf->nkern; ++i) {
+ ttf->kerntables[i] = ptr;
+ ptr += GetUInt32(ptr, 0, 1);
+ /* sanity check; there are some fonts that are broken in this regard */
+ if( ptr > ttf->ptr+ttf->fsize )
+ {
+ free( ttf->kerntables );
+ goto badtable;
+ }
+ }
+ return;
+ }
+
+ badtable:
+ ttf->kerntype = KT_NONE;
+ ttf->kerntables = 0;
+
+ return;
+}
+
+#ifdef TEST5
+/* KernGlyphsPrim?() functions expect the caller to ensure the validity of their arguments and
+ * that x and y elements of the kern array are initialized to zeroes
+ */
+static void KernGlyphsPrim1(TrueTypeFont *ttf, sal_uInt16 *glyphs, int nglyphs, int wmode, KernData *kern)
+{
+ (void)ttf; /* avoid warning */
+ (void)glyphs; /* avoid warning */
+ (void)nglyphs; /* avoid warning */
+ (void)wmode; /* avoid warning */
+ (void)nglyphs; /* avoid warning */
+ (void)kern; /* avoid warning */
+ fprintf(stderr, "MacOS kerning tables have not been implemented yet!\n");
+}
+
+static void KernGlyphsPrim2(TrueTypeFont *ttf, sal_uInt16 *glyphs, int nglyphs, int wmode, KernData *kern)
+{
+ sal_uInt32 i, j;
+ sal_uInt32 gpair;
+
+ if( ! nglyphs )
+ return;
+
+ for (i = 0; i < (sal_uInt32)nglyphs - 1; i++) {
+ gpair = (glyphs[i] << 16) | glyphs[i+1];
+#ifdef DEBUG2
+ /* All fonts with MS kern table that I've seen so far contain just one kern subtable.
+ * MS kern documentation is very poor and I doubt that font developers will be using
+ * several subtables. I expect them to be using OpenType tables instead.
+ * According to MS documention, format 2 subtables are not supported by Windows and OS/2.
+ */
+ if (ttf->nkern > 1) {
+ fprintf(stderr, "KernGlyphsPrim2: %d kern tables found.\n", ttf->nkern);
+ }
+#endif
+ for (j = 0; j < ttf->nkern; j++) {
+ sal_uInt16 coverage = GetUInt16(ttf->kerntables[j], 4, 1);
+ sal_uInt8 *ptr;
+ int npairs;
+ sal_uInt32 t;
+ int l, r, k;
+
+ if (! ((coverage & 1) ^ wmode)) continue;
+ if ((coverage & 0xFFFE) != 0) {
+#ifdef DEBUG2
+ fprintf(stderr, "KernGlyphsPrim2: coverage flags are not supported: %04X.\n", coverage);
+#endif
+ continue;
+ }
+ ptr = ttf->kerntables[j];
+ npairs = GetUInt16(ptr, 6, 1);
+ ptr += 14;
+ l = 0;
+ r = npairs;
+ do {
+ k = (l + r) >> 1;
+ t = GetUInt32(ptr, k * 6, 1);
+ if (gpair >= t) l = k + 1;
+ if (gpair <= t) r = k - 1;
+ } while (l <= r);
+ if (l - r == 2) {
+ if (!wmode) {
+ kern[i].x = XUnits(ttf->unitsPerEm, GetInt16(ptr, 4 + (l-1) * 6, 1));
+ } else {
+ kern[i].y = XUnits(ttf->unitsPerEm, GetInt16(ptr, 4 + (l-1) * 6, 1));
+ }
+ /* !wmode ? kern[i].x : kern[i].y = GetInt16(ptr, 4 + (l-1) * 6, 1); */
+ }
+ }
+ }
+}
+#endif
+
+/*- Public functions */ /*FOLD00*/
+
+int CountTTCFonts(const char* fname)
+{
+ int nFonts = 0;
+ sal_uInt8 buffer[12];
+ FILE* fd = fopen(fname, "rb");
+ if( fd ) {
+ if (fread(buffer, 1, 12, fd) == 12) {
+ if(GetUInt32(buffer, 0, 1) == T_ttcf )
+ nFonts = GetUInt32(buffer, 8, 1);
+ }
+ fclose(fd);
+ }
+ return nFonts;
+}
+
+static void allocTrueTypeFont( TrueTypeFont** ttf )
+{
+ *ttf = (TrueTypeFont*)calloc(1,sizeof(TrueTypeFont));
+ if( *ttf != NULL )
+ {
+ (*ttf)->tag = 0;
+ (*ttf)->fname = 0;
+ (*ttf)->fsize = -1;
+ (*ttf)->ptr = 0;
+ (*ttf)->nglyphs = 0xFFFFFFFF;
+ (*ttf)->pGSubstitution = 0;
+ }
+}
+
+/* forward declariotn for the two entry points to use*/
+static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t );
+
+#if !defined(WIN32) && !defined(OS2)
+int OpenTTFontFile( const char* fname, sal_uInt32 facenum, TrueTypeFont** ttf )
+{
+ int ret, fd = -1;
+ struct stat st;
+
+ if (!fname || !*fname) return SF_BADFILE;
+
+ allocTrueTypeFont( ttf );
+ if( ! *ttf )
+ return SF_MEMORY;
+
+ (*ttf)->fname = strdup(fname);
+ if( ! (*ttf)->fname )
+ {
+ ret = SF_MEMORY;
+ goto cleanup;
+ }
+
+ fd = open(fname, O_RDONLY);
+
+ if (fd == -1) {
+ ret = SF_BADFILE;
+ goto cleanup;
+ }
+
+ if (fstat(fd, &st) == -1) {
+ ret = SF_FILEIO;
+ goto cleanup;
+ }
+
+ (*ttf)->fsize = st.st_size;
+
+ /* On Mac OS, most likely will happen if a Mac user renames a font file
+ * to be .ttf when its really a Mac resource-based font.
+ * Size will be 0, but fonts smaller than 4 bytes would be broken anyway.
+ */
+ if ((*ttf)->fsize == 0) {
+ ret = SF_BADFILE;
+ goto cleanup;
+ }
+
+ if (((*ttf)->ptr = (sal_uInt8 *) mmap(0, (*ttf)->fsize, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ ret = SF_MEMORY;
+ goto cleanup;
+ }
+ close(fd);
+
+ return doOpenTTFont( facenum, *ttf );
+
+cleanup:
+ if (fd != -1) close(fd);
+ /*- t and t->fname have been allocated! */
+ free((*ttf)->fname);
+ free(*ttf);
+ *ttf = NULL;
+ return ret;
+}
+#endif
+
+int OpenTTFontBuffer(void* pBuffer, sal_uInt32 nLen, sal_uInt32 facenum, TrueTypeFont** ttf)
+{
+ allocTrueTypeFont( ttf );
+ if( *ttf == NULL )
+ return SF_MEMORY;
+
+ (*ttf)->fname = NULL;
+ (*ttf)->fsize = nLen;
+ (*ttf)->ptr = (sal_uInt8*)pBuffer;
+
+ return doOpenTTFont( facenum, *ttf );
+}
+
+static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t )
+{
+ int i;
+ sal_uInt32 length, tag;
+ sal_uInt32 tdoffset = 0; /* offset to TableDirectory in a TTC file. For TTF files is 0 */
+ int indexfmt, k;
+
+ sal_uInt32 version = GetInt32(t->ptr, 0, 1);
+
+ if ((version == 0x00010000) || (version == T_true)) {
+ tdoffset = 0;
+ } else if (version == T_otto) { /* PS-OpenType font */
+ tdoffset = 0;
+ } else if (version == T_ttcf) { /* TrueType collection */
+ if (GetUInt32(t->ptr, 4, 1) != 0x00010000) {
+ CloseTTFont(t);
+ return SF_TTFORMAT;
+ }
+ if (facenum >= GetUInt32(t->ptr, 8, 1)) {
+ CloseTTFont(t);
+ return SF_FONTNO;
+ }
+ tdoffset = GetUInt32(t->ptr, 12 + 4 * facenum, 1);
+ } else {
+ CloseTTFont(t);
+ return SF_TTFORMAT;
+ }
+
+#ifdef DEBUG2
+ fprintf(stderr, "tdoffset: %d\n", tdoffset);
+#endif
+
+ /* magic number */
+ t->tag = TTFontClassTag;
+
+ t->ntables = GetUInt16(t->ptr + tdoffset, 4, 1);
+ if( t->ntables >= 128 )
+ return SF_TTFORMAT;
+
+ t->tables = (const sal_uInt8**)calloc(NUM_TAGS, sizeof(sal_uInt8*));
+ assert(t->tables != 0);
+ t->tlens = (sal_uInt32*)calloc(NUM_TAGS, sizeof(sal_uInt32));
+ assert(t->tlens != 0);
+
+ memset(t->tables, 0, NUM_TAGS * sizeof(void *));
+ memset(t->tlens, 0, NUM_TAGS * sizeof(sal_uInt32));
+
+ /* parse the tables */
+ for (i=0; i<(int)t->ntables; i++) {
+ int nIndex;
+ tag = GetUInt32(t->ptr + tdoffset + 12, 16 * i, 1);
+ switch( tag ) {
+ case T_maxp: nIndex = O_maxp; break;
+ case T_glyf: nIndex = O_glyf; break;
+ case T_head: nIndex = O_head; break;
+ case T_loca: nIndex = O_loca; break;
+ case T_name: nIndex = O_name; break;
+ case T_hhea: nIndex = O_hhea; break;
+ case T_hmtx: nIndex = O_hmtx; break;
+ case T_cmap: nIndex = O_cmap; break;
+ case T_vhea: nIndex = O_vhea; break;
+ case T_vmtx: nIndex = O_vmtx; break;
+ case T_OS2 : nIndex = O_OS2; break;
+ case T_post: nIndex = O_post; break;
+ case T_kern: nIndex = O_kern; break;
+ case T_cvt : nIndex = O_cvt; break;
+ case T_prep: nIndex = O_prep; break;
+ case T_fpgm: nIndex = O_fpgm; break;
+ case T_gsub: nIndex = O_gsub; break;
+ case T_CFF: nIndex = O_CFF; break;
+ default: nIndex = -1; break;
+ }
+ if( nIndex >= 0 ) {
+ sal_uInt32 nTableOffset = GetUInt32(t->ptr + tdoffset + 12, 16 * i + 8, 1);
+ length = GetUInt32(t->ptr + tdoffset + 12, 16 * i + 12, 1);
+ t->tables[nIndex] = t->ptr + nTableOffset;
+ t->tlens[nIndex] = length;
+ }
+ }
+
+ /* Fixup offsets when only a TTC extract was provided */
+ if( facenum == (sal_uInt32)~0 ) {
+ sal_uInt8* pHead = (sal_uInt8*)t->tables[O_head];
+ if( !pHead )
+ return SF_TTFORMAT;
+ /* limit Head candidate to TTC extract's limits */
+ if( pHead > t->ptr + (t->fsize - 54) )
+ pHead = t->ptr + (t->fsize - 54);
+ /* TODO: find better method than searching head table's magic */
+ sal_uInt8* p = NULL;
+ for( p = pHead + 12; p > t->ptr; --p ) {
+ if( p[0]==0x5F && p[1]==0x0F && p[2]==0x3C && p[3]==0xF5 ) {
+ int nDelta = (pHead + 12) - p, j;
+ if( nDelta )
+ for( j=0; j<NUM_TAGS; ++j )
+ if( t->tables[j] )
+ *(char**)&t->tables[j] -= nDelta;
+ break;
+ }
+ }
+ if( p <= t->ptr )
+ return SF_TTFORMAT;
+ }
+
+ /* Check the table offsets after TTC correction */
+ for (i=0; i<NUM_TAGS; i++) {
+ /* sanity check: table must lay completely within the file
+ * at this point one could check the checksum of all contained
+ * tables, but this would be quite time intensive.
+ * Try to fix tables, so we can cope with minor problems.
+ */
+
+ if( (sal_uInt8*)t->tables[i] < t->ptr )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ if( t->tables[i] )
+ fprintf( stderr, "font file %s has bad table offset %d (tagnum=%d)\n", t->fname, (sal_uInt8*)t->tables[i]-t->ptr, i );
+#endif
+ t->tlens[i] = 0;
+ t->tables[i] = NULL;
+ }
+ else if( (sal_uInt8*)t->tables[i] + t->tlens[i] > t->ptr + t->fsize )
+ {
+ int nMaxLen = (t->ptr + t->fsize) - (sal_uInt8*)t->tables[i];
+ if( nMaxLen < 0 )
+ nMaxLen = 0;
+ t->tlens[i] = nMaxLen;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "font file %s has too big table (tagnum=%d)\n", t->fname, i );
+#endif
+ }
+ }
+
+ /* At this point TrueTypeFont is constructed, now need to verify the font format
+ and read the basic font properties */
+
+ /* The following tables are absolutely required:
+ * maxp, head, name, cmap
+ */
+
+ if( !(getTable(t, O_maxp) && getTable(t, O_head) && getTable(t, O_name) && getTable(t, O_cmap)) ) {
+ CloseTTFont(t);
+ return SF_TTFORMAT;
+ }
+
+ const sal_uInt8* table = getTable(t, O_maxp);
+ t->nglyphs = GetUInt16(table, 4, 1);
+
+ table = getTable(t, O_head);
+ t->unitsPerEm = GetUInt16(table, 18, 1);
+ indexfmt = GetInt16(table, 50, 1);
+
+ if( ((indexfmt != 0) && (indexfmt != 1)) || (t->unitsPerEm <= 0) ) {
+ CloseTTFont(t);
+ return SF_TTFORMAT;
+ }
+
+ if( getTable(t, O_glyf) && getTable(t, O_loca) ) { /* TTF or TTF-OpenType */
+ k = (getTableSize(t, O_loca) / (indexfmt ? 4 : 2)) - 1;
+ if( k < (int)t->nglyphs ) /* Hack for broken Chinese fonts */
+ t->nglyphs = k;
+
+ table = getTable(t, O_loca);
+ t->goffsets = (sal_uInt32 *) calloc(1+t->nglyphs, sizeof(sal_uInt32));
+ assert(t->goffsets != 0);
+
+ for( i = 0; i <= (int)t->nglyphs; ++i )
+ t->goffsets[i] = indexfmt ? GetUInt32(table, i << 2, 1) : (sal_uInt32)GetUInt16(table, i << 1, 1) << 1;
+ } else if( getTable(t, O_CFF) ) { /* PS-OpenType */
+ t->goffsets = (sal_uInt32 *) calloc(1+t->nglyphs, sizeof(sal_uInt32));
+ /* TODO: implement to get subsetting */
+ assert(t->goffsets != 0);
+ } else {
+ CloseTTFont(t);
+ return SF_TTFORMAT;
+ }
+
+ table = getTable(t, O_hhea);
+ t->numberOfHMetrics = (table != 0) ? GetUInt16(table, 34, 1) : 0;
+
+ table = getTable(t, O_vhea);
+ t->numOfLongVerMetrics = (table != 0) ? GetUInt16(table, 34, 1) : 0;
+
+ GetNames(t);
+ FindCmap(t);
+ GetKern(t);
+ ReadGSUB( t, 0, 0 );
+
+ return SF_OK;
+}
+
+void CloseTTFont(TrueTypeFont *ttf) /*FOLD01*/
+{
+ if (ttf->tag != TTFontClassTag) return;
+
+#if !defined(WIN32) && !defined(OS2)
+ if( ttf->fname )
+ munmap((char *) ttf->ptr, ttf->fsize);
+#endif
+ free(ttf->fname);
+ free(ttf->goffsets);
+ free(ttf->psname);
+ free(ttf->family);
+ if( ttf->ufamily )
+ free( ttf->ufamily );
+ free(ttf->subfamily);
+ if( ttf->usubfamily )
+ free( ttf->usubfamily );
+ free(ttf->tables);
+ free(ttf->tlens);
+ free(ttf->kerntables);
+
+ ReleaseGSUB(ttf);
+
+ free(ttf);
+ return;
+}
+
+int GetTTGlyphPoints(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray)
+{
+ return GetTTGlyphOutline(ttf, glyphID, pointArray, 0, 0);
+}
+
+int GetTTGlyphComponents(TrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist)
+{
+ int n = 1;
+
+ if( glyphID >= ttf->nglyphs )
+ return 0;
+
+ const sal_uInt8* glyf = getTable(ttf, O_glyf);
+ const sal_uInt8* ptr = glyf + ttf->goffsets[glyphID];
+
+ glyphlist.push_back( glyphID );
+
+ if (GetInt16(ptr, 0, 1) == -1) {
+ sal_uInt16 flags, index;
+ ptr += 10;
+ do {
+ flags = GetUInt16(ptr, 0, 1);
+ index = GetUInt16(ptr, 2, 1);
+
+ ptr += 4;
+ n += GetTTGlyphComponents(ttf, index, glyphlist);
+
+ if (flags & ARG_1_AND_2_ARE_WORDS) {
+ ptr += 4;
+ } else {
+ ptr += 2;
+ }
+
+ if (flags & WE_HAVE_A_SCALE) {
+ ptr += 2;
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+ ptr += 4;
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+ ptr += 8;
+ }
+ } while (flags & MORE_COMPONENTS);
+ }
+
+ return n;
+}
+
+#ifndef NO_TYPE3
+int CreateT3FromTTGlyphs(TrueTypeFont *ttf, FILE *outf, const char *fname, /*FOLD00*/
+ sal_uInt16 *glyphArray, sal_uInt8 *encoding, int nGlyphs,
+ int wmode)
+{
+ ControlPoint *pa;
+ PSPathElement *path;
+ int i, j, r, n;
+ const sal_uInt8* table = getTable(ttf, O_head);
+ TTGlyphMetrics metrics;
+ int UPEm = ttf->unitsPerEm;
+
+ const char *h01 = "%%!PS-AdobeFont-%d.%d-%d.%d\n";
+ const char *h02 = "%% Creator: %s %s %s\n";
+ const char *h09 = "%% Original font name: %s\n";
+
+ const char *h10 =
+ "30 dict begin\n"
+ "/PaintType 0 def\n"
+ "/FontType 3 def\n"
+ "/StrokeWidth 0 def\n";
+
+ const char *h11 = "/FontName (%s) cvn def\n";
+
+ /*
+ const char *h12 = "%/UniqueID %d def\n";
+ */
+ const char *h13 = "/FontMatrix [.001 0 0 .001 0 0] def\n";
+ const char *h14 = "/FontBBox [%d %d %d %d] def\n";
+
+ const char *h15=
+ "/Encoding 256 array def\n"
+ " 0 1 255 {Encoding exch /.notdef put} for\n";
+
+ const char *h16 = " Encoding %d /glyph%d put\n";
+ const char *h17 = "/XUID [103 0 0 16#%08X %d 16#%08X 16#%08X] def\n";
+
+ const char *h30 = "/CharProcs %d dict def\n";
+ const char *h31 = " CharProcs begin\n";
+ const char *h32 = " /.notdef {} def\n";
+ const char *h33 = " /glyph%d {\n";
+ const char *h34 = " } bind def\n";
+ const char *h35 = " end\n";
+
+ const char *h40 =
+ "/BuildGlyph {\n"
+ " exch /CharProcs get exch\n"
+ " 2 copy known not\n"
+ " {pop /.notdef} if\n"
+ " get exec\n"
+ "} bind def\n"
+ "/BuildChar {\n"
+ " 1 index /Encoding get exch get\n"
+ " 1 index /BuildGlyph get exec\n"
+ "} bind def\n"
+ "currentdict end\n";
+
+ const char *h41 = "(%s) cvn exch definefont pop\n";
+
+
+ if (!((nGlyphs > 0) && (nGlyphs <= 256))) return SF_GLYPHNUM;
+ if (!glyphArray) return SF_BADARG;
+ if (!fname) fname = ttf->psname;
+
+ fprintf(outf, h01, GetInt16(table, 0, 1), GetUInt16(table, 2, 1), GetInt16(table, 4, 1), GetUInt16(table, 6, 1));
+ fprintf(outf, h02, modname, modver, modextra);
+ fprintf(outf, h09, ttf->psname);
+
+ fprintf(outf, h10);
+ fprintf(outf, h11, fname);
+/* fprintf(outf, h12, 4000000); */
+
+ /* XUID generation:
+ * 103 0 0 C1 C2 C3 C4
+ * C1 - CRC-32 of the entire source TrueType font
+ * C2 - number of glyphs in the subset
+ * C3 - CRC-32 of the glyph array
+ * C4 - CRC-32 of the encoding array
+ *
+ * All CRC-32 numbers are presented as hexadecimal numbers
+ */
+
+ fprintf(outf, h17, rtl_crc32(0, ttf->ptr, ttf->fsize), nGlyphs, rtl_crc32(0, glyphArray, nGlyphs * 2), rtl_crc32(0, encoding, nGlyphs));
+ fprintf(outf, h13);
+ fprintf(outf, h14, XUnits(UPEm, GetInt16(table, 36, 1)), XUnits(UPEm, GetInt16(table, 38, 1)), XUnits(UPEm, GetInt16(table, 40, 1)), XUnits(UPEm, GetInt16(table, 42, 1)));
+ fprintf(outf, h15);
+
+ for (i = 0; i < nGlyphs; i++) {
+ fprintf(outf, h16, encoding[i], i);
+ }
+
+ fprintf(outf, h30, nGlyphs+1);
+ fprintf(outf, h31);
+ fprintf(outf, h32);
+
+ for (i = 0; i < nGlyphs; i++) {
+ fprintf(outf, h33, i);
+ r = GetTTGlyphOutline(ttf, glyphArray[i] < ttf->nglyphs ? glyphArray[i] : 0, &pa, &metrics, 0);
+
+ if (r > 0) {
+ n = BSplineToPSPath(pa, r, &path);
+ } else {
+ n = 0; /* glyph might have zero contours but valid metrics ??? */
+ path = 0;
+ if (r < 0) { /* glyph is not present in the font - pa array was not allocated, so no need to free it */
+ continue;
+ }
+ }
+ fprintf(outf, "\t%d %d %d %d %d %d setcachedevice\n",
+ wmode == 0 ? XUnits(UPEm, metrics.aw) : 0,
+ wmode == 0 ? 0 : -XUnits(UPEm, metrics.ah),
+ XUnits(UPEm, metrics.xMin),
+ XUnits(UPEm, metrics.yMin),
+ XUnits(UPEm, metrics.xMax),
+ XUnits(UPEm, metrics.yMax));
+
+ for (j = 0; j < n; j++)
+ {
+ switch (path[j].type)
+ {
+ case PS_MOVETO:
+ fprintf(outf, "\t%d %d moveto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1));
+ break;
+
+ case PS_LINETO:
+ fprintf(outf, "\t%d %d lineto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1));
+ break;
+
+ case PS_CURVETO:
+ fprintf(outf, "\t%d %d %d %d %d %d curveto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1), XUnits(UPEm, path[j].x2), XUnits(UPEm, path[j].y2), XUnits(UPEm, path[j].x3), XUnits(UPEm, path[j].y3));
+ break;
+
+ case PS_CLOSEPATH:
+ fprintf(outf, "\tclosepath\n");
+ break;
+ case PS_NOOP:
+ break;
+ }
+ }
+ if (n > 0) fprintf(outf, "\tfill\n"); /* if glyph is not a whitespace character */
+
+ fprintf(outf, h34);
+
+ free(pa);
+ free(path);
+ }
+ fprintf(outf, h35);
+
+ fprintf(outf, h40);
+ fprintf(outf, h41, fname);
+
+ return SF_OK;
+}
+#endif
+
+#ifndef NO_TTCR
+int CreateTTFromTTGlyphs(TrueTypeFont *ttf,
+ const char *fname,
+ sal_uInt16 *glyphArray,
+ sal_uInt8 *encoding,
+ int nGlyphs,
+ int nNameRecs,
+ NameRecord *nr,
+ sal_uInt32 flags)
+{
+ TrueTypeCreator *ttcr;
+ TrueTypeTable *head=0, *hhea=0, *maxp=0, *cvt=0, *prep=0, *glyf=0, *fpgm=0, *cmap=0, *name=0, *post = 0, *os2 = 0;
+ int i;
+ int res;
+
+ TrueTypeCreatorNewEmpty(T_true, &ttcr);
+
+ /** name **/
+
+ if (flags & TTCF_AutoName) {
+ /* not implemented yet
+ NameRecord *names;
+ NameRecord newname;
+ int n = GetTTNameRecords(ttf, &names);
+ int n1 = 0, n2 = 0, n3 = 0, n4 = 0, n5 = 0, n6 = 0;
+ sal_uInt8 *cp1;
+ sal_uInt8 suffix[32];
+ sal_uInt32 c1 = crc32(glyphArray, nGlyphs * 2);
+ sal_uInt32 c2 = crc32(encoding, nGlyphs);
+ int len;
+ snprintf(suffix, 31, "S%08X%08X-%d", c1, c2, nGlyphs);
+
+ name = TrueTypeTableNew_name(0, 0);
+ for (i = 0; i < n; i++) {
+ if (names[i].platformID == 1 && names[i].encodingID == 0 && names[i].languageID == 0 && names[i].nameID == 1) {
+
+ memcpy(newname, names+i, sizeof(NameRecord));
+ newname.slen = name[i].slen + strlen(suffix);
+ */
+ const sal_uInt8 ptr[] = {0,'T',0,'r',0,'u',0,'e',0,'T',0,'y',0,'p',0,'e',0,'S',0,'u',0,'b',0,'s',0,'e',0,'t'};
+ NameRecord n1 = {1, 0, 0, 6, 14, (sal_uInt8*)"TrueTypeSubset"};
+ NameRecord n2 = {3, 1, 1033, 6, 28, 0};
+ n2.sptr = (sal_uInt8 *) ptr;
+ name = TrueTypeTableNew_name(0, 0);
+ nameAdd(name, &n1);
+ nameAdd(name, &n2);
+ } else {
+ if (nNameRecs == 0) {
+ NameRecord *names;
+ int n = GetTTNameRecords(ttf, &names);
+ name = TrueTypeTableNew_name(n, names);
+ DisposeNameRecords(names, n);
+ } else {
+ name = TrueTypeTableNew_name(nNameRecs, nr);
+ }
+ }
+
+ /** maxp **/
+ maxp = TrueTypeTableNew_maxp(getTable(ttf, O_maxp), getTableSize(ttf, O_maxp));
+
+ /** hhea **/
+ const sal_uInt8* p = getTable(ttf, O_hhea);
+ if (p) {
+ hhea = TrueTypeTableNew_hhea(GetUInt16(p, 4, 1), GetUInt16(p, 6, 1), GetUInt16(p, 8, 1), GetUInt16(p, 18, 1), GetUInt16(p, 20, 1));
+ } else {
+ hhea = TrueTypeTableNew_hhea(0, 0, 0, 0, 0);
+ }
+
+ /** head **/
+
+ p = getTable(ttf, O_head);
+ assert(p != 0);
+ head = TrueTypeTableNew_head(GetUInt32(p, 4, 1),
+ GetUInt16(p, 16, 1),
+ GetUInt16(p, 18, 1),
+ p+20,
+ GetUInt16(p, 44, 1),
+ GetUInt16(p, 46, 1),
+ GetInt16(p, 48, 1));
+
+
+ /** glyf **/
+
+ glyf = TrueTypeTableNew_glyf();
+ sal_uInt32* gID = (sal_uInt32*)scalloc(nGlyphs, sizeof(sal_uInt32));
+
+ for (i = 0; i < nGlyphs; i++) {
+ gID[i] = glyfAdd(glyf, GetTTRawGlyphData(ttf, glyphArray[i]), ttf);
+ }
+
+ /** cmap **/
+ cmap = TrueTypeTableNew_cmap();
+
+ for (i=0; i < nGlyphs; i++) {
+ cmapAdd(cmap, 0x010000, encoding[i], gID[i]);
+ }
+
+ /** cvt **/
+ if ((p = getTable(ttf, O_cvt)) != 0) {
+ cvt = TrueTypeTableNew(T_cvt, getTableSize(ttf, O_cvt), p);
+ }
+
+ /** prep **/
+ if ((p = getTable(ttf, O_prep)) != 0) {
+ prep = TrueTypeTableNew(T_prep, getTableSize(ttf, O_prep), p);
+ }
+
+ /** fpgm **/
+ if ((p = getTable(ttf, O_fpgm)) != 0) {
+ fpgm = TrueTypeTableNew(T_fpgm, getTableSize(ttf, O_fpgm), p);
+ }
+
+ /** post **/
+ if ((p = getTable(ttf, O_post)) != 0) {
+ post = TrueTypeTableNew_post(0x00030000,
+ GetUInt32(p, 4, 1),
+ GetUInt16(p, 8, 1),
+ GetUInt16(p, 10, 1),
+ GetUInt16(p, 12, 1));
+ } else {
+ post = TrueTypeTableNew_post(0x00030000, 0, 0, 0, 0);
+ }
+
+ if (flags & TTCF_IncludeOS2) {
+ if ((p = getTable(ttf, O_OS2)) != 0) {
+ os2 = TrueTypeTableNew(T_OS2, getTableSize(ttf, O_OS2), p);
+ }
+ }
+
+ AddTable(ttcr, name); AddTable(ttcr, maxp); AddTable(ttcr, hhea);
+ AddTable(ttcr, head); AddTable(ttcr, glyf); AddTable(ttcr, cmap);
+ AddTable(ttcr, cvt ); AddTable(ttcr, prep); AddTable(ttcr, fpgm);
+ AddTable(ttcr, post); AddTable(ttcr, os2);
+
+ if ((res = StreamToFile(ttcr, fname)) != SF_OK) {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "StreamToFile: error code: %d.\n", res);
+#endif
+ }
+
+ TrueTypeCreatorDispose(ttcr);
+ free(gID);
+
+ return res;
+}
+#endif
+
+
+#ifndef NO_TYPE42
+static GlyphOffsets *GlyphOffsetsNew(sal_uInt8 *sfntP)
+{
+ GlyphOffsets* res = (GlyphOffsets*)smalloc(sizeof(GlyphOffsets));
+ sal_uInt8 *loca = NULL;
+ sal_uInt16 i, numTables = GetUInt16(sfntP, 4, 1);
+ sal_uInt32 locaLen = 0;
+ sal_Int16 indexToLocFormat = 0;
+
+ for (i = 0; i < numTables; i++) {
+ sal_uInt32 tag = GetUInt32(sfntP + 12, 16 * i, 1);
+ sal_uInt32 off = GetUInt32(sfntP + 12, 16 * i + 8, 1);
+ sal_uInt32 len = GetUInt32(sfntP + 12, 16 * i + 12, 1);
+
+ if (tag == T_loca) {
+ loca = sfntP + off;
+ locaLen = len;
+ } else if (tag == T_head) {
+ indexToLocFormat = GetInt16(sfntP + off, 50, 1);
+ }
+ }
+
+ res->nGlyphs = locaLen / ((indexToLocFormat == 1) ? 4 : 2);
+ assert(res->nGlyphs != 0);
+ res->offs = (sal_uInt32*)scalloc(res->nGlyphs, sizeof(sal_uInt32));
+
+ for (i = 0; i < res->nGlyphs; i++) {
+ if (indexToLocFormat == 1) {
+ res->offs[i] = GetUInt32(loca, i * 4, 1);
+ } else {
+ res->offs[i] = GetUInt16(loca, i * 2, 1) << 1;
+ }
+ }
+ return res;
+}
+
+static void GlyphOffsetsDispose(GlyphOffsets *_this)
+{
+ if (_this) {
+ free(_this->offs);
+ free(_this);
+ }
+}
+
+static void DumpSfnts(FILE *outf, sal_uInt8 *sfntP)
+{
+ HexFmt *h = HexFmtNew(outf);
+ sal_uInt16 i, numTables = GetUInt16(sfntP, 4, 1);
+ GlyphOffsets *go = GlyphOffsetsNew(sfntP);
+ sal_uInt8 pad[] = {0,0,0,0}; /* zeroes */
+
+ assert(numTables <= 9); /* Type42 has 9 required tables */
+
+ sal_uInt32* offs = (sal_uInt32*)scalloc(numTables, sizeof(sal_uInt32));
+// sal_uInt32* lens = (sal_uInt32*)scalloc(numTables, sizeof(sal_uInt32));
+
+ fputs("/sfnts [", outf);
+ HexFmtOpenString(h);
+ HexFmtBlockWrite(h, sfntP, 12); /* stream out the Offset Table */
+ HexFmtBlockWrite(h, sfntP+12, 16 * numTables); /* stream out the Table Directory */
+
+ for (i=0; i<numTables; i++) {
+ sal_uInt32 tag = GetUInt32(sfntP + 12, 16 * i, 1);
+ sal_uInt32 off = GetUInt32(sfntP + 12, 16 * i + 8, 1);
+ sal_uInt32 len = GetUInt32(sfntP + 12, 16 * i + 12, 1);
+
+ if (tag != T_glyf) {
+ HexFmtBlockWrite(h, sfntP + off, len);
+ } else {
+ sal_uInt8 *glyf = sfntP + off;
+ sal_uInt32 o, l, j;
+ for (j = 0; j < go->nGlyphs - 1; j++) {
+ o = go->offs[j];
+ l = go->offs[j + 1] - o;
+ HexFmtBlockWrite(h, glyf + o, l);
+ }
+ }
+ HexFmtBlockWrite(h, pad, (4 - (len & 3)) & 3);
+ }
+ HexFmtCloseString(h);
+ fputs("] def\n", outf);
+ GlyphOffsetsDispose(go);
+ HexFmtDispose(h);
+ free(offs);
+// free(lens);
+}
+
+int CreateT42FromTTGlyphs(TrueTypeFont *ttf,
+ FILE *outf,
+ const char *psname,
+ sal_uInt16 *glyphArray,
+ sal_uInt8 *encoding,
+ int nGlyphs)
+{
+ TrueTypeCreator *ttcr;
+ TrueTypeTable *head=0, *hhea=0, *maxp=0, *cvt=0, *prep=0, *glyf=0, *fpgm=0;
+ int i;
+ int res;
+
+ sal_uInt32 ver, rev;
+
+ sal_uInt8 *sfntP;
+ sal_uInt32 sfntLen;
+ int UPEm = ttf->unitsPerEm;
+
+ if (nGlyphs >= 256) return SF_GLYPHNUM;
+
+ assert(psname != 0);
+
+ TrueTypeCreatorNewEmpty(T_true, &ttcr);
+
+ /* head */
+ const sal_uInt8* p = getTable(ttf, O_head);
+ const sal_uInt8* headP = p;
+ assert(p != 0);
+ head = TrueTypeTableNew_head(GetUInt32(p, 4, 1), GetUInt16(p, 16, 1), GetUInt16(p, 18, 1), p+20, GetUInt16(p, 44, 1), GetUInt16(p, 46, 1), GetInt16(p, 48, 1));
+ ver = GetUInt32(p, 0, 1);
+ rev = GetUInt32(p, 4, 1);
+
+ /** hhea **/
+ p = getTable(ttf, O_hhea);
+ if (p) {
+ hhea = TrueTypeTableNew_hhea(GetUInt16(p, 4, 1), GetUInt16(p, 6, 1), GetUInt16(p, 8, 1), GetUInt16(p, 18, 1), GetUInt16(p, 20, 1));
+ } else {
+ hhea = TrueTypeTableNew_hhea(0, 0, 0, 0, 0);
+ }
+
+ /** maxp **/
+ maxp = TrueTypeTableNew_maxp(getTable(ttf, O_maxp), getTableSize(ttf, O_maxp));
+
+ /** cvt **/
+ if ((p = getTable(ttf, O_cvt)) != 0) {
+ cvt = TrueTypeTableNew(T_cvt, getTableSize(ttf, O_cvt), p);
+ }
+
+ /** prep **/
+ if ((p = getTable(ttf, O_prep)) != 0) {
+ prep = TrueTypeTableNew(T_prep, getTableSize(ttf, O_prep), p);
+ }
+
+ /** fpgm **/
+ if ((p = getTable(ttf, O_fpgm)) != 0) {
+ fpgm = TrueTypeTableNew(T_fpgm, getTableSize(ttf, O_fpgm), p);
+ }
+
+ /** glyf **/
+ glyf = TrueTypeTableNew_glyf();
+ sal_uInt16* gID = (sal_uInt16*)scalloc(nGlyphs, sizeof(sal_uInt32));
+
+ for (i = 0; i < nGlyphs; i++) {
+ gID[i] = (sal_uInt16)glyfAdd(glyf, GetTTRawGlyphData(ttf, glyphArray[i]), ttf);
+ }
+
+ AddTable(ttcr, head); AddTable(ttcr, hhea); AddTable(ttcr, maxp); AddTable(ttcr, cvt);
+ AddTable(ttcr, prep); AddTable(ttcr, glyf); AddTable(ttcr, fpgm);
+
+ if ((res = StreamToMemory(ttcr, &sfntP, &sfntLen)) != SF_OK) {
+ TrueTypeCreatorDispose(ttcr);
+ free(gID);
+ return res;
+ }
+
+ fprintf(outf, "%%!PS-TrueTypeFont-%d.%d-%d.%d\n", (int)(ver>>16), (int)(ver & 0xFFFF), (int)(rev>>16), (int)(rev & 0xFFFF));
+ fprintf(outf, "%%%%Creator: %s %s %s\n", modname, modver, modextra);
+ fprintf(outf, "%%- Font subset generated from a source font file: '%s'\n", ttf->fname);
+ fprintf(outf, "%%- Original font name: %s\n", ttf->psname);
+ fprintf(outf, "%%- Original font family: %s\n", ttf->family);
+ fprintf(outf, "%%- Original font sub-family: %s\n", ttf->subfamily);
+ fprintf(outf, "11 dict begin\n");
+ fprintf(outf, "/FontName (%s) cvn def\n", psname);
+ fprintf(outf, "/PaintType 0 def\n");
+ fprintf(outf, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(outf, "/FontBBox [%d %d %d %d] def\n", XUnits(UPEm, GetInt16(headP, 36, 1)), XUnits(UPEm, GetInt16(headP, 38, 1)), XUnits(UPEm, GetInt16(headP, 40, 1)), XUnits(UPEm, GetInt16(headP, 42, 1)));
+ fprintf(outf, "/FontType 42 def\n");
+ fprintf(outf, "/Encoding 256 array def\n");
+ fprintf(outf, " 0 1 255 {Encoding exch /.notdef put} for\n");
+
+ for (i = 1; i<nGlyphs; i++) {
+ fprintf(outf, "Encoding %d /glyph%d put\n", encoding[i], gID[i]);
+ }
+ fprintf(outf, "/XUID [103 0 1 16#%08X %d 16#%08X 16#%08X] def\n", (unsigned int)rtl_crc32(0, ttf->ptr, ttf->fsize), (unsigned int)nGlyphs, (unsigned int)rtl_crc32(0, glyphArray, nGlyphs * 2), (unsigned int)rtl_crc32(0, encoding, nGlyphs));
+
+ DumpSfnts(outf, sfntP);
+
+ /* dump charstrings */
+ fprintf(outf, "/CharStrings %d dict dup begin\n", nGlyphs);
+ fprintf(outf, "/.notdef 0 def\n");
+ for (i = 1; i < (int)glyfCount(glyf); i++) {
+ fprintf(outf,"/glyph%d %d def\n", i, i);
+ }
+ fprintf(outf, "end readonly def\n");
+
+ fprintf(outf, "FontName currentdict end definefont pop\n");
+ TrueTypeCreatorDispose(ttcr);
+ free(gID);
+ free(sfntP);
+ return SF_OK;
+}
+#endif
+
+
+#ifndef NO_MAPPERS
+int MapString(TrueTypeFont *ttf, sal_uInt16 *str, int nchars, sal_uInt16 *glyphArray, int bvertical)
+{
+ int i;
+ sal_uInt16 *cp;
+
+ if (ttf->cmapType == CMAP_NOT_USABLE ) return -1;
+ if (!nchars) return 0;
+
+ if (glyphArray == 0) {
+ cp = str;
+ } else {
+ cp = glyphArray;
+ }
+
+ switch (ttf->cmapType) {
+ case CMAP_MS_Symbol:
+ if( ttf->mapper == getGlyph0 ) {
+ sal_uInt16 aChar;
+ for( i = 0; i < nchars; i++ ) {
+ aChar = str[i];
+ if( ( aChar & 0xf000 ) == 0xf000 )
+ aChar &= 0x00ff;
+ cp[i] = aChar;
+ }
+ }
+ else if( glyphArray )
+ memcpy(glyphArray, str, nchars * 2);
+ break;
+
+ case CMAP_MS_Unicode:
+ if (glyphArray != 0) {
+ memcpy(glyphArray, str, nchars * 2);
+ }
+ break;
+
+ case CMAP_MS_ShiftJIS: TranslateString12(str, cp, nchars); break;
+ case CMAP_MS_Big5: TranslateString13(str, cp, nchars); break;
+ case CMAP_MS_PRC: TranslateString14(str, cp, nchars); break;
+ case CMAP_MS_Wansung: TranslateString15(str, cp, nchars); break;
+ case CMAP_MS_Johab: TranslateString16(str, cp, nchars); break;
+ }
+
+ for (i = 0; i < nchars; i++) {
+ cp[i] = (sal_uInt16)ttf->mapper(ttf->cmap, cp[i]);
+ if (cp[i]!=0 && bvertical!=0)
+ cp[i] = (sal_uInt16)UseGSUB(ttf,cp[i],bvertical);
+ }
+ return nchars;
+}
+
+sal_uInt16 MapChar(TrueTypeFont *ttf, sal_uInt16 ch, int bvertical)
+{
+ switch (ttf->cmapType) {
+ case CMAP_MS_Symbol:
+
+ if( ttf->mapper == getGlyph0 && ( ch & 0xf000 ) == 0xf000 )
+ ch &= 0x00ff;
+ return (sal_uInt16)ttf->mapper(ttf->cmap, ch );
+
+ case CMAP_MS_Unicode: break;
+ case CMAP_MS_ShiftJIS: ch = TranslateChar12(ch); break;
+ case CMAP_MS_Big5: ch = TranslateChar13(ch); break;
+ case CMAP_MS_PRC: ch = TranslateChar14(ch); break;
+ case CMAP_MS_Wansung: ch = TranslateChar15(ch); break;
+ case CMAP_MS_Johab: ch = TranslateChar16(ch); break;
+ default: return 0;
+ }
+ ch = (sal_uInt16)ttf->mapper(ttf->cmap, ch);
+ if (ch!=0 && bvertical!=0)
+ ch = (sal_uInt16)UseGSUB(ttf,ch,bvertical);
+ return ch;
+}
+
+int DoesVerticalSubstitution( TrueTypeFont *ttf, int bvertical)
+{
+ int nRet = 0;
+ if( bvertical)
+ nRet = HasVerticalGSUB( ttf);
+ return nRet;
+}
+
+#endif
+
+int GetTTGlyphCount( TrueTypeFont* ttf )
+{
+ return ttf->nglyphs;
+}
+
+bool GetSfntTable( TrueTypeFont* ttf, int nSubtableIndex,
+ const sal_uInt8** ppRawBytes, int* pRawLength )
+{
+ if( (nSubtableIndex < 0) || (nSubtableIndex >= NUM_TAGS) )
+ return false;
+ *pRawLength = ttf->tlens[ nSubtableIndex ];
+ *ppRawBytes = ttf->tables[ nSubtableIndex ];
+ bool bOk = (*pRawLength > 0) && (ppRawBytes != NULL);
+ return bOk;
+}
+
+TTSimpleGlyphMetrics *GetTTSimpleGlyphMetrics(TrueTypeFont *ttf, sal_uInt16 *glyphArray, int nGlyphs, int mode)
+{
+ const sal_uInt8* pTable;
+ sal_uInt32 n;
+ int nTableSize;
+
+ if (mode == 0) {
+ n = ttf->numberOfHMetrics;
+ pTable = getTable( ttf, O_hmtx );
+ nTableSize = getTableSize( ttf, O_hmtx );
+ } else {
+ n = ttf->numOfLongVerMetrics;
+ pTable = getTable( ttf, O_vmtx );
+ nTableSize = getTableSize( ttf, O_vmtx );
+ }
+
+ if (!nGlyphs || !glyphArray) return 0; /* invalid parameters */
+ if (!n || !pTable) return 0; /* the font does not contain the requested metrics */
+
+ TTSimpleGlyphMetrics* res = (TTSimpleGlyphMetrics*)calloc(nGlyphs, sizeof(TTSimpleGlyphMetrics));
+ assert(res != 0);
+
+ const int UPEm = ttf->unitsPerEm;
+ for( int i = 0; i < nGlyphs; ++i) {
+ int nAdvOffset, nLsbOffset;
+ sal_uInt16 glyphID = glyphArray[i];
+
+ if (glyphID < n) {
+ nAdvOffset = 4 * glyphID;
+ nLsbOffset = nAdvOffset + 2;
+ } else {
+ nAdvOffset = 4 * (n - 1);
+ if( glyphID < ttf->nglyphs )
+ nLsbOffset = 4 * n + 2 * (glyphID - n);
+ else /* font is broken -> use lsb of last hmetrics */
+ nLsbOffset = nAdvOffset + 2;
+ }
+
+ if( nAdvOffset >= nTableSize)
+ res[i].adv = 0; /* better than a crash for buggy fonts */
+ else
+ res[i].adv = static_cast<sal_uInt16>(
+ XUnits( UPEm, GetUInt16( pTable, nAdvOffset, 1) ) );
+
+ if( nLsbOffset >= nTableSize)
+ res[i].sb = 0; /* better than a crash for buggy fonts */
+ else
+ res[i].sb = static_cast<sal_Int16>(
+ XUnits( UPEm, GetInt16( pTable, nLsbOffset, 1) ) );
+ }
+
+ return res;
+}
+
+#ifndef NO_MAPPERS
+TTSimpleGlyphMetrics *GetTTSimpleCharMetrics(TrueTypeFont * ttf, sal_uInt16 firstChar, int nChars, int mode)
+{
+ TTSimpleGlyphMetrics *res = 0;
+ int i, n;
+
+ sal_uInt16* str = (sal_uInt16*)malloc(nChars * 2);
+ assert(str != 0);
+
+ for (i=0; i<nChars; i++) str[i] = (sal_uInt16)(firstChar + i);
+ if ((n = MapString(ttf, str, nChars, 0, mode)) != -1) {
+ res = GetTTSimpleGlyphMetrics(ttf, str, n, mode);
+ }
+
+ free(str);
+
+ return res;
+}
+#endif
+
+void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info)
+{
+ int UPEm = ttf->unitsPerEm;
+
+ memset(info, 0, sizeof(TTGlobalFontInfo));
+
+ info->family = ttf->family;
+ info->ufamily = ttf->ufamily;
+ info->subfamily = ttf->subfamily;
+ info->usubfamily = ttf->usubfamily;
+ info->psname = ttf->psname;
+ info->symbolEncoded = (ttf->cmapType == CMAP_MS_Symbol);
+
+ const sal_uInt8* table = getTable(ttf, O_OS2);
+ if (table) {
+ info->weight = GetUInt16(table, 4, 1);
+ info->width = GetUInt16(table, 6, 1);
+
+ /* There are 3 different versions of OS/2 table: original (68 bytes long),
+ * Microsoft old (78 bytes long) and Microsoft new (86 bytes long,)
+ * Apple's documentation recommends looking at the table length.
+ */
+ if (getTableSize(ttf, O_OS2) > 68) {
+ info->typoAscender = XUnits(UPEm,GetInt16(table, 68, 1));
+ info->typoDescender = XUnits(UPEm, GetInt16(table, 70, 1));
+ info->typoLineGap = XUnits(UPEm, GetInt16(table, 72, 1));
+ info->winAscent = XUnits(UPEm, GetUInt16(table, 74, 1));
+ info->winDescent = XUnits(UPEm, GetUInt16(table, 76, 1));
+ /* sanity check; some fonts treat winDescent as signed
+ * violating the standard */
+ if( info->winDescent > 5*UPEm )
+ info->winDescent = XUnits(UPEm, GetInt16(table, 76,1));
+ }
+ if (ttf->cmapType == CMAP_MS_Unicode) {
+ info->rangeFlag = 1;
+ info->ur1 = GetUInt32(table, 42, 1);
+ info->ur2 = GetUInt32(table, 46, 1);
+ info->ur3 = GetUInt32(table, 50, 1);
+ info->ur4 = GetUInt32(table, 54, 1);
+ }
+ memcpy(info->panose, table + 32, 10);
+ info->typeFlags = GetUInt16( table, 8, 1 );
+ if( getTable(ttf, O_CFF) )
+ info->typeFlags |= TYPEFLAG_PS_OPENTYPE;
+ }
+
+ table = getTable(ttf, O_post);
+ if (table && getTableSize(ttf, O_post) >= 12+sizeof(sal_uInt32)) {
+ info->pitch = GetUInt32(table, 12, 1);
+ info->italicAngle = GetInt32(table, 4, 1);
+ }
+
+ table = getTable(ttf, O_head); /* 'head' tables is always there */
+ info->xMin = XUnits(UPEm, GetInt16(table, 36, 1));
+ info->yMin = XUnits(UPEm, GetInt16(table, 38, 1));
+ info->xMax = XUnits(UPEm, GetInt16(table, 40, 1));
+ info->yMax = XUnits(UPEm, GetInt16(table, 42, 1));
+ info->macStyle = GetInt16(table, 44, 1);
+
+ table = getTable(ttf, O_hhea);
+ if (table) {
+ info->ascender = XUnits(UPEm, GetInt16(table, 4, 1));
+ info->descender = XUnits(UPEm, GetInt16(table, 6, 1));
+ info->linegap = XUnits(UPEm, GetInt16(table, 8, 1));
+ }
+
+ table = getTable(ttf, O_vhea);
+ if (table) {
+ info->vascent = XUnits(UPEm, GetInt16(table, 4, 1));
+ info->vdescent = XUnits(UPEm, GetInt16(table, 6, 1));
+ }
+}
+
+#ifdef TEST5
+void KernGlyphs(TrueTypeFont *ttf, sal_uInt16 *glyphs, int nglyphs, int wmode, KernData *kern)
+{
+ int i;
+
+ if (!nglyphs || !glyphs || !kern) return;
+
+ for (i = 0; i < nglyphs-1; i++) kern[i].x = kern[i].y = 0;
+
+ switch (ttf->kerntype) {
+ case KT_APPLE_NEW: KernGlyphsPrim1(ttf, glyphs, nglyphs, wmode, kern); return;
+ case KT_MICROSOFT: KernGlyphsPrim2(ttf, glyphs, nglyphs, wmode, kern); return;
+ default: return;
+ }
+}
+#endif
+
+GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, sal_uInt32 glyphID)
+{
+ const sal_uInt8* glyf = getTable(ttf, O_glyf);
+ const sal_uInt8* hmtx = getTable(ttf, O_hmtx);
+ int i, n, m;
+
+ if( glyphID >= ttf->nglyphs )
+ return 0;
+
+ /* #127161# check the glyph offsets */
+ sal_uInt32 length = getTableSize( ttf, O_glyf );
+ if( length < ttf->goffsets[ glyphID+1 ] )
+ return 0;
+
+ length = ttf->goffsets[glyphID+1] - ttf->goffsets[glyphID];
+
+ GlyphData* d = (GlyphData*)malloc(sizeof(GlyphData)); assert(d != 0);
+
+ if (length > 0) {
+ const sal_uInt8* srcptr = glyf + ttf->goffsets[glyphID];
+ d->ptr = (sal_uInt8*)malloc((length + 1) & ~1); assert(d->ptr != 0);
+ memcpy( d->ptr, srcptr, length );
+ d->compflag = (GetInt16( srcptr, 0, 1 ) < 0);
+ } else {
+ d->ptr = 0;
+ d->compflag = 0;
+ }
+
+ d->glyphID = glyphID;
+ d->nbytes = (sal_uInt16)((length + 1) & ~1);
+
+ /* now calculate npoints and ncontours */
+ ControlPoint *cp;
+ n = GetTTGlyphPoints(ttf, glyphID, &cp);
+ if (n != -1) {
+ m = 0;
+ for (i = 0; i < n; i++) {
+ if (cp[i].flags & 0x8000) m++;
+ }
+ d->npoints = (sal_uInt16)n;
+ d->ncontours = (sal_uInt16)m;
+ free(cp);
+ } else {
+ d->npoints = 0;
+ d->ncontours = 0;
+ }
+
+ /* get advance width and left sidebearing */
+ if (glyphID < ttf->numberOfHMetrics) {
+ d->aw = GetUInt16(hmtx, 4 * glyphID, 1);
+ d->lsb = GetInt16(hmtx, 4 * glyphID + 2, 1);
+ } else {
+ d->aw = GetUInt16(hmtx, 4 * (ttf->numberOfHMetrics - 1), 1);
+ d->lsb = GetInt16(hmtx + ttf->numberOfHMetrics * 4, (glyphID - ttf->numberOfHMetrics) * 2, 1);
+ }
+
+ return d;
+}
+
+int GetTTNameRecords(TrueTypeFont *ttf, NameRecord **nr)
+{
+ const sal_uInt8* table = getTable(ttf, O_name);
+ int nTableSize = getTableSize(ttf, O_name );
+
+ if (nTableSize < 6)
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "O_name table too small\n");
+#endif
+ return 0;
+ }
+
+ sal_uInt16 n = GetUInt16(table, 2, 1);
+ int nStrBase = GetUInt16(table, 4, 1);
+ int i;
+
+ *nr = 0;
+ if (n == 0) return 0;
+
+ NameRecord* rec = (NameRecord*)calloc(n, sizeof(NameRecord));
+
+ for (i = 0; i < n; i++) {
+ int nStrOffset = GetUInt16(table + 6, 10 + 12 * i, 1);
+ rec[i].platformID = GetUInt16(table + 6, 12 * i, 1);
+ rec[i].encodingID = GetUInt16(table + 6, 2 + 12 * i, 1);
+ rec[i].languageID = GetUInt16(table + 6, 4 + 12 * i, 1);
+ rec[i].nameID = GetUInt16(table + 6, 6 + 12 * i, 1);
+ rec[i].slen = GetUInt16(table + 6, 8 + 12 * i, 1);
+ if (rec[i].slen) {
+ if( nStrBase+nStrOffset+rec[i].slen >= nTableSize ) {
+ rec[i].sptr = 0;
+ rec[i].slen = 0;
+ continue;
+ }
+
+ const sal_uInt8* rec_string = table + nStrBase + nStrOffset;
+ // sanity check
+ if( rec_string > (sal_uInt8*)ttf->ptr && rec_string < ((sal_uInt8*)ttf->ptr + ttf->fsize - rec[i].slen ) )
+ {
+ rec[i].sptr = (sal_uInt8 *) malloc(rec[i].slen); assert(rec[i].sptr != 0);
+ memcpy(rec[i].sptr, rec_string, rec[i].slen);
+ }
+ else
+ {
+#ifdef DEBUG
+ fprintf( stderr, "found invalid name record %d with name id %d for file %s\n",
+ i, rec[i].nameID, ttf->fname );
+#endif
+ rec[i].sptr = 0;
+ rec[i].slen = 0;
+ }
+ } else {
+ rec[i].sptr = 0;
+ }
+ // some fonts have 3.0 names => fix them to 3.1
+ if( (rec[i].platformID == 3) && (rec[i].encodingID == 0) )
+ rec[i].encodingID = 1;
+ }
+
+ *nr = rec;
+ return n;
+}
+
+void DisposeNameRecords(NameRecord* nr, int n)
+{
+ int i;
+ for (i = 0; i < n; i++) {
+ if (nr[i].sptr) free(nr[i].sptr);
+ }
+ free(nr);
+}
+
+} // namespace vcl
+
+
+#ifdef TEST1
+/* This example creates a subset of a TrueType font with two encoded characters */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ int r;
+
+ /* Array of Unicode source characters */
+ sal_uInt16 chars[2];
+
+ /* Encoding vector maps character encoding to the ordinal number
+ * of the glyph in the output file */
+ sal_uInt8 encoding[2];
+
+ /* This array is for glyph IDs that source characters map to */
+ sal_uInt16 g[2];
+
+
+ if (ac < 2) return 0;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+
+ /* We want to create the output file that only contains two Unicode characters:
+ * L'a' and L'A' */
+
+ chars[0] = L'a';
+ chars[1] = L'A';
+
+ /* Figure out what glyphs do these characters map in our font */
+ MapString(fnt, chars, 2, g);
+
+ /* Encode the characters. Value of encoding[i] is the number 0..255 which maps to glyph i of the
+ * newly generated font */
+ encoding[0] = chars[0];
+ encoding[1] = chars[1];
+
+
+ /* Generate a subset */
+ CreateT3FromTTGlyphs(fnt, stdout, 0, g, encoding, 2, 0);
+
+ /* Now call the dtor for the font */
+ CloseTTFont(fnt);
+ return 0;
+}
+#endif
+
+#ifdef TEST2
+/* This example extracts first 224 glyphs from a TT fonts and encodes them starting at 32 */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ int i, r;
+
+ /* Array of Unicode source characters */
+ sal_uInt16 glyphs[224];
+
+ /* Encoding vector maps character encoding to the ordinal number
+ * of the glyph in the output file */
+ sal_uInt8 encoding[224];
+
+
+
+ for (i=0; i<224; i++) {
+ glyphs[i] = i;
+ encoding[i] = 32 + i;
+ }
+
+ if (ac < 2) return 0;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+
+ /* Encode the characters. Value of encoding[i] is the number 0..255 which maps to glyph i of the
+ * newly generated font */
+
+ /* Generate a subset */
+ CreateT3FromTTGlyphs(fnt, stdout, 0, glyphs, encoding, 224, 0);
+
+ /* Now call the dtor for the font */
+ CloseTTFont(fnt);
+ return 0;
+}
+#endif
+
+#ifdef TEST3
+/* Glyph metrics example */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ int i, r;
+ sal_uInt16 glyphs[224];
+ TTSimpleGlyphMetrics *m;
+
+ for (i=0; i<224; i++) {
+ glyphs[i] = i;
+ }
+
+ if (ac < 2) return 0;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ if ((m = GetTTSimpleGlyphMetrics(fnt, glyphs, 224, 0)) == 0) {
+ printf("Requested metrics is not available\n");
+ } else {
+ for (i=0; i<224; i++) {
+ printf("%d. advWid: %5d, LSBear: %5d\n", i, m[i].adv, m[i].sb);
+ }
+ }
+
+ /* Now call the dtor for the font */
+ free(m);
+ CloseTTFont(fnt);
+ return 0;
+}
+#endif
+
+#ifdef TEST4
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ TTGlobalFontInfo info;
+ int i, r;
+
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ printf("Font file: %s\n", av[1]);
+
+#ifdef PRINT_KERN
+ switch (fnt->kerntype) {
+ case KT_MICROSOFT:
+ printf("\tkern: MICROSOFT, ntables: %d.", fnt->nkern);
+ if (fnt->nkern) {
+ printf(" [");
+ for (i=0; i<fnt->nkern; i++) {
+ printf("%04X ", GetUInt16(fnt->kerntables[i], 4, 1));
+ }
+ printf("]");
+ }
+ printf("\n");
+ break;
+
+ case KT_APPLE_NEW:
+ printf("\tkern: APPLE_NEW, ntables: %d.", fnt->nkern);
+ if (fnt->nkern) {
+ printf(" [");
+ for (i=0; i<fnt->nkern; i++) {
+ printf("%04X ", GetUInt16(fnt->kerntables[i], 4, 1));
+ }
+ printf("]");
+ }
+ printf("\n");
+ break;
+
+ case KT_NONE:
+ printf("\tkern: none.\n");
+ break;
+
+ default:
+ printf("\tkern: unrecoginzed.\n");
+ break;
+ }
+ printf("\n");
+#endif
+
+ GetTTGlobalFontInfo(fnt, &info);
+ printf("\tfamily name: `%s`\n", info.family);
+ printf("\tsubfamily name: `%s`\n", info.subfamily);
+ printf("\tpostscript name: `%s`\n", info.psname);
+ printf("\tweight: %d\n", info.weight);
+ printf("\twidth: %d\n", info.width);
+ printf("\tpitch: %d\n", info.pitch);
+ printf("\titalic angle: %d\n", info.italicAngle);
+ printf("\tbouding box: [%d %d %d %d]\n", info.xMin, info.yMin, info.xMax, info.yMax);
+ printf("\tascender: %d\n", info.ascender);
+ printf("\tdescender: %d\n", info.descender);
+ printf("\tlinegap: %d\n", info.linegap);
+ printf("\tvascent: %d\n", info.vascent);
+ printf("\tvdescent: %d\n", info.vdescent);
+ printf("\ttypoAscender: %d\n", info.typoAscender);
+ printf("\ttypoDescender: %d\n", info.typoDescender);
+ printf("\ttypoLineGap: %d\n", info.typoLineGap);
+ printf("\twinAscent: %d\n", info.winAscent);
+ printf("\twinDescent: %d\n", info.winDescent);
+ printf("\tUnicode ranges:\n");
+ for (i = 0; i < 32; i++) {
+ if ((info.ur1 >> i) & 1) {
+ printf("\t\t\t%s\n", UnicodeRangeName(i));
+ }
+ }
+ for (i = 0; i < 32; i++) {
+ if ((info.ur2 >> i) & 1) {
+ printf("\t\t\t%s\n", UnicodeRangeName(i+32));
+ }
+ }
+ for (i = 0; i < 32; i++) {
+ if ((info.ur3 >> i) & 1) {
+ printf("\t\t\t%s\n", UnicodeRangeName(i+64));
+ }
+ }
+ for (i = 0; i < 32; i++) {
+ if ((info.ur4 >> i) & 1) {
+ printf("\t\t\t%s\n", UnicodeRangeName(i+96));
+ }
+ }
+
+ CloseTTFont(fnt);
+ return 0;
+}
+#endif
+
+#ifdef TEST5
+/* Kerning example */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ sal_uInt16 g[224];
+ KernData d[223];
+ int r, i, k = 0;
+
+ g[k++] = 11;
+ g[k++] = 36;
+ g[k++] = 11;
+ g[k++] = 98;
+ g[k++] = 11;
+ g[k++] = 144;
+ g[k++] = 41;
+ g[k++] = 171;
+ g[k++] = 51;
+ g[k++] = 15;
+
+ if (ac < 2) return 0;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ KernGlyphs(fnt, g, k, 0, d);
+
+ for (i = 0; i < k-1; i++) {
+ printf("%3d %3d: [%3d %3d]\n", g[i], g[i+1], d[i].x, d[i].y);
+ }
+
+ CloseTTFont(fnt);
+ return 0;
+}
+#endif
+
+
+
+#ifdef TEST6
+/* This example extracts a single glyph from a font */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ int r, i;
+
+ sal_uInt16 glyphs[256];
+ sal_uInt8 encoding[256];
+
+ for (i=0; i<256; i++) {
+ glyphs[i] = 512 + i;
+ encoding[i] = i;
+ }
+
+#if 0
+ i=0;
+ glyphs[i++] = 2001;
+ glyphs[i++] = 2002;
+ glyphs[i++] = 2003;
+ glyphs[i++] = 2004;
+ glyphs[i++] = 2005;
+ glyphs[i++] = 2006;
+ glyphs[i++] = 2007;
+ glyphs[i++] = 2008;
+ glyphs[i++] = 2009;
+ glyphs[i++] = 2010;
+ glyphs[i++] = 2011;
+ glyphs[i++] = 2012;
+ glyphs[i++] = 2013;
+ glyphs[i++] = 2014;
+ glyphs[i++] = 2015;
+ glyphs[i++] = 2016;
+ glyphs[i++] = 2017;
+ glyphs[i++] = 2018;
+ glyphs[i++] = 2019;
+ glyphs[i++] = 2020;
+
+
+ r = 97;
+ i = 0;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+ encoding[i++] = r++;
+#endif
+
+ if (ac < 2) return 0;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ /* Generate a subset */
+ CreateT3FromTTGlyphs(fnt, stdout, 0, glyphs, encoding, 256, 0);
+
+ fprintf(stderr, "UnitsPerEm: %d.\n", fnt->unitsPerEm);
+
+ /* Now call the dtor for the font */
+ CloseTTFont(fnt);
+ return 0;
+}
+#endif
+
+#ifdef TEST7
+/* NameRecord extraction example */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ int r, i, j, n;
+ NameRecord *nr;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ if ((n = GetTTNameRecords(fnt, &nr)) == 0) {
+ fprintf(stderr, "No name records in the font.\n");
+ return 0;
+ }
+
+ printf("Number of name records: %d.\n", n);
+ for (i = 0; i < n; i++) {
+ printf("%d %d %04X %d [", nr[i].platformID, nr[i].encodingID, nr[i].languageID, nr[i].nameID);
+ for (j=0; j<nr[i].slen; j++) {
+ printf("%c", isprint(nr[i].sptr[j]) ? nr[i].sptr[j] : '.');
+ }
+ printf("]\n");
+ }
+
+
+ DisposeNameRecords(nr, n);
+ CloseTTFont(fnt);
+ return 0;
+}
+#endif
+
+#ifdef TEST8
+/* TrueType -> TrueType subsetting */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ sal_uInt16 glyphArray[] = { 0, 98, 99, 22, 24, 25, 26, 27, 28, 29, 30, 31, 1270, 1289, 34};
+ sal_uInt8 encoding[] = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46};
+ int r;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ CreateTTFromTTGlyphs(fnt, "subfont.ttf", glyphArray, encoding, 15, 0, 0, TTCF_AutoName | TTCF_IncludeOS2);
+
+
+ CloseTTFont(fnt);
+
+ return 0;
+}
+#endif
+
+#ifdef TEST9
+/* TrueType -> Type42 subsetting */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ /*
+ sal_uInt16 glyphArray[] = { 0, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34};
+ sal_uInt8 encoding[] = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46};
+ */
+ sal_uInt16 glyphArray[] = { 0, 6711, 6724, 11133, 11144, 14360, 26, 27, 28, 29, 30, 31, 1270, 1289, 34};
+ sal_uInt8 encoding[] = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46};
+ int r;
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ CreateT42FromTTGlyphs(fnt, stdout, "testfont", glyphArray, encoding, 15);
+
+ CloseTTFont(fnt);
+
+ return 0;
+}
+#endif
+
+#ifdef TEST10
+/* Component glyph test */
+int main(int ac, char **av)
+{
+ TrueTypeFont *fnt;
+ int r, i;
+ list glyphlist = listNewEmpty();
+
+
+ if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) {
+ fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]);
+ return 0;
+ }
+
+ for (i = 0; i < fnt->nglyphs; i++) {
+ r = GetTTGlyphComponents(fnt, i, glyphlist);
+ if (r > 1) {
+ printf("%d -> ", i);
+ listToFirst(glyphlist);
+ do {
+ printf("%d ", (int) listCurrent(glyphlist));
+ } while (listNext(glyphlist));
+ printf("\n");
+ } else {
+ printf("%d: single glyph.\n", i);
+ }
+ listClear(glyphlist);
+ }
+
+ CloseTTFont(fnt);
+ listDispose(glyphlist);
+
+ return 0;
+}
+#endif
+
+
diff --git a/vcl/source/fontsubset/ttcr.cxx b/vcl/source/fontsubset/ttcr.cxx
new file mode 100644
index 000000000000..badf9fb496b0
--- /dev/null
+++ b/vcl/source/fontsubset/ttcr.cxx
@@ -0,0 +1,1666 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/*
+ * TrueTypeCreator method implementation
+ *
+ * @author: Alexander Gelfenbain
+ *
+ */
+
+#if OSL_DEBUG_LEVEL == 0
+# ifndef NDEBUG
+# define NDEBUG
+# endif
+#endif
+#include <assert.h>
+
+#include "ttcr.hxx"
+#include "list.h"
+#include "string.h"
+
+
+
+namespace vcl
+{
+
+/*
+ * Private Data Types
+ */
+
+ struct _TrueTypeCreator {
+ sal_uInt32 tag; /**< TrueType file tag */
+ list tables; /**< List of table tags and pointers */
+ };
+
+/* These must be #defined so that they can be used in initializers */
+#define T_maxp 0x6D617870
+#define T_glyf 0x676C7966
+#define T_head 0x68656164
+#define T_loca 0x6C6F6361
+#define T_name 0x6E616D65
+#define T_hhea 0x68686561
+#define T_hmtx 0x686D7478
+#define T_cmap 0x636D6170
+#define T_vhea 0x76686561
+#define T_vmtx 0x766D7478
+#define T_OS2 0x4F532F32
+#define T_post 0x706F7374
+#define T_kern 0x6B65726E
+#define T_cvt 0x63767420
+
+typedef struct {
+ sal_uInt32 tag;
+ sal_uInt32 length;
+ sal_uInt8 *data;
+} TableEntry;
+
+/*
+ * this is a duplicate code from sft.c but it is left here for performance reasons
+ */
+#ifdef __GNUC__
+#define _inline static __inline__
+#else
+#define _inline static
+#endif
+
+_inline sal_uInt32 mkTag(sal_uInt8 a, sal_uInt8 b, sal_uInt8 c, sal_uInt8 d) {
+ return (a << 24) | (b << 16) | (c << 8) | d;
+}
+
+/*- Data access macros for data stored in big-endian or little-endian format */
+_inline sal_Int16 GetInt16( const sal_uInt8* ptr, sal_uInt32 offset, int bigendian)
+{
+ sal_Int16 t;
+ assert(ptr != 0);
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
+ } else {
+ t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+_inline sal_uInt16 GetUInt16( const sal_uInt8* ptr, sal_uInt32 offset, int bigendian)
+{
+ sal_uInt16 t;
+ assert(ptr != 0);
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
+ } else {
+ t = (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+_inline sal_Int32 GetInt32( const sal_uInt8* ptr, sal_uInt32 offset, int bigendian)
+{
+ sal_Int32 t;
+ assert(ptr != 0);
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
+ (ptr+offset)[2] << 8 | (ptr+offset)[3];
+ } else {
+ t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
+ (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+_inline sal_uInt32 GetUInt32( const sal_uInt8* ptr, sal_uInt32 offset, int bigendian)
+{
+ sal_uInt32 t;
+ assert(ptr != 0);
+
+
+ if (bigendian) {
+ t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
+ (ptr+offset)[2] << 8 | (ptr+offset)[3];
+ } else {
+ t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 |
+ (ptr+offset)[1] << 8 | (ptr+offset)[0];
+ }
+
+ return t;
+}
+
+
+_inline void PutInt16(sal_Int16 val, sal_uInt8 *ptr, sal_uInt32 offset, int bigendian)
+{
+ assert(ptr != 0);
+
+ if (bigendian) {
+ ptr[offset] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset+1] = (sal_uInt8)(val & 0xFF);
+ } else {
+ ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset] = (sal_uInt8)(val & 0xFF);
+ }
+}
+
+_inline void PutUInt16(sal_uInt16 val, sal_uInt8 *ptr, sal_uInt32 offset, int bigendian)
+{
+ assert(ptr != 0);
+
+ if (bigendian) {
+ ptr[offset] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset+1] = (sal_uInt8)(val & 0xFF);
+ } else {
+ ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset] = (sal_uInt8)(val & 0xFF);
+ }
+}
+
+_inline void PutUInt32(sal_uInt32 val, sal_uInt8 *ptr, sal_uInt32 offset, int bigendian)
+{
+ assert(ptr != 0);
+
+ if (bigendian) {
+ ptr[offset] = (sal_uInt8)((val >> 24) & 0xFF);
+ ptr[offset+1] = (sal_uInt8)((val >> 16) & 0xFF);
+ ptr[offset+2] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset+3] = (sal_uInt8)(val & 0xFF);
+ } else {
+ ptr[offset+3] = (sal_uInt8)((val >> 24) & 0xFF);
+ ptr[offset+2] = (sal_uInt8)((val >> 16) & 0xFF);
+ ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset] = (sal_uInt8)(val & 0xFF);
+ }
+
+}
+
+
+_inline void PutInt32(sal_Int32 val, sal_uInt8 *ptr, sal_uInt32 offset, int bigendian)
+{
+ assert(ptr != 0);
+
+ if (bigendian) {
+ ptr[offset] = (sal_uInt8)((val >> 24) & 0xFF);
+ ptr[offset+1] = (sal_uInt8)((val >> 16) & 0xFF);
+ ptr[offset+2] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset+3] = (sal_uInt8)(val & 0xFF);
+ } else {
+ ptr[offset+3] = (sal_uInt8)((val >> 24) & 0xFF);
+ ptr[offset+2] = (sal_uInt8)((val >> 16) & 0xFF);
+ ptr[offset+1] = (sal_uInt8)((val >> 8) & 0xFF);
+ ptr[offset] = (sal_uInt8)(val & 0xFF);
+ }
+
+}
+
+static int TableEntryCompareF(const void *l, const void *r)
+{
+ return ((const TableEntry *) l)->tag - ((const TableEntry *) r)->tag;
+}
+
+static int NameRecordCompareF(const void *l, const void *r)
+{
+ NameRecord *ll = (NameRecord *) l;
+ NameRecord *rr = (NameRecord *) r;
+
+ if (ll->platformID != rr->platformID) {
+ return ll->platformID - rr->platformID;
+ } else if (ll->encodingID != rr->encodingID) {
+ return ll->encodingID - rr->encodingID;
+ } else if (ll->languageID != rr->languageID) {
+ return ll->languageID - rr->languageID;
+ } else if (ll->nameID != rr->nameID) {
+ return ll->nameID - rr->nameID;
+ }
+ return 0;
+}
+
+
+static sal_uInt32 CheckSum(sal_uInt32 *ptr, sal_uInt32 length)
+{
+ sal_uInt32 sum = 0;
+ sal_uInt32 *endptr = ptr + ((length + 3) & (sal_uInt32) ~3) / 4;
+
+ while (ptr < endptr) sum += *ptr++;
+
+ return sum;
+}
+
+_inline void *smalloc(sal_uInt32 size)
+{
+ void *res = malloc(size);
+ assert(res != 0);
+ return res;
+}
+
+_inline void *scalloc(sal_uInt32 n, sal_uInt32 size)
+{
+ void *res = calloc(n, size);
+ assert(res != 0);
+ return res;
+}
+
+/*
+ * Public functions
+ */
+
+void TrueTypeCreatorNewEmpty(sal_uInt32 tag, TrueTypeCreator **_this)
+{
+ TrueTypeCreator* ptr = (TrueTypeCreator*)smalloc(sizeof(TrueTypeCreator));
+
+ ptr->tables = listNewEmpty();
+ listSetElementDtor(ptr->tables, (list_destructor)TrueTypeTableDispose);
+
+ ptr->tag = tag;
+
+ *_this = ptr;
+}
+
+int AddTable(TrueTypeCreator *_this, TrueTypeTable *table)
+{
+ if (table != 0) {
+ listAppend(_this->tables, table);
+ }
+ return SF_OK;
+}
+
+void RemoveTable(TrueTypeCreator *_this, sal_uInt32 tag)
+{
+ int done = 0;
+
+ if (listCount(_this->tables)) {
+ listToFirst(_this->tables);
+ do {
+ if (((TrueTypeTable *) listCurrent(_this->tables))->tag == tag) {
+ listRemove(_this->tables);
+ } else {
+ if (listNext(_this->tables)) {
+ done = 1;
+ }
+ }
+ } while (!done);
+ }
+}
+
+static void ProcessTables(TrueTypeCreator *);
+
+int StreamToMemory(TrueTypeCreator *_this, sal_uInt8 **ptr, sal_uInt32 *length)
+{
+ sal_uInt16 numTables, searchRange=1, entrySelector=0, rangeShift;
+ sal_uInt32 s, offset, checkSumAdjustment = 0;
+ sal_uInt32 *p;
+ int i=0, n;
+ sal_uInt8 *head = NULL; /* saved pointer to the head table data for checkSumAdjustment calculation */
+
+ if ((n = listCount(_this->tables)) == 0) return SF_TTFORMAT;
+
+ ProcessTables(_this);
+
+ /* ProcessTables() adds 'loca' and 'hmtx' */
+
+ n = listCount(_this->tables);
+ numTables = (sal_uInt16) n;
+
+
+ TableEntry* te = (TableEntry*)scalloc(n, sizeof(TableEntry));
+
+ listToFirst(_this->tables);
+ for (i = 0; i < n; i++) {
+ GetRawData((TrueTypeTable *) listCurrent(_this->tables), &te[i].data, &te[i].length, &te[i].tag);
+ listNext(_this->tables);
+ }
+
+ qsort(te, n, sizeof(TableEntry), TableEntryCompareF);
+
+ do {
+ searchRange *= 2;
+ entrySelector++;
+ } while (searchRange <= numTables);
+
+ searchRange *= 8;
+ entrySelector--;
+ rangeShift = numTables * 16 - searchRange;
+
+ s = offset = 12 + 16 * n;
+
+ for (i = 0; i < n; i++) {
+ s += (te[i].length + 3) & (sal_uInt32) ~3;
+ /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */
+ }
+
+ sal_uInt8* ttf = (sal_uInt8*)smalloc(s);
+
+ /* Offset Table */
+ PutUInt32(_this->tag, ttf, 0, 1);
+ PutUInt16(numTables, ttf, 4, 1);
+ PutUInt16(searchRange, ttf, 6, 1);
+ PutUInt16(entrySelector, ttf, 8, 1);
+ PutUInt16(rangeShift, ttf, 10, 1);
+
+ /* Table Directory */
+ for (i = 0; i < n; i++) {
+ PutUInt32(te[i].tag, ttf + 12, 16 * i, 1);
+ PutUInt32(CheckSum((sal_uInt32 *) te[i].data, te[i].length), ttf + 12, 16 * i + 4, 1);
+ PutUInt32(offset, ttf + 12, 16 * i + 8, 1);
+ PutUInt32(te[i].length, ttf + 12, 16 * i + 12, 1);
+
+ if (te[i].tag == T_head) {
+ head = ttf + offset;
+ }
+
+ memcpy(ttf+offset, te[i].data, (te[i].length + 3) & (sal_uInt32) ~3 );
+ offset += (te[i].length + 3) & (sal_uInt32) ~3;
+ /* if ((te[i].length & 3) != 0) offset += (4 - (te[i].length & 3)) & 3; */
+ }
+
+ free(te);
+
+ p = (sal_uInt32 *) ttf;
+ for (i = 0; i < (int)s / 4; i++) checkSumAdjustment += p[i];
+ PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8, 1);
+
+ *ptr = ttf;
+ *length = s;
+
+ return SF_OK;
+}
+
+int StreamToFile(TrueTypeCreator *_this, const char* fname)
+{
+ sal_uInt8 *ptr;
+ sal_uInt32 length;
+ int r;
+ FILE* fd;
+
+ if ((r = StreamToMemory(_this, &ptr, &length)) != SF_OK) return r;
+ if (!fname) return SF_BADFILE;
+ if ((fd = fopen(fname, "wb")) == NULL) return SF_BADFILE;
+
+ if (fwrite(ptr, 1, length, fd) != length) {
+ r = SF_FILEIO;
+ } else {
+ r = SF_OK;
+ }
+
+ fclose(fd);
+ free(ptr);
+ return r;
+}
+
+
+
+/*
+ * TrueTypeTable private methods
+ */
+
+#define TABLESIZE_head 54
+#define TABLESIZE_hhea 36
+#define TABLESIZE_maxp 32
+
+
+
+/* Table data points to
+ * --------------------------------------------
+ * generic tdata_generic struct
+ * 'head' TABLESIZE_head bytes of memory
+ * 'hhea' TABLESIZE_hhea bytes of memory
+ * 'loca' tdata_loca struct
+ * 'maxp' TABLESIZE_maxp bytes of memory
+ * 'glyf' list of GlyphData structs (defined in sft.h)
+ * 'name' list of NameRecord structs (defined in sft.h)
+ * 'post' tdata_post struct
+ *
+ */
+
+
+#define CMAP_SUBTABLE_INIT 10
+#define CMAP_SUBTABLE_INCR 10
+#define CMAP_PAIR_INIT 500
+#define CMAP_PAIR_INCR 500
+
+typedef struct {
+ sal_uInt32 id; /* subtable ID (platform/encoding ID) */
+ sal_uInt32 n; /* number of used translation pairs */
+ sal_uInt32 m; /* number of allocated translation pairs */
+ sal_uInt32 *xc; /* character array */
+ sal_uInt32 *xg; /* glyph array */
+} CmapSubTable;
+
+typedef struct {
+ sal_uInt32 n; /* number of used CMAP sub-tables */
+ sal_uInt32 m; /* number of allocated CMAP sub-tables */
+ CmapSubTable *s; /* sotred array of sub-tables */
+} table_cmap;
+
+typedef struct {
+ sal_uInt32 tag;
+ sal_uInt32 nbytes;
+ sal_uInt8 *ptr;
+} tdata_generic;
+
+typedef struct {
+ sal_uInt32 nbytes; /* number of bytes in loca table */
+ sal_uInt8 *ptr; /* pointer to the data */
+} tdata_loca;
+
+typedef struct {
+ sal_uInt32 format;
+ sal_uInt32 italicAngle;
+ sal_Int16 underlinePosition;
+ sal_Int16 underlineThickness;
+ sal_uInt32 isFixedPitch;
+ void *ptr; /* format-specific pointer */
+} tdata_post;
+
+
+/* allocate memory for a TT table */
+static sal_uInt8 *ttmalloc(sal_uInt32 nbytes)
+{
+ sal_uInt32 n;
+
+ n = (nbytes + 3) & (sal_uInt32) ~3;
+ sal_uInt8* res = (sal_uInt8*)malloc(n);
+ assert(res != 0);
+ memset(res, 0, n);
+
+ return res;
+}
+
+static void FreeGlyphData(void *ptr)
+{
+ GlyphData *p = (GlyphData *) ptr;
+ if (p->ptr) free(p->ptr);
+ free(p);
+}
+
+static void TrueTypeTableDispose_generic(TrueTypeTable *_this)
+{
+ if (_this) {
+ if (_this->data) {
+ tdata_generic *pdata = (tdata_generic *) _this->data;
+ if (pdata->nbytes) free(pdata->ptr);
+ free(_this->data);
+ }
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_head(TrueTypeTable *_this)
+{
+ if (_this) {
+ if (_this->data) free(_this->data);
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_hhea(TrueTypeTable *_this)
+{
+ if (_this) {
+ if (_this->data) free(_this->data);
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_loca(TrueTypeTable *_this)
+{
+ if (_this) {
+ if (_this->data) {
+ tdata_loca *p = (tdata_loca *) _this->data;
+ if (p->ptr) free(p->ptr);
+ free(_this->data);
+ }
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_maxp(TrueTypeTable *_this)
+{
+ if (_this) {
+ if (_this->data) free(_this->data);
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_glyf(TrueTypeTable *_this)
+{
+ if (_this) {
+ if (_this->data) listDispose((list) _this->data);
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_cmap(TrueTypeTable *_this)
+{
+ table_cmap *t;
+ CmapSubTable *s;
+ sal_uInt32 i;
+
+ if (_this) {
+ t = (table_cmap *) _this->data;
+ if (t) {
+ s = t->s;
+ if (s) {
+ for (i = 0; i < t->m; i++) {
+ if (s[i].xc) free(s[i].xc);
+ if (s[i].xg) free(s[i].xg);
+ }
+ free(s);
+ }
+ free(t);
+ }
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_name(TrueTypeTable *_this)
+{
+ if (_this) {
+ if (_this->data) listDispose((list) _this->data);
+ free(_this);
+ }
+}
+
+static void TrueTypeTableDispose_post(TrueTypeTable *_this)
+{
+ if (_this) {
+ tdata_post *p = (tdata_post *) _this->data;
+ if (p) {
+ if (p->format == 0x00030000) {
+ /* do nothing */
+ } else {
+ fprintf(stderr, "Unsupported format of a 'post' table: %08X.\n", (int)p->format);
+ }
+ free(p);
+ }
+ free(_this);
+ }
+}
+
+/* destructor vtable */
+
+static struct {
+ sal_uInt32 tag;
+ void (*f)(TrueTypeTable *);
+} vtable1[] =
+{
+ {0, TrueTypeTableDispose_generic},
+ {T_head, TrueTypeTableDispose_head},
+ {T_hhea, TrueTypeTableDispose_hhea},
+ {T_loca, TrueTypeTableDispose_loca},
+ {T_maxp, TrueTypeTableDispose_maxp},
+ {T_glyf, TrueTypeTableDispose_glyf},
+ {T_cmap, TrueTypeTableDispose_cmap},
+ {T_name, TrueTypeTableDispose_name},
+ {T_post, TrueTypeTableDispose_post}
+
+};
+
+static int GetRawData_generic(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ assert(_this != 0);
+ assert(_this->data != 0);
+
+ *ptr = ((tdata_generic *) _this->data)->ptr;
+ *len = ((tdata_generic *) _this->data)->nbytes;
+ *tag = ((tdata_generic *) _this->data)->tag;
+
+ return TTCR_OK;
+}
+
+
+static int GetRawData_head(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ *len = TABLESIZE_head;
+ *ptr = (sal_uInt8 *) _this->data;
+ *tag = T_head;
+
+ return TTCR_OK;
+}
+
+static int GetRawData_hhea(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ *len = TABLESIZE_hhea;
+ *ptr = (sal_uInt8 *) _this->data;
+ *tag = T_hhea;
+
+ return TTCR_OK;
+}
+
+static int GetRawData_loca(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ tdata_loca *p;
+
+ assert(_this->data != 0);
+
+ p = (tdata_loca *) _this->data;
+
+ if (p->nbytes == 0) return TTCR_ZEROGLYPHS;
+
+ *ptr = p->ptr;
+ *len = p->nbytes;
+ *tag = T_loca;
+
+ return TTCR_OK;
+}
+
+static int GetRawData_maxp(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ *len = TABLESIZE_maxp;
+ *ptr = (sal_uInt8 *) _this->data;
+ *tag = T_maxp;
+
+ return TTCR_OK;
+}
+
+static int GetRawData_glyf(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ sal_uInt32 n, nbytes = 0;
+ list l = (list) _this->data;
+ /* sal_uInt16 curID = 0; */ /* to check if glyph IDs are sequential and start from zero */
+ sal_uInt8 *p;
+
+ *ptr = 0;
+ *len = 0;
+ *tag = 0;
+
+ if (listCount(l) == 0) return TTCR_ZEROGLYPHS;
+
+ listToFirst(l);
+ do {
+ /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */
+ nbytes += ((GlyphData *) listCurrent(l))->nbytes;
+ } while (listNext(l));
+
+ p = _this->rawdata = ttmalloc(nbytes);
+
+ listToFirst(l);
+ do {
+ n = ((GlyphData *) listCurrent(l))->nbytes;
+ if (n != 0) {
+ memcpy(p, ((GlyphData *) listCurrent(l))->ptr, n);
+ p += n;
+ }
+ } while (listNext(l));
+
+ *len = nbytes;
+ *ptr = _this->rawdata;
+ *tag = T_glyf;
+
+ return TTCR_OK;
+}
+
+/* cmap packers */
+static sal_uInt8 *PackCmapType0(CmapSubTable *s, sal_uInt32 *length)
+{
+ sal_uInt8* ptr = (sal_uInt8*)smalloc(262);
+ sal_uInt8 *p = ptr + 6;
+ sal_uInt32 i, j;
+ sal_uInt16 g;
+
+ PutUInt16(0, ptr, 0, 1);
+ PutUInt16(262, ptr, 2, 1);
+ PutUInt16(0, ptr, 4, 1);
+
+ for (i = 0; i < 256; i++) {
+ g = 0;
+ for (j = 0; j < s->n; j++) {
+ if (s->xc[j] == i) {
+ g = (sal_uInt16) s->xg[j];
+ }
+ }
+ p[i] = (sal_uInt8) g;
+ }
+ *length = 262;
+ return ptr;
+}
+
+static sal_uInt8 *PackCmapType6(CmapSubTable *s, sal_uInt32 *length)
+{
+ sal_uInt8* ptr = (sal_uInt8*)smalloc(s->n*2 + 10);
+ sal_uInt8 *p = ptr + 10;
+ sal_uInt32 i, j;
+ sal_uInt16 g;
+
+ PutUInt16(6, ptr, 0, 1);
+ PutUInt16((sal_uInt16)(s->n*2+10), ptr, 2, 1);
+ PutUInt16(0, ptr, 4, 1);
+ PutUInt16(0, ptr, 6, 1);
+ PutUInt16((sal_uInt16)(s->n), ptr, 8, 1 );
+
+ for (i = 0; i < s->n; i++) {
+ g = 0;
+ for (j = 0; j < s->n; j++) {
+ if (s->xc[j] == i) {
+ g = (sal_uInt16) s->xg[j];
+ }
+ }
+ PutUInt16( g, p, 2*i, 1 );
+ }
+ *length = s->n*2+10;
+ return ptr;
+}
+
+
+
+/* XXX it only handles Format 0 encoding tables */
+static sal_uInt8 *PackCmap(CmapSubTable *s, sal_uInt32 *length)
+{
+ if( s->xg[s->n-1] > 0xff )
+ return PackCmapType6(s, length);
+ else
+ return PackCmapType0(s, length);
+}
+
+static int GetRawData_cmap(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ table_cmap *t;
+ sal_uInt32 i;
+ sal_uInt32 tlen = 0;
+ sal_uInt32 l;
+ sal_uInt32 cmapsize;
+ sal_uInt8 *cmap;
+ sal_uInt32 coffset;
+
+ assert(_this != 0);
+ t = (table_cmap *) _this->data;
+ assert(t != 0);
+ assert(t->n != 0);
+
+ sal_uInt8** subtables = (sal_uInt8**)scalloc(t->n, sizeof(sal_uInt8 *));
+ sal_uInt32* sizes = (sal_uInt32*)scalloc(t->n, sizeof(sal_uInt32));
+
+ for (i = 0; i < t->n; i++) {
+ subtables[i] = PackCmap(t->s+i, &l);
+ sizes[i] = l;
+ tlen += l;
+ }
+
+ cmapsize = tlen + 4 + 8 * t->n;
+ _this->rawdata = cmap = ttmalloc(cmapsize);
+
+ PutUInt16(0, cmap, 0, 1);
+ PutUInt16((sal_uInt16)t->n, cmap, 2, 1);
+ coffset = 4 + t->n * 8;
+
+ for (i = 0; i < t->n; i++) {
+ PutUInt16((sal_uInt16)(t->s[i].id >> 16), cmap + 4, i * 8, 1);
+ PutUInt16((sal_uInt16)(t->s[i].id & 0xFF), cmap + 4, 2 + i * 8, 1);
+ PutUInt32(coffset, cmap + 4, 4 + i * 8, 1);
+ memcpy(cmap + coffset, subtables[i], sizes[i]);
+ free(subtables[i]);
+ coffset += sizes[i];
+ }
+
+ free(subtables);
+ free(sizes);
+
+ *ptr = cmap;
+ *len = cmapsize;
+ *tag = T_cmap;
+
+ return TTCR_OK;
+}
+
+
+static int GetRawData_name(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ list l;
+ sal_Int16 i=0, n; /* number of Name Records */
+ int stringLen = 0;
+ sal_uInt8 *p1, *p2;
+
+ *ptr = 0;
+ *len = 0;
+ *tag = 0;
+
+ assert(_this != 0);
+ l = (list) _this->data;
+ assert(l != 0);
+
+ if ((n = (sal_Int16)listCount(l)) == 0) return TTCR_NONAMES;
+
+ NameRecord* nr = (NameRecord*)scalloc(n, sizeof(NameRecord));
+
+ listToFirst(l);
+
+ do {
+ memcpy(nr+i, listCurrent(l), sizeof(NameRecord));
+ stringLen += nr[i].slen;
+ i++;
+ } while (listNext(l));
+
+ if (stringLen > 65535) {
+ free(nr);
+ return TTCR_NAMETOOLONG;
+ }
+
+ qsort(nr, n, sizeof(NameRecord), NameRecordCompareF);
+
+ int nameLen = stringLen + 12 * n + 6;
+ sal_uInt8* name = (sal_uInt8*)ttmalloc(nameLen);
+
+ PutUInt16(0, name, 0, 1);
+ PutUInt16(n, name, 2, 1);
+ PutUInt16((sal_uInt16)(6 + 12 * n), name, 4, 1);
+
+ p1 = name + 6;
+ p2 = p1 + 12 * n;
+
+ for (i = 0; i < n; i++) {
+ PutUInt16(nr[i].platformID, p1, 0, 1);
+ PutUInt16(nr[i].encodingID, p1, 2, 1);
+ PutUInt16(nr[i].languageID, p1, 4, 1);
+ PutUInt16(nr[i].nameID, p1, 6, 1);
+ PutUInt16(nr[i].slen, p1, 8, 1);
+ PutUInt16((sal_uInt16)(p2 - (name + 6 + 12 * n)), p1, 10, 1);
+ memcpy(p2, nr[i].sptr, nr[i].slen);
+ /* {int j; for(j=0; j<nr[i].slen; j++) printf("%c", nr[i].sptr[j]); printf("\n"); }; */
+ p2 += nr[i].slen;
+ p1 += 12;
+ }
+
+ free(nr);
+ _this->rawdata = name;
+
+ *ptr = name;
+ *len = (sal_uInt16)nameLen;
+ *tag = T_name;
+
+ /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */
+
+ return TTCR_OK;
+}
+
+static int GetRawData_post(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ tdata_post *p = (tdata_post *) _this->data;
+ sal_uInt8 *post = 0;
+ sal_uInt32 postLen = 0;
+ int ret;
+
+ if (_this->rawdata) free(_this->rawdata);
+
+ if (p->format == 0x00030000) {
+ postLen = 32;
+ post = ttmalloc(postLen);
+ PutUInt32(0x00030000, post, 0, 1);
+ PutUInt32(p->italicAngle, post, 4, 1);
+ PutUInt16(p->underlinePosition, post, 8, 1);
+ PutUInt16(p->underlineThickness, post, 10, 1);
+ PutUInt16((sal_uInt16)p->isFixedPitch, post, 12, 1);
+ ret = TTCR_OK;
+ } else {
+ fprintf(stderr, "Unrecognized format of a post table: %08X.\n", (int)p->format);
+ ret = TTCR_POSTFORMAT;
+ }
+
+ *ptr = _this->rawdata = post;
+ *len = postLen;
+ *tag = T_post;
+
+ return ret;
+}
+
+
+
+
+
+static struct {
+ sal_uInt32 tag;
+ int (*f)(TrueTypeTable *, sal_uInt8 **, sal_uInt32 *, sal_uInt32 *);
+} vtable2[] =
+{
+ {0, GetRawData_generic},
+ {T_head, GetRawData_head},
+ {T_hhea, GetRawData_hhea},
+ {T_loca, GetRawData_loca},
+ {T_maxp, GetRawData_maxp},
+ {T_glyf, GetRawData_glyf},
+ {T_cmap, GetRawData_cmap},
+ {T_name, GetRawData_name},
+ {T_post, GetRawData_post}
+
+
+};
+
+/*
+ * TrueTypeTable public methods
+ */
+
+/* Note: Type42 fonts only need these tables:
+ * head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
+ *
+ * Microsoft required tables
+ * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2
+ *
+ * Apple required tables
+ * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post
+ *
+ */
+
+TrueTypeTable *TrueTypeTableNew(sal_uInt32 tag,
+ sal_uInt32 nbytes,
+ const sal_uInt8* ptr)
+{
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ tdata_generic* pdata = (tdata_generic*)smalloc(sizeof(tdata_generic));
+ pdata->nbytes = nbytes;
+ pdata->tag = tag;
+ if (nbytes) {
+ pdata->ptr = ttmalloc(nbytes);
+ memcpy(pdata->ptr, ptr, nbytes);
+ } else {
+ pdata->ptr = 0;
+ }
+
+ table->tag = 0;
+ table->data = pdata;
+ table->rawdata = 0;
+
+ return table;
+}
+
+TrueTypeTable *TrueTypeTableNew_head(sal_uInt32 fontRevision,
+ sal_uInt16 flags,
+ sal_uInt16 unitsPerEm,
+ const sal_uInt8* created,
+ sal_uInt16 macStyle,
+ sal_uInt16 lowestRecPPEM,
+ sal_Int16 fontDirectionHint)
+{
+ assert(created != 0);
+
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ sal_uInt8* ptr = (sal_uInt8*)ttmalloc(TABLESIZE_head);
+
+
+ PutUInt32(0x00010000, ptr, 0, 1); /* version */
+ PutUInt32(fontRevision, ptr, 4, 1);
+ PutUInt32(0x5F0F3CF5, ptr, 12, 1); /* magic number */
+ PutUInt16(flags, ptr, 16, 1);
+ PutUInt16(unitsPerEm, ptr, 18, 1);
+ memcpy(ptr+20, created, 8); /* Created Long Date */
+ memset(ptr+28, 0, 8); /* Modified Long Date */
+ PutUInt16(macStyle, ptr, 44, 1);
+ PutUInt16(lowestRecPPEM, ptr, 46, 1);
+ PutUInt16(fontDirectionHint, ptr, 48, 1);
+ PutUInt16(0, ptr, 52, 1); /* glyph data format: 0 */
+
+ table->data = (void *) ptr;
+ table->tag = T_head;
+ table->rawdata = 0;
+
+ return table;
+}
+
+TrueTypeTable *TrueTypeTableNew_hhea(sal_Int16 ascender,
+ sal_Int16 descender,
+ sal_Int16 linegap,
+ sal_Int16 caretSlopeRise,
+ sal_Int16 caretSlopeRun)
+{
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ sal_uInt8* ptr = (sal_uInt8*)ttmalloc(TABLESIZE_hhea);
+
+ PutUInt32(0x00010000, ptr, 0, 1); /* version */
+ PutUInt16(ascender, ptr, 4, 1);
+ PutUInt16(descender, ptr, 6, 1);
+ PutUInt16(linegap, ptr, 8, 1);
+ PutUInt16(caretSlopeRise, ptr, 18, 1);
+ PutUInt16(caretSlopeRun, ptr, 20, 1);
+ PutUInt16(0, ptr, 22, 1); /* reserved 1 */
+ PutUInt16(0, ptr, 24, 1); /* reserved 2 */
+ PutUInt16(0, ptr, 26, 1); /* reserved 3 */
+ PutUInt16(0, ptr, 28, 1); /* reserved 4 */
+ PutUInt16(0, ptr, 30, 1); /* reserved 5 */
+ PutUInt16(0, ptr, 32, 1); /* metricDataFormat */
+
+ table->data = (void *) ptr;
+ table->tag = T_hhea;
+ table->rawdata = 0;
+
+ return table;
+}
+
+TrueTypeTable *TrueTypeTableNew_loca(void)
+{
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ table->data = smalloc(sizeof(tdata_loca));
+
+ ((tdata_loca *)table->data)->nbytes = 0;
+ ((tdata_loca *)table->data)->ptr = 0;
+
+ table->tag = T_loca;
+ table->rawdata = 0;
+
+ return table;
+}
+
+TrueTypeTable *TrueTypeTableNew_maxp( const sal_uInt8* maxp, int size)
+{
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ table->data = ttmalloc(TABLESIZE_maxp);
+
+ if (maxp && size == TABLESIZE_maxp) {
+ memcpy(table->data, maxp, TABLESIZE_maxp);
+ }
+
+ table->tag = T_maxp;
+ table->rawdata = 0;
+
+ return table;
+}
+
+TrueTypeTable *TrueTypeTableNew_glyf(void)
+{
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ list l = listNewEmpty();
+
+ assert(l != 0);
+
+ listSetElementDtor(l, (list_destructor)FreeGlyphData);
+
+ table->data = l;
+ table->rawdata = 0;
+ table->tag = T_glyf;
+
+ return table;
+}
+
+TrueTypeTable *TrueTypeTableNew_cmap(void)
+{
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ table_cmap* cmap = (table_cmap*)smalloc(sizeof(table_cmap));
+
+ cmap->n = 0;
+ cmap->m = CMAP_SUBTABLE_INIT;
+ cmap->s = (CmapSubTable *) scalloc(CMAP_SUBTABLE_INIT, sizeof(CmapSubTable));
+ memset(cmap->s, 0, sizeof(CmapSubTable) * CMAP_SUBTABLE_INIT);
+
+ table->data = (table_cmap *) cmap;
+
+ table->rawdata = 0;
+ table->tag = T_cmap;
+
+ return table;
+}
+
+static void DisposeNameRecord(void *ptr)
+{
+ if (ptr != 0) {
+ NameRecord *nr = (NameRecord *) ptr;
+ if (nr->sptr) free(nr->sptr);
+ free(ptr);
+ }
+}
+
+static NameRecord* NameRecordNewCopy(NameRecord *nr)
+{
+ NameRecord* p = (NameRecord*)smalloc(sizeof(NameRecord));
+
+ memcpy(p, nr, sizeof(NameRecord));
+
+ if (p->slen) {
+ p->sptr = (sal_uInt8*)smalloc(p->slen);
+ memcpy(p->sptr, nr->sptr, p->slen);
+ }
+
+ return p;
+}
+
+TrueTypeTable *TrueTypeTableNew_name(int n, NameRecord *nr)
+{
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ list l = listNewEmpty();
+
+ assert(l != 0);
+
+ listSetElementDtor(l, (list_destructor)DisposeNameRecord);
+
+ if (n != 0) {
+ int i;
+ for (i = 0; i < n; i++) {
+ listAppend(l, NameRecordNewCopy(nr+i));
+ }
+ }
+
+ table->data = l;
+ table->rawdata = 0;
+ table->tag = T_name;
+
+ return table;
+}
+
+TrueTypeTable *TrueTypeTableNew_post(sal_uInt32 format,
+ sal_uInt32 italicAngle,
+ sal_Int16 underlinePosition,
+ sal_Int16 underlineThickness,
+ sal_uInt32 isFixedPitch)
+{
+ assert(format == 0x00030000); /* Only format 3.0 is supported at this time */
+ TrueTypeTable* table = (TrueTypeTable*)smalloc(sizeof(TrueTypeTable));
+ tdata_post* post = (tdata_post*)smalloc(sizeof(tdata_post));
+
+ post->format = format;
+ post->italicAngle = italicAngle;
+ post->underlinePosition = underlinePosition;
+ post->underlineThickness = underlineThickness;
+ post->isFixedPitch = isFixedPitch;
+ post->ptr = 0;
+
+ table->data = post;
+ table->rawdata = 0;
+ table->tag = T_post;
+
+ return table;
+}
+
+int GetRawData(TrueTypeTable *_this, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag)
+{
+ /* XXX do a binary search */
+ unsigned int i;
+
+ assert(_this != 0);
+ assert(ptr != 0);
+ assert(len != 0);
+ assert(tag != 0);
+
+ *ptr = 0; *len = 0; *tag = 0;
+
+ if (_this->rawdata) {
+ free(_this->rawdata);
+ _this->rawdata = 0;
+ }
+
+ for(i=0; i < sizeof(vtable2)/sizeof(*vtable2); i++) {
+ if (_this->tag == vtable2[i].tag) {
+ return vtable2[i].f(_this, ptr, len, tag);
+ }
+ }
+
+ assert(!"Unknwon TrueType table.\n");
+ return TTCR_UNKNOWN;
+}
+
+void cmapAdd(TrueTypeTable *table, sal_uInt32 id, sal_uInt32 c, sal_uInt32 g)
+{
+ sal_uInt32 i, found;
+ table_cmap *t;
+ CmapSubTable *s;
+
+ assert(table != 0);
+ assert(table->tag == T_cmap);
+ t = (table_cmap *) table->data; assert(t != 0);
+ s = t->s; assert(s != 0);
+
+ found = 0;
+
+ for (i = 0; i < t->n; i++) {
+ if (s[i].id == id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (t->n == t->m) {
+ CmapSubTable* tmp = (CmapSubTable*)scalloc(t->m + CMAP_SUBTABLE_INCR, sizeof(CmapSubTable));
+ memset(tmp, 0, t->m + CMAP_SUBTABLE_INCR * sizeof(CmapSubTable));
+ memcpy(tmp, s, sizeof(CmapSubTable) * t->m);
+ t->m += CMAP_SUBTABLE_INCR;
+ free(s);
+ s = tmp;
+ t->s = s;
+ }
+
+ for (i = 0; i < t->n; i++) {
+ if (s[i].id > id) break;
+ }
+
+ if (i < t->n) {
+ memmove(s+i+1, s+i, t->n-i);
+ }
+
+ t->n++;
+
+ s[i].id = id;
+ s[i].n = 0;
+ s[i].m = CMAP_PAIR_INIT;
+ s[i].xc = (sal_uInt32*)scalloc(CMAP_PAIR_INIT, sizeof(sal_uInt32));
+ s[i].xg = (sal_uInt32*)scalloc(CMAP_PAIR_INIT, sizeof(sal_uInt32));
+ }
+
+ if (s[i].n == s[i].m) {
+ sal_uInt32* tmp1 = (sal_uInt32*)scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(sal_uInt32));
+ sal_uInt32* tmp2 = (sal_uInt32*)scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(sal_uInt32));
+ assert(tmp1 != 0);
+ assert(tmp2 != 0);
+ memcpy(tmp1, s[i].xc, sizeof(sal_uInt32) * s[i].m);
+ memcpy(tmp2, s[i].xg, sizeof(sal_uInt32) * s[i].m);
+ s[i].m += CMAP_PAIR_INCR;
+ free(s[i].xc);
+ free(s[i].xg);
+ s[i].xc = tmp1;
+ s[i].xg = tmp2;
+ }
+
+ s[i].xc[s[i].n] = c;
+ s[i].xg[s[i].n] = g;
+ s[i].n++;
+}
+
+sal_uInt32 glyfAdd(TrueTypeTable *table, GlyphData *glyphdata, TrueTypeFont *fnt)
+{
+ list l;
+ sal_uInt32 currentID;
+ int ret, n, ncomponents;
+ GlyphData *gd;
+
+ assert(table != 0);
+ assert(table->tag == T_glyf);
+
+ if (!glyphdata) return (sal_uInt32)~0;
+
+ std::vector< sal_uInt32 > glyphlist;
+
+ ncomponents = GetTTGlyphComponents(fnt, glyphdata->glyphID, glyphlist);
+
+ l = (list) table->data;
+ if (listCount(l) > 0) {
+ listToLast(l);
+ ret = n = ((GlyphData *) listCurrent(l))->newID + 1;
+ } else {
+ ret = n = 0;
+ }
+ glyphdata->newID = n++;
+ listAppend(l, glyphdata);
+
+ if (ncomponents > 1 && glyphlist.size() > 1 )
+ {
+ std::vector< sal_uInt32 >::const_iterator it = glyphlist.begin();
+ ++it;
+ /* glyphData->glyphID is always the first glyph on the list */
+ do
+ {
+ int found = 0;
+ currentID = *it;
+ /* XXX expensive! should be rewritten with sorted arrays! */
+ listToFirst(l);
+ do {
+ if (((GlyphData *) listCurrent(l))->glyphID == currentID) {
+ found = 1;
+ break;
+ }
+ } while (listNext(l));
+
+ if (!found) {
+ gd = GetTTRawGlyphData(fnt, currentID);
+ gd->newID = n++;
+ listAppend(l, gd);
+ }
+ } while( ++it != glyphlist.end() );
+ }
+
+ return ret;
+}
+
+sal_uInt32 glyfCount(const TrueTypeTable *table)
+{
+ assert(table != 0);
+ assert(table->tag == T_glyf);
+ return listCount((list) table->data);
+}
+
+
+void nameAdd(TrueTypeTable *table, NameRecord *nr)
+{
+ list l;
+
+ assert(table != 0);
+ assert(table->tag == T_name);
+
+ l = (list) table->data;
+
+ listAppend(l, NameRecordNewCopy(nr));
+}
+
+static TrueTypeTable *FindTable(TrueTypeCreator *tt, sal_uInt32 tag)
+{
+ if (listIsEmpty(tt->tables)) return 0;
+
+ listToFirst(tt->tables);
+
+ do {
+ if (((TrueTypeTable *) listCurrent(tt->tables))->tag == tag) {
+ return (TrueTypeTable*)listCurrent(tt->tables);
+ }
+ } while (listNext(tt->tables));
+
+ return 0;
+}
+
+/* This function processes all the tables and synchronizes them before creating
+ * the output TrueType stream.
+ *
+ * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' ***
+ *
+ * It does:
+ *
+ * - Re-numbers glyph IDs and creates 'glyf', 'loca', and 'hmtx' tables.
+ * - Calculates xMin, yMin, xMax, and yMax and stores values in 'head' table.
+ * - Stores indexToLocFormat in 'head'
+ * - updates 'maxp' table
+ * - Calculates advanceWidthMax, minLSB, minRSB, xMaxExtent and numberOfHMetrics
+ * in 'hhea' table
+ *
+ */
+static void ProcessTables(TrueTypeCreator *tt)
+{
+ TrueTypeTable *glyf, *loca, *head, *maxp, *hhea;
+ list glyphlist;
+ sal_uInt32 nGlyphs, locaLen = 0, glyfLen = 0;
+ sal_Int16 xMin = 0, yMin = 0, xMax = 0, yMax = 0;
+ sal_uInt32 i = 0;
+ sal_Int16 indexToLocFormat;
+ sal_uInt8 *hmtxPtr, *hheaPtr;
+ sal_uInt32 hmtxSize;
+ sal_uInt8 *p1, *p2;
+ sal_uInt16 maxPoints = 0, maxContours = 0, maxCompositePoints = 0, maxCompositeContours = 0;
+ int nlsb = 0;
+ sal_uInt32 *gid; /* array of old glyphIDs */
+
+ glyf = FindTable(tt, T_glyf);
+ glyphlist = (list) glyf->data;
+ nGlyphs = listCount(glyphlist);
+ assert(nGlyphs != 0);
+ gid = (sal_uInt32*)scalloc(nGlyphs, sizeof(sal_uInt32));
+
+ RemoveTable(tt, T_loca);
+ RemoveTable(tt, T_hmtx);
+
+ /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */
+
+ listToFirst(glyphlist);
+ do {
+ GlyphData *gd = (GlyphData *) listCurrent(glyphlist);
+ sal_Int16 z;
+ glyfLen += gd->nbytes;
+ /* XXX if (gd->nbytes & 1) glyfLen++; */
+
+
+ assert(gd->newID == i);
+ gid[i++] = gd->glyphID;
+ /* gd->glyphID = i++; */
+
+ /* printf("IDs: %d %d.\n", gd->glyphID, gd->newID); */
+
+ if (gd->nbytes != 0) {
+ z = GetInt16(gd->ptr, 2, 1);
+ if (z < xMin) xMin = z;
+
+ z = GetInt16(gd->ptr, 4, 1);
+ if (z < yMin) yMin = z;
+
+ z = GetInt16(gd->ptr, 6, 1);
+ if (z > xMax) xMax = z;
+
+ z = GetInt16(gd->ptr, 8, 1);
+ if (z > yMax) yMax = z;
+ }
+
+ if (gd->compflag == 0) { /* non-composite glyph */
+ if (gd->npoints > maxPoints) maxPoints = gd->npoints;
+ if (gd->ncontours > maxContours) maxContours = gd->ncontours;
+ } else { /* composite glyph */
+ if (gd->npoints > maxCompositePoints) maxCompositePoints = gd->npoints;
+ if (gd->ncontours > maxCompositeContours) maxCompositeContours = gd->ncontours;
+ }
+
+ } while (listNext(glyphlist));
+
+ indexToLocFormat = (glyfLen / 2 > 0xFFFF) ? 1 : 0;
+ locaLen = indexToLocFormat ? (nGlyphs + 1) << 2 : (nGlyphs + 1) << 1;
+
+ sal_uInt8* glyfPtr = ttmalloc(glyfLen);
+ sal_uInt8* locaPtr = ttmalloc(locaLen);
+ TTSimpleGlyphMetrics* met = (TTSimpleGlyphMetrics*)scalloc(nGlyphs, sizeof(TTSimpleGlyphMetrics));
+ i = 0;
+
+ listToFirst(glyphlist);
+ p1 = glyfPtr;
+ p2 = locaPtr;
+ do {
+ GlyphData *gd = (GlyphData *) listCurrent(glyphlist);
+
+ if (gd->compflag) { /* re-number all components */
+ sal_uInt16 flags, index;
+ sal_uInt8 *ptr = gd->ptr + 10;
+ do {
+ sal_uInt32 j;
+ flags = GetUInt16(ptr, 0, 1);
+ index = GetUInt16(ptr, 2, 1);
+ /* XXX use the sorted array of old to new glyphID mapping and do a binary search */
+ for (j = 0; j < nGlyphs; j++) {
+ if (gid[j] == index) {
+ break;
+ }
+ }
+ /* printf("X: %d -> %d.\n", index, j); */
+
+ PutUInt16((sal_uInt16) j, ptr, 2, 1);
+
+ ptr += 4;
+
+ if (flags & ARG_1_AND_2_ARE_WORDS) {
+ ptr += 4;
+ } else {
+ ptr += 2;
+ }
+
+ if (flags & WE_HAVE_A_SCALE) {
+ ptr += 2;
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+ ptr += 4;
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+ ptr += 8;
+ }
+ } while (flags & MORE_COMPONENTS);
+ }
+
+ if (gd->nbytes != 0) {
+ memcpy(p1, gd->ptr, gd->nbytes);
+ }
+ if (indexToLocFormat == 1) {
+ PutUInt32(p1 - glyfPtr, p2, 0, 1);
+ p2 += 4;
+ } else {
+ PutUInt16((sal_uInt16)((p1 - glyfPtr) >> 1), p2, 0, 1);
+ p2 += 2;
+ }
+ p1 += gd->nbytes;
+
+ /* fill the array of metrics */
+ met[i].adv = gd->aw;
+ met[i].sb = gd->lsb;
+ i++;
+ } while (listNext(glyphlist));
+
+ free(gid);
+
+ if (indexToLocFormat == 1) {
+ PutUInt32(p1 - glyfPtr, p2, 0, 1);
+ } else {
+ PutUInt16((sal_uInt16)((p1 - glyfPtr) >> 1), p2, 0, 1);
+ }
+
+ glyf->rawdata = glyfPtr;
+
+ loca = TrueTypeTableNew_loca(); assert(loca != 0);
+ ((tdata_loca *) loca->data)->ptr = locaPtr;
+ ((tdata_loca *) loca->data)->nbytes = locaLen;
+
+ AddTable(tt, loca);
+
+ head = FindTable(tt, T_head);
+ sal_uInt8* const pHeadData = (sal_uInt8*)head->data;
+ PutInt16(xMin, pHeadData, 36, 1);
+ PutInt16(yMin, pHeadData, 38, 1);
+ PutInt16(xMax, pHeadData, 40, 1);
+ PutInt16(yMax, pHeadData, 42, 1);
+ PutInt16(indexToLocFormat, pHeadData, 50, 1);
+
+ maxp = FindTable(tt, T_maxp);
+
+ sal_uInt8* const pMaxpData = (sal_uInt8*)maxp->data;
+ PutUInt16((sal_uInt16)nGlyphs, pMaxpData, 4, 1);
+ PutUInt16(maxPoints, pMaxpData, 6, 1);
+ PutUInt16(maxContours, pMaxpData, 8, 1);
+ PutUInt16(maxCompositePoints, pMaxpData, 10, 1);
+ PutUInt16(maxCompositeContours, pMaxpData, 12, 1);
+
+#if 0
+ /* XXX do not overwrite the existing data. Fix: re-calculate these numbers here */
+ PutUInt16(2, maxp->data, 14, 1); /* maxZones is always 2 */
+ PutUInt16(0, maxp->data, 16, 1); /* maxTwilightPoints */
+ PutUInt16(0, maxp->data, 18, 1); /* maxStorage */
+ PutUInt16(0, maxp->data, 20, 1); /* maxFunctionDefs */
+ PutUint16(0, maxp->data, 22, 1); /* maxInstructionDefs */
+ PutUint16(0, maxp->data, 24, 1); /* maxStackElements */
+ PutUint16(0, maxp->data, 26, 1); /* maxSizeOfInstructions */
+ PutUint16(0, maxp->data, 28, 1); /* maxComponentElements */
+ PutUint16(0, maxp->data, 30, 1); /* maxComponentDepth */
+#endif
+
+ /*
+ * Generate an htmx table and update hhea table
+ */
+ hhea = FindTable(tt, T_hhea); assert(hhea != 0);
+ hheaPtr = (sal_uInt8 *) hhea->data;
+ if (nGlyphs > 2) {
+ for (i = nGlyphs - 1; i > 0; i--) {
+ if (met[i].adv != met[i-1].adv) break;
+ }
+ nlsb = nGlyphs - 1 - i;
+ }
+ hmtxSize = (nGlyphs - nlsb) * 4 + nlsb * 2;
+ hmtxPtr = ttmalloc(hmtxSize);
+ p1 = hmtxPtr;
+
+ for (i = 0; i < nGlyphs; i++) {
+ if (i < nGlyphs - nlsb) {
+ PutUInt16(met[i].adv, p1, 0, 1);
+ PutUInt16(met[i].sb, p1, 2, 1);
+ p1 += 4;
+ } else {
+ PutUInt16(met[i].sb, p1, 0, 1);
+ p1 += 2;
+ }
+ }
+
+ AddTable(tt, TrueTypeTableNew(T_hmtx, hmtxSize, hmtxPtr));
+ PutUInt16((sal_uInt16)(nGlyphs - nlsb), hheaPtr, 34, 1);
+ free(hmtxPtr);
+ free(met);
+}
+
+} // namespace vcl
+
+extern "C"
+{
+ /**
+ * TrueTypeCreator destructor. It calls destructors for all TrueTypeTables added to it.
+ */
+ void TrueTypeCreatorDispose(vcl::TrueTypeCreator *_this)
+ {
+ listDispose(_this->tables);
+ free(_this);
+ }
+
+
+ /**
+ * Destructor for the TrueTypeTable object.
+ */
+ void TrueTypeTableDispose(vcl::TrueTypeTable *_this)
+ {
+ /* XXX do a binary search */
+ unsigned int i;
+
+ assert(_this != 0);
+
+ if (_this->rawdata) free(_this->rawdata);
+
+ for(i=0; i < sizeof(vcl::vtable1)/sizeof(*vcl::vtable1); i++) {
+ if (_this->tag == vcl::vtable1[i].tag) {
+ vcl::vtable1[i].f(_this);
+ return;
+ }
+ }
+ assert(!"Unknown TrueType table.\n");
+ }
+}
+
+
+#ifdef TEST_TTCR
+int main(void)
+{
+ TrueTypeCreator *ttcr;
+ sal_uInt8 *t1, *t2, *t3, *t4, *t5, *t6, *t7;
+
+ TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr);
+
+ t1 = malloc(1000); memset(t1, 'a', 1000);
+ t2 = malloc(2000); memset(t2, 'b', 2000);
+ t3 = malloc(3000); memset(t3, 'c', 3000);
+ t4 = malloc(4000); memset(t4, 'd', 4000);
+ t5 = malloc(5000); memset(t5, 'e', 5000);
+ t6 = malloc(6000); memset(t6, 'f', 6000);
+ t7 = malloc(7000); memset(t7, 'g', 7000);
+
+ AddTable(ttcr, TrueTypeTableNew(0x6D617870, 1000, t1));
+ AddTable(ttcr, TrueTypeTableNew(0x4F532F32, 2000, t2));
+ AddTable(ttcr, TrueTypeTableNew(0x636D6170, 3000, t3));
+ AddTable(ttcr, TrueTypeTableNew(0x6C6F6361, 4000, t4));
+ AddTable(ttcr, TrueTypeTableNew(0x68686561, 5000, t5));
+ AddTable(ttcr, TrueTypeTableNew(0x676C7966, 6000, t6));
+ AddTable(ttcr, TrueTypeTableNew(0x6B65726E, 7000, t7));
+
+ free(t1);
+ free(t2);
+ free(t3);
+ free(t4);
+ free(t5);
+ free(t6);
+ free(t7);
+
+
+ StreamToFile(ttcr, "ttcrout.ttf");
+
+ TrueTypeCreatorDispose(ttcr);
+ return 0;
+}
+#endif
diff --git a/vcl/source/fontsubset/ttcr.hxx b/vcl/source/fontsubset/ttcr.hxx
new file mode 100644
index 000000000000..69583ecdbdda
--- /dev/null
+++ b/vcl/source/fontsubset/ttcr.hxx
@@ -0,0 +1,261 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/**
+ *
+ * @file ttcr.h
+ * @brief TrueType font creator
+ * @author Alexander Gelfenbain
+ */
+
+#ifndef __TTCR_H
+#define __TTCR_H
+
+#include "sft.hxx"
+
+namespace vcl
+{
+ typedef struct _TrueTypeCreator TrueTypeCreator;
+
+/* TrueType data types */
+ typedef struct {
+ sal_uInt16 aw;
+ sal_Int16 lsb;
+ } longHorMetrics;
+
+/* A generic base class for all TrueType tables */
+ struct TrueTypeTable {
+ sal_uInt32 tag; /* table tag */
+ sal_uInt8 *rawdata; /* raw data allocated by GetRawData_*() */
+ void *data; /* table specific data */
+ };
+
+/** Error codes for most functions */
+ enum TTCRErrCodes {
+ TTCR_OK = 0, /**< no error */
+ TTCR_ZEROGLYPHS = 1, /**< At least one glyph should be defined */
+ TTCR_UNKNOWN = 2, /**< Unknown TrueType table */
+ TTCR_GLYPHSEQ = 3, /**< Glyph IDs are not sequential in the glyf table */
+ TTCR_NONAMES = 4, /**< 'name' table does not contain any names */
+ TTCR_NAMETOOLONG = 5, /**< 'name' table is too long (string data > 64K) */
+ TTCR_POSTFORMAT = 6 /**< unsupported format of a 'post' table */
+ };
+
+/* ============================================================================
+ *
+ * TrueTypeCreator methods
+ *
+ * ============================================================================ */
+
+/**
+ * TrueTypeCreator constructor.
+ * Allocates all internal structures.
+ */
+ void TrueTypeCreatorNewEmpty(sal_uInt32 tag, TrueTypeCreator **_this);
+
+/**
+ * Adds a TrueType table to the TrueType creator.
+ * SF_TABLEFORMAT value.
+ * @return value of SFErrCodes type
+ */
+ int AddTable(TrueTypeCreator *_this, TrueTypeTable *table);
+
+/**
+ * Removes a TrueType table from the TrueType creator if it is stored there.
+ * It also calls a TrueTypeTable destructor.
+ * Note: all generic tables (with tag 0) will be removed if this function is
+ * called with the second argument of 0.
+ * @return value of SFErrCodes type
+ */
+ void RemoveTable(TrueTypeCreator *_this, sal_uInt32 tag);
+
+
+
+/**
+ * Writes a TrueType font generated by the TrueTypeCreator to a segment of
+ * memory that this method allocates. When it is not needed anymore the caller
+ * is supposed to call free() on it.
+ * @return value of SFErrCodes type
+ */
+ int StreamToMemory(TrueTypeCreator *_this, sal_uInt8 **ptr, sal_uInt32 *length);
+
+/**
+ * Writes a TrueType font generated by the TrueTypeCreator to a file
+ * @return value of SFErrCodes type
+ */
+ int StreamToFile(TrueTypeCreator *_this, const char* fname);
+
+
+/* ============================================================================
+ *
+ * TrueTypeTable methods
+ *
+ * ============================================================================ */
+
+
+/**
+ * This function converts the data of a TrueType table to a raw array of bytes.
+ * It may allocates the memory for it and returns the size of the raw data in bytes.
+ * If memory is allocated it does not need to be freed by the caller of this function,
+ * since the pointer to it is stored in the TrueTypeTable and it is freed by the destructor
+ * @return TTCRErrCode
+ *
+ */
+
+ int GetRawData(TrueTypeTable *, sal_uInt8 **ptr, sal_uInt32 *len, sal_uInt32 *tag);
+
+/**
+ *
+ * Creates a new raw TrueType table. The difference between this constructor and
+ * TrueTypeTableNew_tag constructors is that the latter create structured tables
+ * while this constructor just copies memory pointed to by ptr to its buffer
+ * and stores its length. This constructor is suitable for data that is not
+ * supposed to be processed in any way, just written to the resulting TTF file.
+ */
+ TrueTypeTable *TrueTypeTableNew(sal_uInt32 tag,
+ sal_uInt32 nbytes,
+ const sal_uInt8* ptr);
+
+/**
+ * Creates a new 'head' table for a TrueType font.
+ * Allocates memory for it. Since a lot of values in the 'head' table depend on the
+ * rest of the tables in the TrueType font this table should be the last one added
+ * to the font.
+ */
+ TrueTypeTable *TrueTypeTableNew_head(sal_uInt32 fontRevision,
+ sal_uInt16 flags,
+ sal_uInt16 unitsPerEm,
+ const sal_uInt8 *created,
+ sal_uInt16 macStyle,
+ sal_uInt16 lowestRecPPEM,
+ sal_Int16 fontDirectionHint);
+
+/**
+ * Creates a new 'hhea' table for a TrueType font.
+ * Allocates memory for it and stores it in the hhea pointer.
+ */
+ TrueTypeTable *TrueTypeTableNew_hhea(sal_Int16 ascender,
+ sal_Int16 descender,
+ sal_Int16 linegap,
+ sal_Int16 caretSlopeRise,
+ sal_Int16 caretSlopeRun);
+
+/**
+ * Creates a new empty 'loca' table for a TrueType font.
+ *
+ * INTERNAL: gets called only from ProcessTables();
+ */
+ TrueTypeTable *TrueTypeTableNew_loca(void);
+
+/**
+ * Creates a new 'maxp' table based on an existing maxp table.
+ * If maxp is 0, a new empty maxp table is created
+ * size specifies the size of existing maxp table for
+ * error-checking purposes
+ */
+ TrueTypeTable *TrueTypeTableNew_maxp( const sal_uInt8* maxp, int size);
+
+/**
+ * Creates a new empty 'glyf' table.
+ */
+ TrueTypeTable *TrueTypeTableNew_glyf(void);
+
+/**
+ * Creates a new empty 'cmap' table.
+ */
+ TrueTypeTable *TrueTypeTableNew_cmap(void);
+
+/**
+ * Creates a new 'name' table. If n != 0 the table gets populated by
+ * the Name Records stored in the nr array. This function allocates
+ * memory for its own copy of NameRecords, so nr array has to
+ * be explicitly deallocated when it is not needed.
+ */
+ TrueTypeTable *TrueTypeTableNew_name(int n, NameRecord *nr);
+
+/**
+ * Creates a new 'post' table of one of the supported formats
+ */
+ TrueTypeTable *TrueTypeTableNew_post(sal_uInt32 format,
+ sal_uInt32 italicAngle,
+ sal_Int16 underlinePosition,
+ sal_Int16 underlineThickness,
+ sal_uInt32 isFixedPitch);
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Table manipulation functions
+ *
+ *------------------------------------------------------------------------------*/
+
+
+/**
+ * Add a character/glyph pair to a cmap table
+ */
+ void cmapAdd(TrueTypeTable *, sal_uInt32 id, sal_uInt32 c, sal_uInt32 g);
+
+/**
+ * Add a glyph to a glyf table.
+ *
+ * @return glyphID of the glyph in the new font
+ *
+ * NOTE: This function does not duplicate GlyphData, so memory will be
+ * deallocated in the table destructor
+ */
+ sal_uInt32 glyfAdd(TrueTypeTable *, GlyphData *glyphdata, TrueTypeFont *fnt);
+
+/**
+ * Query the number of glyphs currently stored in the 'glyf' table
+ *
+ */
+ sal_uInt32 glyfCount(const TrueTypeTable *);
+
+/**
+ * Add a Name Record to a name table.
+ * NOTE: This function duplicates NameRecord, so the argument
+ * has to be deallocated by the caller (unlike glyfAdd)
+ */
+ void nameAdd(TrueTypeTable *, NameRecord *nr);
+
+} // namespace
+
+
+extern "C"
+{
+/**
+ * Destructor for the TrueTypeTable object.
+ */
+ void TrueTypeTableDispose(vcl::TrueTypeTable *);
+
+/**
+ * TrueTypeCreator destructor. It calls destructors for all TrueTypeTables added to it.
+ */
+ void TrueTypeCreatorDispose(vcl::TrueTypeCreator *_this);
+}
+
+#endif /* __TTCR_H */
diff --git a/vcl/source/fontsubset/xlat.cxx b/vcl/source/fontsubset/xlat.cxx
new file mode 100644
index 000000000000..108c69cee8c7
--- /dev/null
+++ b/vcl/source/fontsubset/xlat.cxx
@@ -0,0 +1,221 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "rtl/textcvt.h"
+#include <tools/debug.hxx>
+
+namespace { // anonymous namespace
+
+// ====================================================================
+
+#define MAX_CVT_SELECT 6
+
+class ConverterCache
+{
+public:
+ explicit ConverterCache( void );
+ ~ConverterCache( void );
+ sal_uInt16 convertOne( int nSelect, sal_Unicode );
+ void convertStr( int nSelect, const sal_Unicode* pSrc, sal_uInt16* pDst, int nCount );
+protected:
+ void ensureConverter( int nSelect );
+private:
+ rtl_UnicodeToTextConverter maConverterCache[ MAX_CVT_SELECT+1 ];
+ rtl_UnicodeToTextContext maContexts[ MAX_CVT_SELECT+1 ];
+};
+
+// ====================================================================
+
+ConverterCache::ConverterCache( void)
+{
+ for( int i = 0; i <= MAX_CVT_SELECT; ++i)
+ {
+ maConverterCache[i] = NULL;
+ maContexts[i] = NULL;
+ }
+}
+
+// --------------------------------------------------------------------
+
+ConverterCache::~ConverterCache( void)
+{
+ for( int i = 0; i <= MAX_CVT_SELECT; ++i)
+ {
+ if( !maContexts[i] )
+ continue;
+ rtl_destroyUnicodeToTextContext( maConverterCache[i], maContexts[i] );
+ rtl_destroyUnicodeToTextConverter( maConverterCache[i] );
+ }
+}
+
+// --------------------------------------------------------------------
+
+void ConverterCache::ensureConverter( int nSelect )
+{
+ // DBG_ASSERT( (2<=nSelect) && (nSelect<=MAX_CVT_SELECT)), "invalid XLAT.Converter requested" );
+ rtl_UnicodeToTextContext aContext = maContexts[ nSelect ];
+ if( !aContext )
+ {
+ rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
+ switch( nSelect )
+ {
+ default: nSelect = 1; // fall through to unicode recoding
+ case 1: eRecodeFrom = RTL_TEXTENCODING_UNICODE; break;
+ case 2: eRecodeFrom = RTL_TEXTENCODING_SHIFT_JIS; break;
+ case 3: eRecodeFrom = RTL_TEXTENCODING_GB_2312; break;
+ case 4: eRecodeFrom = RTL_TEXTENCODING_BIG5; break;
+ case 5: eRecodeFrom = RTL_TEXTENCODING_MS_949; break;
+ case 6: eRecodeFrom = RTL_TEXTENCODING_MS_1361; break;
+ }
+ rtl_UnicodeToTextConverter aRecodeConverter = rtl_createUnicodeToTextConverter( eRecodeFrom );
+ maConverterCache[ nSelect ] = aRecodeConverter;
+
+ aContext = rtl_createUnicodeToTextContext( aRecodeConverter );
+ maContexts[ nSelect ] = aContext;
+ }
+
+ rtl_resetUnicodeToTextContext( maConverterCache[ nSelect ], aContext );
+}
+
+// --------------------------------------------------------------------
+
+sal_uInt16 ConverterCache::convertOne( int nSelect, sal_Unicode aChar )
+{
+ ensureConverter( nSelect );
+
+ sal_Unicode aUCS2Char = aChar;
+ sal_Char aTempArray[8];
+ sal_Size nTempSize;
+ sal_uInt32 nCvtInfo;
+
+ // TODO: use direct unicode->mbcs converter should there ever be one
+ int nCodeLen = rtl_convertUnicodeToText(
+ maConverterCache[ nSelect ], maContexts[ nSelect ],
+ &aUCS2Char, 1, aTempArray, sizeof(aTempArray),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_0
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_0,
+ &nCvtInfo, &nTempSize );
+
+ sal_uInt16 aCode = aTempArray[0];
+ for( int i = 1; i < nCodeLen; ++i )
+ aCode = (aCode << 8) + (aTempArray[i] & 0xFF);
+ return aCode;
+}
+
+// --------------------------------------------------------------------
+
+void ConverterCache::convertStr( int nSelect, const sal_Unicode* pSrc, sal_uInt16* pDst, int nCount )
+{
+ ensureConverter( nSelect );
+
+ for( int n = 0; n < nCount; ++n )
+ {
+ sal_Unicode aUCS2Char = pSrc[n];
+
+ sal_Char aTempArray[8];
+ sal_Size nTempSize;
+ sal_uInt32 nCvtInfo;
+
+ // assume that non-unicode-fonts do not support codepoints >U+FFFF
+ // TODO: use direct unicode->mbcs converter should there ever be one
+ int nCodeLen = rtl_convertUnicodeToText(
+ maConverterCache[ nSelect ], maContexts[ nSelect ],
+ &aUCS2Char, 1, aTempArray, sizeof(aTempArray),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_0
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_0,
+ &nCvtInfo, &nTempSize );
+
+ sal_uInt16 aCode = aTempArray[0];
+ for( int i = 1; i < nCodeLen; ++i )
+ aCode = (aCode << 8) + (aTempArray[i] & 0xFF);
+ pDst[n] = aCode;
+ }
+}
+
+} // anonymous namespace
+
+// ====================================================================
+
+#include "xlat.hxx"
+
+namespace vcl
+{
+
+static ConverterCache aCC;
+
+sal_uInt16 TranslateChar12(sal_uInt16 src)
+{
+ return aCC.convertOne( 2, src);
+}
+
+sal_uInt16 TranslateChar13(sal_uInt16 src)
+{
+ return aCC.convertOne( 3, src);
+}
+
+sal_uInt16 TranslateChar14(sal_uInt16 src)
+{
+ return aCC.convertOne( 4, src);
+}
+
+sal_uInt16 TranslateChar15(sal_uInt16 src)
+{
+ return aCC.convertOne( 5, src);
+}
+
+sal_uInt16 TranslateChar16(sal_uInt16 src)
+{
+ return aCC.convertOne( 6, src);
+}
+
+void TranslateString12(sal_uInt16 *src, sal_uInt16 *dst, sal_uInt32 n)
+{
+ aCC.convertStr( 2, src, dst, n);
+}
+
+void TranslateString13(sal_uInt16 *src, sal_uInt16 *dst, sal_uInt32 n)
+{
+ aCC.convertStr( 3, src, dst, n);
+}
+
+void TranslateString14(sal_uInt16 *src, sal_uInt16 *dst, sal_uInt32 n)
+{
+ aCC.convertStr( 4, src, dst, n);
+}
+
+void TranslateString15(sal_uInt16 *src, sal_uInt16 *dst, sal_uInt32 n)
+{
+ aCC.convertStr( 5, src, dst, n);
+}
+
+void TranslateString16(sal_uInt16 *src, sal_uInt16 *dst, sal_uInt32 n)
+{
+ aCC.convertStr( 6, src, dst, n);
+}
+
+} // namespace vcl
+
diff --git a/vcl/source/fontsubset/xlat.hxx b/vcl/source/fontsubset/xlat.hxx
new file mode 100644
index 000000000000..5960336e13e3
--- /dev/null
+++ b/vcl/source/fontsubset/xlat.hxx
@@ -0,0 +1,54 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/*| Author: Alexander Gelfenbain |*/
+
+
+#ifndef __XLAT_H
+#define __XLAT_H
+
+//####include "sft.hxx"
+
+namespace vcl
+{
+// TODO: sal_UCS4
+
+ sal_uInt16 TranslateChar12(sal_uInt16);
+ sal_uInt16 TranslateChar13(sal_uInt16);
+ sal_uInt16 TranslateChar14(sal_uInt16);
+ sal_uInt16 TranslateChar15(sal_uInt16);
+ sal_uInt16 TranslateChar16(sal_uInt16);
+
+ void TranslateString12(sal_uInt16 *, sal_uInt16 *, sal_uInt32);
+ void TranslateString13(sal_uInt16 *, sal_uInt16 *, sal_uInt32);
+ void TranslateString14(sal_uInt16 *, sal_uInt16 *, sal_uInt32);
+ void TranslateString15(sal_uInt16 *, sal_uInt16 *, sal_uInt32);
+ void TranslateString16(sal_uInt16 *, sal_uInt16 *, sal_uInt32);
+}
+
+#endif /* __XLAT_H */
+
diff --git a/vcl/source/gdi/alpha.cxx b/vcl/source/gdi/alpha.cxx
new file mode 100644
index 000000000000..9d93a540750a
--- /dev/null
+++ b/vcl/source/gdi/alpha.cxx
@@ -0,0 +1,434 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <vcl/bmpacc.hxx>
+#include <tools/color.hxx>
+#include <vcl/alpha.hxx>
+
+// -------------
+// - AlphaMask -
+// -------------
+
+AlphaMask::AlphaMask()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+AlphaMask::AlphaMask( const Bitmap& rBitmap ) :
+ Bitmap( rBitmap )
+{
+ if( !!rBitmap )
+ Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
+}
+
+// -----------------------------------------------------------------------------
+
+AlphaMask::AlphaMask( const AlphaMask& rAlphaMask ) :
+ Bitmap( rAlphaMask )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+AlphaMask::AlphaMask( const Size& rSizePixel, BYTE* pEraseTransparency ) :
+ Bitmap( rSizePixel, 8, &Bitmap::GetGreyPalette( 256 ) )
+{
+ if( pEraseTransparency )
+ Bitmap::Erase( Color( *pEraseTransparency, *pEraseTransparency, *pEraseTransparency ) );
+}
+
+// -----------------------------------------------------------------------------
+
+AlphaMask::~AlphaMask()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+AlphaMask& AlphaMask::operator=( const Bitmap& rBitmap )
+{
+ *(Bitmap*) this = rBitmap;
+
+ if( !!rBitmap )
+ Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------------
+
+const Bitmap& AlphaMask::ImplGetBitmap() const
+{
+ return( (const Bitmap&) *this );
+}
+
+// -----------------------------------------------------------------------------
+
+void AlphaMask::ImplSetBitmap( const Bitmap& rBitmap )
+{
+ DBG_ASSERT( ( 8 == rBitmap.GetBitCount() ) && rBitmap.HasGreyPalette(), "AlphaMask::ImplSetBitmap: invalid bitmap" );
+ *(Bitmap*) this = rBitmap;
+}
+
+// -----------------------------------------------------------------------------
+
+Bitmap AlphaMask::GetBitmap() const
+{
+ return ImplGetBitmap();
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Crop( const Rectangle& rRectPixel )
+{
+ return Bitmap::Crop( rRectPixel );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Expand( ULONG nDX, ULONG nDY, BYTE* pInitTransparency )
+{
+ Color aColor;
+
+ if( pInitTransparency )
+ aColor = Color( *pInitTransparency, *pInitTransparency, *pInitTransparency );
+
+ return Bitmap::Expand( nDX, nDY, pInitTransparency ? &aColor : NULL );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
+ const AlphaMask* pAlphaSrc )
+{
+ // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
+ // this optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
+
+ const Size aSizePix( GetSizePixel() );
+ Rectangle aRectDst( rRectDst );
+ BOOL bRet = FALSE;
+
+ aRectDst.Intersection( Rectangle( Point(), aSizePix ) );
+
+ if( !aRectDst.IsEmpty() )
+ {
+ if( pAlphaSrc && ( *pAlphaSrc != *this ) )
+ {
+ Bitmap* pSrc = (Bitmap*) pAlphaSrc;
+ const Size aCopySizePix( pSrc->GetSizePixel() );
+ Rectangle aRectSrc( rRectSrc );
+
+ aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) );
+
+ if( !aRectSrc.IsEmpty() )
+ {
+ BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess();
+
+ if( pReadAcc )
+ {
+ BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcEndX = aRectSrc.Left() + nWidth;
+ const long nSrcEndY = aRectSrc.Top() + nHeight;
+ long nDstY = aRectDst.Top();
+
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) );
+
+ ReleaseAccess( pWriteAcc );
+ bRet = ( nWidth > 0L ) && ( nHeight > 0L );
+ }
+
+ pSrc->ReleaseAccess( pReadAcc );
+ }
+ }
+ }
+ else
+ {
+ Rectangle aRectSrc( rRectSrc );
+
+ aRectSrc.Intersection( Rectangle( Point(), aSizePix ) );
+
+ if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
+ {
+ BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcX = aRectSrc.Left();
+ const long nSrcY = aRectSrc.Top();
+ const long nSrcEndX1 = nSrcX + nWidth - 1L;
+ const long nSrcEndY1 = nSrcY + nHeight - 1L;
+ const long nDstX = aRectDst.Left();
+ const long nDstY = aRectDst.Top();
+ const long nDstEndX1 = nDstX + nWidth - 1L;
+ const long nDstEndY1 = nDstY + nHeight - 1L;
+
+ if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+ else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+ else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+ else
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+
+ ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+
+ return bRet;
+
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Erase( BYTE cTransparency )
+{
+ return Bitmap::Erase( Color( cTransparency, cTransparency, cTransparency ) );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Invert()
+{
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pAcc && pAcc->GetBitCount() == 8 )
+ {
+ BitmapColor aCol( 0 );
+ const long nWidth = pAcc->Width(), nHeight = pAcc->Height();
+ BYTE* pMap = new BYTE[ 256 ];
+
+ for( long i = 0; i < 256; i++ )
+ pMap[ i ] = ~(BYTE) i;
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aCol.SetIndex( pMap[ pAcc->GetPixel( nY, nX ).GetIndex() ] );
+ pAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+
+ delete[] pMap;
+ bRet = TRUE;
+ }
+
+ if( pAcc )
+ ReleaseAccess( pAcc );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Mirror( ULONG nMirrorFlags )
+{
+ return Bitmap::Mirror( nMirrorFlags );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Scale( const Size& rNewSize, ULONG nScaleFlag )
+{
+ BOOL bRet = Bitmap::Scale( rNewSize, nScaleFlag );
+
+ if( bRet && ( nScaleFlag == BMP_SCALE_INTERPOLATE ) )
+ Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag )
+{
+ BOOL bRet = Bitmap::Scale( rScaleX, rScaleY, nScaleFlag );
+
+ if( bRet && ( nScaleFlag == BMP_SCALE_INTERPOLATE ) )
+ Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Rotate( long nAngle10, BYTE cFillTransparency )
+{
+ return Bitmap::Rotate( nAngle10, Color( cFillTransparency, cFillTransparency, cFillTransparency ) );
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Replace( const Bitmap& rMask, BYTE cReplaceTransparency )
+{
+ BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pMaskAcc && pAcc )
+ {
+ const BitmapColor aReplace( cReplaceTransparency );
+ const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() );
+ const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() );
+ const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite )
+ pAcc->SetPixel( nY, nX, aReplace );
+ }
+
+ ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
+ ReleaseAccess( pAcc );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Replace( BYTE cSearchTransparency, BYTE cReplaceTransparency, ULONG
+#ifdef DBG_UTIL
+nTol
+#endif
+)
+{
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ DBG_ASSERT( !nTol, "AlphaMask::Replace: nTol not used yet" );
+
+ if( pAcc && pAcc->GetBitCount() == 8 )
+ {
+ const long nWidth = pAcc->Width(), nHeight = pAcc->Height();
+
+ if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ Scanline pScan = pAcc->GetScanline( nY );
+
+ for( long nX = 0L; nX < nWidth; nX++, pScan++ )
+ {
+ if( *pScan == cSearchTransparency )
+ *pScan = cReplaceTransparency;
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aReplace( cReplaceTransparency );
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pAcc->GetPixel( nY, nX ).GetIndex() == cSearchTransparency )
+ pAcc->SetPixel( nY, nX, aReplace );
+ }
+ }
+ }
+
+ bRet = TRUE;
+ }
+
+ if( pAcc )
+ ReleaseAccess( pAcc );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL AlphaMask::Replace( BYTE* pSearchTransparencies, BYTE* pReplaceTransparencies,
+ ULONG nColorCount, ULONG* pTols )
+{
+ Color* pSearchColors = new Color[ nColorCount ];
+ Color* pReplaceColors = new Color[ nColorCount ];
+ BOOL bRet;
+
+ for( ULONG i = 0; i < nColorCount; i++ )
+ {
+ const BYTE cSearchTransparency = pSearchTransparencies[ i ];
+ const BYTE cReplaceTransparency = pReplaceTransparencies[ i ];
+
+ pSearchColors[ i ] = Color( cSearchTransparency, cSearchTransparency, cSearchTransparency );
+ pReplaceColors[ i ] = Color( cReplaceTransparency, cReplaceTransparency, cReplaceTransparency );
+ }
+
+ bRet = Bitmap::Replace( pSearchColors, pReplaceColors, nColorCount, pTols ) &&
+ Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
+
+ delete[] pSearchColors;
+ delete[] pReplaceColors;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void AlphaMask::ReleaseAccess( BitmapReadAccess* pAccess )
+{
+ if( pAccess )
+ {
+ Bitmap::ReleaseAccess( pAccess );
+ Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
+ }
+}
diff --git a/vcl/source/gdi/animate.cxx b/vcl/source/gdi/animate.cxx
new file mode 100644
index 000000000000..b0fb3b3de513
--- /dev/null
+++ b/vcl/source/gdi/animate.cxx
@@ -0,0 +1,939 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define ENABLE_BYTESTRING_STREAM_OPERATORS
+#include <vcl/animate.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <rtl/crc.h>
+#include <vcl/virdev.hxx>
+#include <vcl/window.hxx>
+#include <impanmvw.hxx>
+DBG_NAME( Animation )
+
+// -----------
+// - Defines -
+// -----------
+
+#define MIN_TIMEOUT 2L
+#define INC_TIMEOUT 0L
+
+// -----------
+// - statics -
+// -----------
+
+ULONG Animation::mnAnimCount = 0UL;
+
+// -------------------
+// - AnimationBitmap -
+// -------------------
+
+ULONG AnimationBitmap::GetChecksum() const
+{
+ sal_uInt32 nCrc = aBmpEx.GetChecksum();
+ SVBT32 aBT32;
+
+ UInt32ToSVBT32( aPosPix.X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( aPosPix.Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( aSizePix.Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( aSizePix.Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( (long) nWait, aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( (long) eDisposal, aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( (long) bUserInput, aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ return nCrc;
+}
+
+// -------------
+// - Animation -
+// -------------
+
+Animation::Animation() :
+ mnLoopCount ( 0 ),
+ mnLoops ( 0 ),
+ mnPos ( 0 ),
+ meCycleMode ( CYCLE_NORMAL ),
+ mbIsInAnimation ( FALSE ),
+ mbLoopTerminated ( FALSE ),
+ mbIsWaiting ( FALSE )
+{
+ DBG_CTOR( Animation, NULL );
+ maTimer.SetTimeoutHdl( LINK( this, Animation, ImplTimeoutHdl ) );
+ mpViewList = new List;
+}
+
+// -----------------------------------------------------------------------
+
+Animation::Animation( const Animation& rAnimation ) :
+ maBitmapEx ( rAnimation.maBitmapEx ),
+ maGlobalSize ( rAnimation.maGlobalSize ),
+ mnLoopCount ( rAnimation.mnLoopCount ),
+ mnPos ( rAnimation.mnPos ),
+ meCycleMode ( rAnimation.meCycleMode ),
+ mbIsInAnimation ( FALSE ),
+ mbLoopTerminated ( rAnimation.mbLoopTerminated ),
+ mbIsWaiting ( rAnimation.mbIsWaiting )
+{
+ DBG_CTOR( Animation, NULL );
+
+ for( long i = 0, nCount = rAnimation.maList.Count(); i < nCount; i++ )
+ maList.Insert( new AnimationBitmap( *(AnimationBitmap*) rAnimation.maList.GetObject( i ) ), LIST_APPEND );
+
+ maTimer.SetTimeoutHdl( LINK( this, Animation, ImplTimeoutHdl ) );
+ mpViewList = new List;
+ mnLoops = mbLoopTerminated ? 0 : mnLoopCount;
+}
+
+// -----------------------------------------------------------------------
+
+Animation::~Animation()
+{
+ DBG_DTOR( Animation, NULL );
+
+ if( mbIsInAnimation )
+ Stop();
+
+ for( void* pStepBmp = maList.First(); pStepBmp; pStepBmp = maList.Next() )
+ delete (AnimationBitmap*) pStepBmp;
+
+ for( void* pView = mpViewList->First(); pView; pView = mpViewList->Next() )
+ delete (ImplAnimView*) pView;
+
+ delete mpViewList;
+}
+
+// -----------------------------------------------------------------------
+
+Animation& Animation::operator=( const Animation& rAnimation )
+{
+ Clear();
+
+ for( long i = 0, nCount = rAnimation.maList.Count(); i < nCount; i++ )
+ maList.Insert( new AnimationBitmap( *(AnimationBitmap*) rAnimation.maList.GetObject( i ) ), LIST_APPEND );
+
+ maGlobalSize = rAnimation.maGlobalSize;
+ maBitmapEx = rAnimation.maBitmapEx;
+ meCycleMode = rAnimation.meCycleMode;
+ mnLoopCount = rAnimation.mnLoopCount;
+ mnPos = rAnimation.mnPos;
+ mbLoopTerminated = rAnimation.mbLoopTerminated;
+ mbIsWaiting = rAnimation.mbIsWaiting;
+ mnLoops = mbLoopTerminated ? 0 : mnLoopCount;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::operator==( const Animation& rAnimation ) const
+{
+ const ULONG nCount = maList.Count();
+ BOOL bRet = FALSE;
+
+ if( rAnimation.maList.Count() == nCount &&
+ rAnimation.maBitmapEx == maBitmapEx &&
+ rAnimation.maGlobalSize == maGlobalSize &&
+ rAnimation.meCycleMode == meCycleMode )
+ {
+ bRet = TRUE;
+
+ for( ULONG n = 0; n < nCount; n++ )
+ {
+ if( ( *(AnimationBitmap*) maList.GetObject( n ) ) !=
+ ( *(AnimationBitmap*) rAnimation.maList.GetObject( n ) ) )
+ {
+ bRet = FALSE;
+ break;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Animation::IsEqual( const Animation& rAnimation ) const
+{
+ const ULONG nCount = maList.Count();
+ BOOL bRet = FALSE;
+
+ if( rAnimation.maList.Count() == nCount &&
+ rAnimation.maBitmapEx.IsEqual( maBitmapEx ) &&
+ rAnimation.maGlobalSize == maGlobalSize &&
+ rAnimation.meCycleMode == meCycleMode )
+ {
+ for( ULONG n = 0; ( n < nCount ) && !bRet; n++ )
+ if( ( (AnimationBitmap*) maList.GetObject( n ) )->IsEqual( *(AnimationBitmap*) rAnimation.maList.GetObject( n ) ) )
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Animation::IsEmpty() const
+{
+ return( maBitmapEx.IsEmpty() && !maList.Count() );
+}
+
+// ------------------------------------------------------------------
+
+void Animation::SetEmpty()
+{
+ maTimer.Stop();
+ mbIsInAnimation = FALSE;
+ maGlobalSize = Size();
+ maBitmapEx.SetEmpty();
+
+ for( void* pStepBmp = maList.First(); pStepBmp; pStepBmp = maList.Next() )
+ delete (AnimationBitmap*) pStepBmp;
+ maList.Clear();
+
+ for( void* pView = mpViewList->First(); pView; pView = mpViewList->Next() )
+ delete (ImplAnimView*) pView;
+ mpViewList->Clear();
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::Clear()
+{
+ SetEmpty();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::IsTransparent() const
+{
+ Point aPoint;
+ Rectangle aRect( aPoint, maGlobalSize );
+ BOOL bRet = FALSE;
+
+ // Falls irgendein 'kleines' Bildchen durch den Hintergrund
+ // ersetzt werden soll, muessen wir 'transparent' sein, um
+ // richtig dargestellt zu werden, da die Appl. aus Optimierungsgruenden
+ // kein Invalidate auf nicht-transp. Grafiken ausfuehren
+ for( long i = 0, nCount = maList.Count(); i < nCount; i++ )
+ {
+ const AnimationBitmap* pAnimBmp = (AnimationBitmap*) maList.GetObject( i );
+
+ if( DISPOSE_BACK == pAnimBmp->eDisposal && Rectangle( pAnimBmp->aPosPix, pAnimBmp->aSizePix ) != aRect )
+ {
+ bRet = TRUE;
+ break;
+ }
+ }
+
+ if( !bRet )
+ bRet = maBitmapEx.IsTransparent();
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Animation::GetSizeBytes() const
+{
+ ULONG nSizeBytes = GetBitmapEx().GetSizeBytes();
+
+ for( long i = 0, nCount = maList.Count(); i < nCount; i++ )
+ {
+ const AnimationBitmap* pAnimBmp = (AnimationBitmap*) maList.GetObject( i );
+ nSizeBytes += pAnimBmp->aBmpEx.GetSizeBytes();
+ }
+
+ return nSizeBytes;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Animation::GetChecksum() const
+{
+ SVBT32 aBT32;
+ sal_uInt32 nCrc = GetBitmapEx().GetChecksum();
+
+ UInt32ToSVBT32( maList.Count(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( maGlobalSize.Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( maGlobalSize.Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( (long) meCycleMode, aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ for( long i = 0, nCount = maList.Count(); i < nCount; i++ )
+ {
+ UInt32ToSVBT32( ( (AnimationBitmap*) maList.GetObject( i ) )->GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+
+ return nCrc;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Start( OutputDevice* pOut, const Point& rDestPt, long nExtraData,
+ OutputDevice* pFirstFrameOutDev )
+{
+ return Start( pOut, rDestPt, pOut->PixelToLogic( maGlobalSize ), nExtraData, pFirstFrameOutDev );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Start( OutputDevice* pOut, const Point& rDestPt, const Size& rDestSz, long nExtraData,
+ OutputDevice* pFirstFrameOutDev )
+{
+ BOOL bRet = FALSE;
+
+ if( maList.Count() )
+ {
+ if( ( pOut->GetOutDevType() == OUTDEV_WINDOW ) && !mbLoopTerminated &&
+ ( ANIMATION_TIMEOUT_ON_CLICK != ( (AnimationBitmap*) maList.GetObject( mnPos ) )->nWait ) )
+ {
+ ImplAnimView* pView;
+ ImplAnimView* pMatch = NULL;
+
+ for( pView = (ImplAnimView*) mpViewList->First(); pView; pView = (ImplAnimView*) mpViewList->Next() )
+ {
+ if( pView->ImplMatches( pOut, nExtraData ) )
+ {
+ if( pView->ImplGetOutPos() == rDestPt &&
+ pView->ImplGetOutSizePix() == pOut->LogicToPixel( rDestSz ) )
+ {
+ pView->ImplRepaint();
+ pMatch = pView;
+ }
+ else
+ {
+ delete (ImplAnimView*) mpViewList->Remove( pView );
+ pView = NULL;
+ }
+
+ break;
+ }
+ }
+
+ if( !mpViewList->Count() )
+ {
+ maTimer.Stop();
+ mbIsInAnimation = FALSE;
+ mnPos = 0UL;
+ }
+
+ if( !pMatch )
+ mpViewList->Insert( new ImplAnimView( this, pOut, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev ), LIST_APPEND );
+
+ if( !mbIsInAnimation )
+ {
+ ImplRestartTimer( ( (AnimationBitmap*) maList.GetObject( mnPos ) )->nWait );
+ mbIsInAnimation = TRUE;
+ }
+ }
+ else
+ Draw( pOut, rDestPt, rDestSz );
+
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::Stop( OutputDevice* pOut, long nExtraData )
+{
+ ImplAnimView* pView = (ImplAnimView*) mpViewList->First();
+
+ while( pView )
+ {
+ if( pView->ImplMatches( pOut, nExtraData ) )
+ {
+ delete (ImplAnimView*) mpViewList->Remove( pView );
+ pView = (ImplAnimView*) mpViewList->GetCurObject();
+ }
+ else
+ pView = (ImplAnimView*) mpViewList->Next();
+ }
+
+ if( !mpViewList->Count() )
+ {
+ maTimer.Stop();
+ mbIsInAnimation = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::Draw( OutputDevice* pOut, const Point& rDestPt ) const
+{
+ Draw( pOut, rDestPt, pOut->PixelToLogic( maGlobalSize ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::Draw( OutputDevice* pOut, const Point& rDestPt, const Size& rDestSz ) const
+{
+ const ULONG nCount = maList.Count();
+
+ if( nCount )
+ {
+ AnimationBitmap* pObj = (AnimationBitmap*) maList.GetObject( Min( mnPos, (long) nCount - 1L ) );
+
+ if( pOut->GetConnectMetaFile() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) )
+ ( (AnimationBitmap*) maList.GetObject( 0 ) )->aBmpEx.Draw( pOut, rDestPt, rDestSz );
+ else if( ANIMATION_TIMEOUT_ON_CLICK == pObj->nWait )
+ pObj->aBmpEx.Draw( pOut, rDestPt, rDestSz );
+ else
+ {
+ const ULONG nOldPos = mnPos;
+ ( (Animation*) this )->mnPos = mbLoopTerminated ? ( nCount - 1UL ) : mnPos;
+ delete new ImplAnimView( (Animation*) this, pOut, rDestPt, rDestSz, 0 );
+ ( (Animation*) this )->mnPos = nOldPos;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::ImplRestartTimer( ULONG nTimeout )
+{
+ maTimer.SetTimeout( Max( nTimeout, (ULONG)(MIN_TIMEOUT + ( mnAnimCount - 1 ) * INC_TIMEOUT) ) * 10L );
+ maTimer.Start();
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Animation, ImplTimeoutHdl, Timer*, EMPTYARG )
+{
+ const ULONG nAnimCount = maList.Count();
+
+ if( nAnimCount )
+ {
+ ImplAnimView* pView;
+ BOOL bGlobalPause = TRUE;
+
+ if( maNotifyLink.IsSet() )
+ {
+ AInfo* pAInfo;
+
+ // create AInfo-List
+ for( pView = (ImplAnimView*) mpViewList->First(); pView; pView = (ImplAnimView*) mpViewList->Next() )
+ maAInfoList.Insert( pView->ImplCreateAInfo() );
+
+ maNotifyLink.Call( this );
+
+ // set view state from AInfo structure
+ for( pAInfo = (AInfo*) maAInfoList.First(); pAInfo; pAInfo = (AInfo*) maAInfoList.Next() )
+ {
+ if( !pAInfo->pViewData )
+ {
+ pView = new ImplAnimView( this, pAInfo->pOutDev,
+ pAInfo->aStartOrg, pAInfo->aStartSize, pAInfo->nExtraData );
+
+ mpViewList->Insert( pView, LIST_APPEND );
+ }
+ else
+ pView = (ImplAnimView*) pAInfo->pViewData;
+
+ pView->ImplPause( pAInfo->bPause );
+ pView->ImplSetMarked( TRUE );
+ }
+
+ // delete AInfo structures
+ for( pAInfo = (AInfo*) maAInfoList.First(); pAInfo; pAInfo = (AInfo*) maAInfoList.Next() )
+ delete (AInfo*) pAInfo;
+ maAInfoList.Clear();
+
+ // delete all unmarked views and reset marked state
+ pView = (ImplAnimView*) mpViewList->First();
+ while( pView )
+ {
+ if( !pView->ImplIsMarked() )
+ {
+ delete (ImplAnimView*) mpViewList->Remove( pView );
+ pView = (ImplAnimView*) mpViewList->GetCurObject();
+ }
+ else
+ {
+ if( !pView->ImplIsPause() )
+ bGlobalPause = FALSE;
+
+ pView->ImplSetMarked( FALSE );
+ pView = (ImplAnimView*) mpViewList->Next();
+ }
+ }
+ }
+ else
+ bGlobalPause = FALSE;
+
+ if( !mpViewList->Count() )
+ Stop();
+ else if( bGlobalPause )
+ ImplRestartTimer( 10 );
+ else
+ {
+ AnimationBitmap* pStepBmp = (AnimationBitmap*) maList.GetObject( ++mnPos );
+
+ if( !pStepBmp )
+ {
+ if( mnLoops == 1 )
+ {
+ Stop();
+ mbLoopTerminated = TRUE;
+ mnPos = nAnimCount - 1UL;
+ maBitmapEx = ( (AnimationBitmap*) maList.GetObject( mnPos ) )->aBmpEx;
+ return 0L;
+ }
+ else
+ {
+ if( mnLoops )
+ mnLoops--;
+
+ mnPos = 0;
+ pStepBmp = (AnimationBitmap*) maList.GetObject( mnPos );
+ }
+ }
+
+ // Paint all views; after painting check, if view is
+ // marked; in this case remove view, because area of output
+ // lies out of display area of window; mark state is
+ // set from view itself
+ pView = (ImplAnimView*) mpViewList->First();
+ while( pView )
+ {
+ pView->ImplDraw( mnPos );
+
+ if( pView->ImplIsMarked() )
+ {
+ delete (ImplAnimView*) mpViewList->Remove( pView );
+ pView = (ImplAnimView*) mpViewList->GetCurObject();
+ }
+ else
+ pView = (ImplAnimView*) mpViewList->Next();
+ }
+
+ // stop or restart timer
+ if( !mpViewList->Count() )
+ Stop();
+ else
+ ImplRestartTimer( pStepBmp->nWait );
+ }
+ }
+ else
+ Stop();
+
+ return 0L;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Insert( const AnimationBitmap& rStepBmp )
+{
+ BOOL bRet = FALSE;
+
+ if( !IsInAnimation() )
+ {
+ Point aPoint;
+ Rectangle aGlobalRect( aPoint, maGlobalSize );
+
+ maGlobalSize = aGlobalRect.Union( Rectangle( rStepBmp.aPosPix, rStepBmp.aSizePix ) ).GetSize();
+ maList.Insert( new AnimationBitmap( rStepBmp ), LIST_APPEND );
+
+ // zunaechst nehmen wir die erste BitmapEx als Ersatz-BitmapEx
+ if( maList.Count() == 1 )
+ maBitmapEx = rStepBmp.aBmpEx;
+
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+const AnimationBitmap& Animation::Get( USHORT nAnimation ) const
+{
+ DBG_ASSERT( ( nAnimation < maList.Count() ), "No object at this position" );
+ return *(AnimationBitmap*) maList.GetObject( nAnimation );
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::Replace( const AnimationBitmap& rNewAnimationBitmap, USHORT nAnimation )
+{
+ DBG_ASSERT( ( nAnimation < maList.Count() ), "No object at this position" );
+
+ delete (AnimationBitmap*) maList.Replace( new AnimationBitmap( rNewAnimationBitmap ), nAnimation );
+
+ // Falls wir an erster Stelle einfuegen,
+ // muessen wir natuerlich auch,
+ // auch die Ersatzdarstellungs-BitmapEx
+ // aktualisieren;
+ if ( ( !nAnimation && ( !mbLoopTerminated || ( maList.Count() == 1 ) ) ) ||
+ ( ( nAnimation == maList.Count() - 1 ) && mbLoopTerminated ) )
+ {
+ maBitmapEx = rNewAnimationBitmap.aBmpEx;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::SetLoopCount( const ULONG nLoopCount )
+{
+ mnLoopCount = nLoopCount;
+ ResetLoopCount();
+}
+
+// -----------------------------------------------------------------------
+
+void Animation::ResetLoopCount()
+{
+ mnLoops = mnLoopCount;
+ mbLoopTerminated = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Convert( BmpConversion eConversion )
+{
+ DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
+
+ BOOL bRet;
+
+ if( !IsInAnimation() && maList.Count() )
+ {
+ bRet = TRUE;
+
+ for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
+ bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Convert( eConversion );
+
+ maBitmapEx.Convert( eConversion );
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::ReduceColors( USHORT nNewColorCount, BmpReduce eReduce )
+{
+ DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
+
+ BOOL bRet;
+
+ if( !IsInAnimation() && maList.Count() )
+ {
+ bRet = TRUE;
+
+ for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
+ bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.ReduceColors( nNewColorCount, eReduce );
+
+ maBitmapEx.ReduceColors( nNewColorCount, eReduce );
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Invert()
+{
+ DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
+
+ BOOL bRet;
+
+ if( !IsInAnimation() && maList.Count() )
+ {
+ bRet = TRUE;
+
+ for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
+ bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Invert();
+
+ maBitmapEx.Invert();
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Mirror( ULONG nMirrorFlags )
+{
+ DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
+
+ BOOL bRet;
+
+ if( !IsInAnimation() && maList.Count() )
+ {
+ bRet = TRUE;
+
+ if( nMirrorFlags )
+ {
+ for( AnimationBitmap* pStepBmp = (AnimationBitmap*) maList.First();
+ pStepBmp && bRet;
+ pStepBmp = (AnimationBitmap*) maList.Next() )
+ {
+ if( ( bRet = pStepBmp->aBmpEx.Mirror( nMirrorFlags ) ) == TRUE )
+ {
+ if( nMirrorFlags & BMP_MIRROR_HORZ )
+ pStepBmp->aPosPix.X() = maGlobalSize.Width() - pStepBmp->aPosPix.X() - pStepBmp->aSizePix.Width();
+
+ if( nMirrorFlags & BMP_MIRROR_VERT )
+ pStepBmp->aPosPix.Y() = maGlobalSize.Height() - pStepBmp->aPosPix.Y() - pStepBmp->aSizePix.Height();
+ }
+ }
+
+ maBitmapEx.Mirror( nMirrorFlags );
+ }
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Dither( ULONG nDitherFlags )
+{
+ DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
+
+ BOOL bRet;
+
+ if( !IsInAnimation() && maList.Count() )
+ {
+ bRet = TRUE;
+
+ for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
+ bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Dither( nDitherFlags );
+
+ maBitmapEx.Dither( nDitherFlags );
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Adjust( short nLuminancePercent, short nContrastPercent,
+ short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
+ double fGamma, BOOL bInvert )
+{
+ DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
+
+ BOOL bRet;
+
+ if( !IsInAnimation() && maList.Count() )
+ {
+ bRet = TRUE;
+
+ for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
+ {
+ bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Adjust( nLuminancePercent, nContrastPercent,
+ nChannelRPercent, nChannelGPercent, nChannelBPercent,
+ fGamma, bInvert );
+ }
+
+ maBitmapEx.Adjust( nLuminancePercent, nContrastPercent,
+ nChannelRPercent, nChannelGPercent, nChannelBPercent,
+ fGamma, bInvert );
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Animation::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
+{
+ DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
+
+ BOOL bRet;
+
+ if( !IsInAnimation() && maList.Count() )
+ {
+ bRet = TRUE;
+
+ for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
+ bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Filter( eFilter, pFilterParam, pProgress );
+
+ maBitmapEx.Filter( eFilter, pFilterParam, pProgress );
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Animation& rAnimation )
+{
+ const USHORT nCount = rAnimation.Count();
+
+ if( nCount )
+ {
+ const ByteString aDummyStr;
+ const UINT32 nDummy32 = 0UL;
+
+ // Falls keine BitmapEx gesetzt wurde, schreiben wir
+ // einfach die erste Bitmap der Animation
+ if( !rAnimation.GetBitmapEx().GetBitmap() )
+ rOStm << rAnimation.Get( 0 ).aBmpEx;
+ else
+ rOStm << rAnimation.GetBitmapEx();
+
+ // Kennung schreiben ( SDANIMA1 )
+ rOStm << (UINT32) 0x5344414e << (UINT32) 0x494d4931;
+
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ const AnimationBitmap& rAnimBmp = rAnimation.Get( i );
+ const UINT16 nRest = nCount - i - 1;
+
+ // AnimationBitmap schreiben
+ rOStm << rAnimBmp.aBmpEx;
+ rOStm << rAnimBmp.aPosPix;
+ rOStm << rAnimBmp.aSizePix;
+ rOStm << rAnimation.maGlobalSize;
+ rOStm << (UINT16) ( ( ANIMATION_TIMEOUT_ON_CLICK == rAnimBmp.nWait ) ? 65535 : rAnimBmp.nWait );
+ rOStm << (UINT16) rAnimBmp.eDisposal;
+ rOStm << (BYTE) rAnimBmp.bUserInput;
+ rOStm << (UINT32) rAnimation.mnLoopCount;
+ rOStm << nDummy32; // unbenutzt
+ rOStm << nDummy32; // unbenutzt
+ rOStm << nDummy32; // unbenutzt
+ rOStm << aDummyStr; // unbenutzt
+ rOStm << nRest; // Anzahl der Strukturen, die noch _folgen_
+ }
+ }
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, Animation& rAnimation )
+{
+ Bitmap aBmp;
+ ULONG nStmPos = rIStm.Tell();
+ UINT32 nAnimMagic1, nAnimMagic2;
+ USHORT nOldFormat = rIStm.GetNumberFormatInt();
+ BOOL bReadAnimations = FALSE;
+
+ rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+ nStmPos = rIStm.Tell();
+ rIStm >> nAnimMagic1 >> nAnimMagic2;
+
+ rAnimation.Clear();
+
+ // Wenn die BitmapEx am Anfang schon gelesen
+ // wurde ( von Graphic ), koennen wir direkt die Animationsbitmaps einlesen
+ if( ( nAnimMagic1 == 0x5344414e ) && ( nAnimMagic2 == 0x494d4931 ) && !rIStm.GetError() )
+ bReadAnimations = TRUE;
+ // ansonsten versuchen wir erstmal die Bitmap(-Ex) zu lesen
+ else
+ {
+ rIStm.Seek( nStmPos );
+ rIStm >> rAnimation.maBitmapEx;
+ nStmPos = rIStm.Tell();
+ rIStm >> nAnimMagic1 >> nAnimMagic2;
+
+ if( ( nAnimMagic1 == 0x5344414e ) && ( nAnimMagic2 == 0x494d4931 ) && !rIStm.GetError() )
+ bReadAnimations = TRUE;
+ else
+ rIStm.Seek( nStmPos );
+ }
+
+ // ggf. Animationsbitmaps lesen
+ if( bReadAnimations )
+ {
+ AnimationBitmap aAnimBmp;
+ BitmapEx aBmpEx;
+ ByteString aDummyStr;
+ UINT32 nTmp32;
+ UINT16 nTmp16;
+ BYTE cTmp;
+
+ do
+ {
+ rIStm >> aAnimBmp.aBmpEx;
+ rIStm >> aAnimBmp.aPosPix;
+ rIStm >> aAnimBmp.aSizePix;
+ rIStm >> rAnimation.maGlobalSize;
+ rIStm >> nTmp16; aAnimBmp.nWait = ( ( 65535 == nTmp16 ) ? ANIMATION_TIMEOUT_ON_CLICK : nTmp16 );
+ rIStm >> nTmp16; aAnimBmp.eDisposal = ( Disposal) nTmp16;
+ rIStm >> cTmp; aAnimBmp.bUserInput = (BOOL) cTmp;
+ rIStm >> nTmp32; rAnimation.mnLoopCount = (USHORT) nTmp32;
+ rIStm >> nTmp32; // unbenutzt
+ rIStm >> nTmp32; // unbenutzt
+ rIStm >> nTmp32; // unbenutzt
+ rIStm >> aDummyStr; // unbenutzt
+ rIStm >> nTmp16; // Rest zu lesen
+
+ rAnimation.Insert( aAnimBmp );
+ }
+ while( nTmp16 && !rIStm.GetError() );
+
+ rAnimation.ResetLoopCount();
+ }
+
+ rIStm.SetNumberFormatInt( nOldFormat );
+
+ return rIStm;
+}
diff --git a/vcl/source/gdi/base14.cxx b/vcl/source/gdi/base14.cxx
new file mode 100644
index 000000000000..83820bc654bf
--- /dev/null
+++ b/vcl/source/gdi/base14.cxx
@@ -0,0 +1,687 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "pdfwriter_impl.hxx"
+#include <rtl/strbuf.hxx>
+
+using namespace vcl;
+using namespace rtl;
+
+OString PDFWriterImpl::BuiltinFont::getNameObject() const
+{
+ OStringBuffer aBuf( 16 );
+ aBuf.append( '/' );
+ const char* pRun = m_pPSName;
+
+ unsigned int nCopied = 0;
+ while( *pRun )
+ {
+ if( *pRun >= 'A' && *pRun <= 'Z' )
+ nCopied = 0;
+ if( nCopied++ < 2 )
+ aBuf.append( *pRun );
+ pRun++;
+ }
+ return aBuf.makeStringAndClear();
+}
+
+const PDFWriterImpl::BuiltinFont PDFWriterImpl::m_aBuiltinFonts[ 14 ] = {
+{ "Courier", // family name
+ "Normal", // style
+ "Courier", // PSName
+ 629, -157, // ascend, descend
+ FAMILY_MODERN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_FIXED, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 600, 600, 600, 600, 600, 600, 600, 600, // 32 - 39
+ 600, 600, 600, 600, 600, 600, 600, 600, // 40 - 47
+ 600, 600, 600, 600, 600, 600, 600, 600, // 48 - 55
+ 600, 600, 600, 600, 600, 600, 600, 600, // 56 - 63
+ 600, 600, 600, 600, 600, 600, 600, 600, // 64 - 71
+ 600, 600, 600, 600, 600, 600, 600, 600, // 72 - 79
+ 600, 600, 600, 600, 600, 600, 600, 600, // 80 - 87
+ 600, 600, 600, 600, 600, 600, 600, 600, // 88 - 95
+ 600, 600, 600, 600, 600, 600, 600, 600, // 96 - 103
+ 600, 600, 600, 600, 600, 600, 600, 600, // 104 - 111
+ 600, 600, 600, 600, 600, 600, 600, 600, // 112 - 119
+ 600, 600, 600, 600, 600, 600, 600, 0, // 120 - 127
+ 600, 0, 600, 600, 600, 600, 600, 600, // 128 - 135
+ 600, 600, 600, 600, 600, 0, 600, 0, // 136 - 143
+ 0, 600, 600, 600, 600, 600, 600, 600, // 144 - 151
+ 600, 600, 600, 600, 600, 0, 600, 600, // 152 - 159
+ 600, 600, 600, 600, 600, 600, 600, 600, // 160 - 167
+ 600, 600, 600, 600, 600, 600, 600, 600, // 168 - 175
+ 600, 600, 600, 600, 600, 600, 600, 600, // 176 - 183
+ 600, 600, 600, 600, 600, 600, 600, 600, // 184 - 191
+ 600, 600, 600, 600, 600, 600, 600, 600, // 192 - 199
+ 600, 600, 600, 600, 600, 600, 600, 600, // 200 - 207
+ 600, 600, 600, 600, 600, 600, 600, 600, // 208 - 215
+ 600, 600, 600, 600, 600, 600, 600, 600, // 216 - 223
+ 600, 600, 600, 600, 600, 600, 600, 600, // 224 - 231
+ 600, 600, 600, 600, 600, 600, 600, 600, // 232 - 239
+ 600, 600, 600, 600, 600, 600, 600, 600, // 240 - 247
+ 600, 600, 600, 600, 600, 600, 600, 600 // 248 - 255
+ }
+},
+
+{ "Courier", // family name
+ "Italic", // style
+ "Courier-Oblique", // PSName
+ 629, -157, // ascend, descend
+ FAMILY_MODERN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_FIXED, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NORMAL, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 600, 600, 600, 600, 600, 600, 600, 600, // 32 - 39
+ 600, 600, 600, 600, 600, 600, 600, 600, // 40 - 47
+ 600, 600, 600, 600, 600, 600, 600, 600, // 48 - 55
+ 600, 600, 600, 600, 600, 600, 600, 600, // 56 - 63
+ 600, 600, 600, 600, 600, 600, 600, 600, // 64 - 71
+ 600, 600, 600, 600, 600, 600, 600, 600, // 72 - 79
+ 600, 600, 600, 600, 600, 600, 600, 600, // 80 - 87
+ 600, 600, 600, 600, 600, 600, 600, 600, // 88 - 95
+ 600, 600, 600, 600, 600, 600, 600, 600, // 96 - 103
+ 600, 600, 600, 600, 600, 600, 600, 600, // 104 - 111
+ 600, 600, 600, 600, 600, 600, 600, 600, // 112 - 119
+ 600, 600, 600, 600, 600, 600, 600, 0, // 120 - 127
+ 600, 0, 600, 600, 600, 600, 600, 600, // 128 - 135
+ 600, 600, 600, 600, 600, 0, 600, 0, // 136 - 143
+ 0, 600, 600, 600, 600, 600, 600, 600, // 144 - 151
+ 600, 600, 600, 600, 600, 0, 600, 600, // 152 - 159
+ 600, 600, 600, 600, 600, 600, 600, 600, // 160 - 167
+ 600, 600, 600, 600, 600, 600, 600, 600, // 168 - 175
+ 600, 600, 600, 600, 600, 600, 600, 600, // 176 - 183
+ 600, 600, 600, 600, 600, 600, 600, 600, // 184 - 191
+ 600, 600, 600, 600, 600, 600, 600, 600, // 192 - 199
+ 600, 600, 600, 600, 600, 600, 600, 600, // 200 - 207
+ 600, 600, 600, 600, 600, 600, 600, 600, // 208 - 215
+ 600, 600, 600, 600, 600, 600, 600, 600, // 216 - 223
+ 600, 600, 600, 600, 600, 600, 600, 600, // 224 - 231
+ 600, 600, 600, 600, 600, 600, 600, 600, // 232 - 239
+ 600, 600, 600, 600, 600, 600, 600, 600, // 240 - 247
+ 600, 600, 600, 600, 600, 600, 600, 600 // 248 - 255
+ }
+},
+
+{ "Courier", // family name
+ "Bold", // style
+ "Courier-Bold", // PSName
+ 629, -157, // ascend, descend
+ FAMILY_MODERN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_FIXED, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_BOLD, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 600, 600, 600, 600, 600, 600, 600, 600, // 32 - 39
+ 600, 600, 600, 600, 600, 600, 600, 600, // 40 - 47
+ 600, 600, 600, 600, 600, 600, 600, 600, // 48 - 55
+ 600, 600, 600, 600, 600, 600, 600, 600, // 56 - 63
+ 600, 600, 600, 600, 600, 600, 600, 600, // 64 - 71
+ 600, 600, 600, 600, 600, 600, 600, 600, // 72 - 79
+ 600, 600, 600, 600, 600, 600, 600, 600, // 80 - 87
+ 600, 600, 600, 600, 600, 600, 600, 600, // 88 - 95
+ 600, 600, 600, 600, 600, 600, 600, 600, // 96 - 103
+ 600, 600, 600, 600, 600, 600, 600, 600, // 104 - 111
+ 600, 600, 600, 600, 600, 600, 600, 600, // 112 - 119
+ 600, 600, 600, 600, 600, 600, 600, 0, // 120 - 127
+ 600, 0, 600, 600, 600, 600, 600, 600, // 128 - 135
+ 600, 600, 600, 600, 600, 0, 600, 0, // 136 - 143
+ 0, 600, 600, 600, 600, 600, 600, 600, // 144 - 151
+ 600, 600, 600, 600, 600, 0, 600, 600, // 152 - 159
+ 600, 600, 600, 600, 600, 600, 600, 600, // 160 - 167
+ 600, 600, 600, 600, 600, 600, 600, 600, // 168 - 175
+ 600, 600, 600, 600, 600, 600, 600, 600, // 176 - 183
+ 600, 600, 600, 600, 600, 600, 600, 600, // 184 - 191
+ 600, 600, 600, 600, 600, 600, 600, 600, // 192 - 199
+ 600, 600, 600, 600, 600, 600, 600, 600, // 200 - 207
+ 600, 600, 600, 600, 600, 600, 600, 600, // 208 - 215
+ 600, 600, 600, 600, 600, 600, 600, 600, // 216 - 223
+ 600, 600, 600, 600, 600, 600, 600, 600, // 224 - 231
+ 600, 600, 600, 600, 600, 600, 600, 600, // 232 - 239
+ 600, 600, 600, 600, 600, 600, 600, 600, // 240 - 247
+ 600, 600, 600, 600, 600, 600, 600, 600 // 248 - 255
+ }
+},
+
+{ "Courier", // family name
+ "Bold Italic", // style
+ "Courier-BoldOblique", // PSName
+ 629, -157, // ascend, descend
+ FAMILY_MODERN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_FIXED, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_BOLD, // weight type
+ ITALIC_NORMAL, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 600, 600, 600, 600, 600, 600, 600, 600, // 32 - 39
+ 600, 600, 600, 600, 600, 600, 600, 600, // 40 - 47
+ 600, 600, 600, 600, 600, 600, 600, 600, // 48 - 55
+ 600, 600, 600, 600, 600, 600, 600, 600, // 56 - 63
+ 600, 600, 600, 600, 600, 600, 600, 600, // 64 - 71
+ 600, 600, 600, 600, 600, 600, 600, 600, // 72 - 79
+ 600, 600, 600, 600, 600, 600, 600, 600, // 80 - 87
+ 600, 600, 600, 600, 600, 600, 600, 600, // 88 - 95
+ 600, 600, 600, 600, 600, 600, 600, 600, // 96 - 103
+ 600, 600, 600, 600, 600, 600, 600, 600, // 104 - 111
+ 600, 600, 600, 600, 600, 600, 600, 600, // 112 - 119
+ 600, 600, 600, 600, 600, 600, 600, 0, // 120 - 127
+ 600, 0, 600, 600, 600, 600, 600, 600, // 128 - 135
+ 600, 600, 600, 600, 600, 0, 600, 0, // 136 - 143
+ 0, 600, 600, 600, 600, 600, 600, 600, // 144 - 151
+ 600, 600, 600, 600, 600, 0, 600, 600, // 152 - 159
+ 600, 600, 600, 600, 600, 600, 600, 600, // 160 - 167
+ 600, 600, 600, 600, 600, 600, 600, 600, // 168 - 175
+ 600, 600, 600, 600, 600, 600, 600, 600, // 176 - 183
+ 600, 600, 600, 600, 600, 600, 600, 600, // 184 - 191
+ 600, 600, 600, 600, 600, 600, 600, 600, // 192 - 199
+ 600, 600, 600, 600, 600, 600, 600, 600, // 200 - 207
+ 600, 600, 600, 600, 600, 600, 600, 600, // 208 - 215
+ 600, 600, 600, 600, 600, 600, 600, 600, // 216 - 223
+ 600, 600, 600, 600, 600, 600, 600, 600, // 224 - 231
+ 600, 600, 600, 600, 600, 600, 600, 600, // 232 - 239
+ 600, 600, 600, 600, 600, 600, 600, 600, // 240 - 247
+ 600, 600, 600, 600, 600, 600, 600, 600 // 248 - 255
+ }
+},
+
+{ "Helvetica", // family name
+ "Normal", // style
+ "Helvetica", // PSName
+ 718, -207, // ascend, descend
+ FAMILY_SWISS, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 278, 278, 355, 556, 556, 889, 667, 191, // 32 - 39
+ 333, 333, 389, 584, 278, 333, 278, 278, // 40 - 47
+ 556, 556, 556, 556, 556, 556, 556, 556, // 48 - 55
+ 556, 556, 278, 278, 584, 584, 584, 556, // 56 - 63
+ 1015, 667, 667, 722, 722, 667, 611, 778, // 64 - 71
+ 722, 278, 500, 667, 556, 833, 722, 778, // 72 - 79
+ 667, 778, 722, 667, 611, 722, 667, 944, // 80 - 87
+ 667, 667, 611, 278, 278, 278, 469, 556, // 88 - 95
+ 333, 556, 556, 500, 556, 556, 278, 556, // 96 - 103
+ 556, 222, 222, 500, 222, 833, 556, 556, // 104 - 111
+ 556, 556, 333, 500, 278, 556, 500, 722, // 112 - 119
+ 500, 500, 500, 334, 260, 334, 584, 0, // 120 - 127
+ 556, 0, 222, 556, 333, 1000, 556, 556, // 128 - 135
+ 333, 1000, 667, 333, 1000, 0, 500, 0, // 136 - 143
+ 0, 222, 222, 333, 333, 350, 556, 1000, // 144 - 151
+ 333, 1000, 500, 333, 944, 0, 500, 667, // 152 - 159
+ 278, 333, 556, 556, 556, 556, 260, 556, // 160 - 167
+ 333, 737, 370, 556, 584, 333, 737, 333, // 168 - 175
+ 400, 584, 333, 333, 333, 556, 537, 278, // 176 - 183
+ 333, 333, 365, 556, 834, 834, 834, 611, // 184 - 191
+ 667, 667, 667, 667, 667, 667, 1000, 722, // 192 - 199
+ 667, 667, 667, 667, 278, 278, 278, 278, // 200 - 207
+ 722, 722, 778, 778, 778, 778, 778, 584, // 208 - 215
+ 778, 722, 722, 722, 722, 667, 667, 611, // 216 - 223
+ 556, 556, 556, 556, 556, 556, 889, 500, // 224 - 231
+ 556, 556, 556, 556, 278, 278, 278, 278, // 232 - 239
+ 556, 556, 556, 556, 556, 556, 556, 584, // 240 - 247
+ 611, 556, 556, 556, 556, 500, 556, 500 // 248 - 255
+ }
+},
+
+{ "Helvetica", // family name
+ "Italic", // style
+ "Helvetica-Oblique", // PSName
+ 718, -207, // ascend, descend
+ FAMILY_SWISS, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NORMAL, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 278, 278, 355, 556, 556, 889, 667, 191, // 32 - 39
+ 333, 333, 389, 584, 278, 333, 278, 278, // 40 - 47
+ 556, 556, 556, 556, 556, 556, 556, 556, // 48 - 55
+ 556, 556, 278, 278, 584, 584, 584, 556, // 56 - 63
+ 1015, 667, 667, 722, 722, 667, 611, 778, // 64 - 71
+ 722, 278, 500, 667, 556, 833, 722, 778, // 72 - 79
+ 667, 778, 722, 667, 611, 722, 667, 944, // 80 - 87
+ 667, 667, 611, 278, 278, 278, 469, 556, // 88 - 95
+ 333, 556, 556, 500, 556, 556, 278, 556, // 96 - 103
+ 556, 222, 222, 500, 222, 833, 556, 556, // 104 - 111
+ 556, 556, 333, 500, 278, 556, 500, 722, // 112 - 119
+ 500, 500, 500, 334, 260, 334, 584, 0, // 120 - 127
+ 556, 0, 222, 556, 333, 1000, 556, 556, // 128 - 135
+ 333, 1000, 667, 333, 1000, 0, 500, 0, // 136 - 143
+ 0, 222, 222, 333, 333, 350, 556, 1000, // 144 - 151
+ 333, 1000, 500, 333, 944, 0, 500, 667, // 152 - 159
+ 278, 333, 556, 556, 556, 556, 260, 556, // 160 - 167
+ 333, 737, 370, 556, 584, 333, 737, 333, // 168 - 175
+ 400, 584, 333, 333, 333, 556, 537, 278, // 176 - 183
+ 333, 333, 365, 556, 834, 834, 834, 611, // 184 - 191
+ 667, 667, 667, 667, 667, 667, 1000, 722, // 192 - 199
+ 667, 667, 667, 667, 278, 278, 278, 278, // 200 - 207
+ 722, 722, 778, 778, 778, 778, 778, 584, // 208 - 215
+ 778, 722, 722, 722, 722, 667, 667, 611, // 216 - 223
+ 556, 556, 556, 556, 556, 556, 889, 500, // 224 - 231
+ 556, 556, 556, 556, 278, 278, 278, 278, // 232 - 239
+ 556, 556, 556, 556, 556, 556, 556, 584, // 240 - 247
+ 611, 556, 556, 556, 556, 500, 556, 500 // 248 - 255
+ }
+},
+
+{ "Helvetica", // family name
+ "Bold", // style
+ "Helvetica-Bold", // PSName
+ 718, -207, // ascend, descend
+ FAMILY_SWISS, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_BOLD, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 278, 333, 474, 556, 556, 889, 722, 238, // 32 - 39
+ 333, 333, 389, 584, 278, 333, 278, 278, // 40 - 47
+ 556, 556, 556, 556, 556, 556, 556, 556, // 48 - 55
+ 556, 556, 333, 333, 584, 584, 584, 611, // 56 - 63
+ 975, 722, 722, 722, 722, 667, 611, 778, // 64 - 71
+ 722, 278, 556, 722, 611, 833, 722, 778, // 72 - 79
+ 667, 778, 722, 667, 611, 722, 667, 944, // 80 - 87
+ 667, 667, 611, 333, 278, 333, 584, 556, // 88 - 95
+ 333, 556, 611, 556, 611, 556, 333, 611, // 96 - 103
+ 611, 278, 278, 556, 278, 889, 611, 611, // 104 - 111
+ 611, 611, 389, 556, 333, 611, 556, 778, // 112 - 119
+ 556, 556, 500, 389, 280, 389, 584, 0, // 120 - 127
+ 556, 0, 278, 556, 500, 1000, 556, 556, // 128 - 135
+ 333, 1000, 667, 333, 1000, 0, 500, 0, // 136 - 143
+ 0, 278, 278, 500, 500, 350, 556, 1000, // 144 - 151
+ 333, 1000, 556, 333, 944, 0, 500, 667, // 152 - 159
+ 278, 333, 556, 556, 556, 556, 280, 556, // 160 - 167
+ 333, 737, 370, 556, 584, 333, 737, 333, // 168 - 175
+ 400, 584, 333, 333, 333, 611, 556, 278, // 176 - 183
+ 333, 333, 365, 556, 834, 834, 834, 611, // 184 - 191
+ 722, 722, 722, 722, 722, 722, 1000, 722, // 192 - 199
+ 667, 667, 667, 667, 278, 278, 278, 278, // 200 - 207
+ 722, 722, 778, 778, 778, 778, 778, 584, // 208 - 215
+ 778, 722, 722, 722, 722, 667, 667, 611, // 216 - 223
+ 556, 556, 556, 556, 556, 556, 889, 556, // 224 - 231
+ 556, 556, 556, 556, 278, 278, 278, 278, // 232 - 239
+ 611, 611, 611, 611, 611, 611, 611, 584, // 240 - 247
+ 611, 611, 611, 611, 611, 556, 611, 556 // 248 - 255
+ }
+},
+
+{ "Helvetica", // family name
+ "Bold Italic", // style
+ "Helvetica-BoldOblique", // PSName
+ 718, -207, // ascend, descend
+ FAMILY_SWISS, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_BOLD, // weight type
+ ITALIC_NORMAL, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 278, 333, 474, 556, 556, 889, 722, 238, // 32 - 39
+ 333, 333, 389, 584, 278, 333, 278, 278, // 40 - 47
+ 556, 556, 556, 556, 556, 556, 556, 556, // 48 - 55
+ 556, 556, 333, 333, 584, 584, 584, 611, // 56 - 63
+ 975, 722, 722, 722, 722, 667, 611, 778, // 64 - 71
+ 722, 278, 556, 722, 611, 833, 722, 778, // 72 - 79
+ 667, 778, 722, 667, 611, 722, 667, 944, // 80 - 87
+ 667, 667, 611, 333, 278, 333, 584, 556, // 88 - 95
+ 333, 556, 611, 556, 611, 556, 333, 611, // 96 - 103
+ 611, 278, 278, 556, 278, 889, 611, 611, // 104 - 111
+ 611, 611, 389, 556, 333, 611, 556, 778, // 112 - 119
+ 556, 556, 500, 389, 280, 389, 584, 0, // 120 - 127
+ 556, 0, 278, 556, 500, 1000, 556, 556, // 128 - 135
+ 333, 1000, 667, 333, 1000, 0, 500, 0, // 136 - 143
+ 0, 278, 278, 500, 500, 350, 556, 1000, // 144 - 151
+ 333, 1000, 556, 333, 944, 0, 500, 667, // 152 - 159
+ 278, 333, 556, 556, 556, 556, 280, 556, // 160 - 167
+ 333, 737, 370, 556, 584, 333, 737, 333, // 168 - 175
+ 400, 584, 333, 333, 333, 611, 556, 278, // 176 - 183
+ 333, 333, 365, 556, 834, 834, 834, 611, // 184 - 191
+ 722, 722, 722, 722, 722, 722, 1000, 722, // 192 - 199
+ 667, 667, 667, 667, 278, 278, 278, 278, // 200 - 207
+ 722, 722, 778, 778, 778, 778, 778, 584, // 208 - 215
+ 778, 722, 722, 722, 722, 667, 667, 611, // 216 - 223
+ 556, 556, 556, 556, 556, 556, 889, 556, // 224 - 231
+ 556, 556, 556, 556, 278, 278, 278, 278, // 232 - 239
+ 611, 611, 611, 611, 611, 611, 611, 584, // 240 - 247
+ 611, 611, 611, 611, 611, 556, 611, 556 // 248 - 255
+ }
+},
+
+{ "Times", // family name
+ "Normal", // style
+ "Times-Roman", // PSName
+ 683, -217, // ascend, descend
+ FAMILY_ROMAN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 250, 333, 408, 500, 500, 833, 778, 180, // 32 - 39
+ 333, 333, 500, 564, 250, 333, 250, 278, // 40 - 47
+ 500, 500, 500, 500, 500, 500, 500, 500, // 48 - 55
+ 500, 500, 278, 278, 564, 564, 564, 444, // 56 - 63
+ 921, 722, 667, 667, 722, 611, 556, 722, // 64 - 71
+ 722, 333, 389, 722, 611, 889, 722, 722, // 72 - 79
+ 556, 722, 667, 556, 611, 722, 722, 944, // 80 - 87
+ 722, 722, 611, 333, 278, 333, 469, 500, // 88 - 95
+ 333, 444, 500, 444, 500, 444, 333, 500, // 96 - 103
+ 500, 278, 278, 500, 278, 778, 500, 500, // 104 - 111
+ 500, 500, 333, 389, 278, 500, 500, 722, // 112 - 119
+ 500, 500, 444, 480, 200, 480, 541, 0, // 120 - 127
+ 500, 0, 333, 500, 444, 1000, 500, 500, // 128 - 135
+ 333, 1000, 556, 333, 889, 0, 444, 0, // 136 - 143
+ 0, 333, 333, 444, 444, 350, 500, 1000, // 144 - 151
+ 333, 980, 389, 333, 722, 0, 444, 722, // 152 - 159
+ 250, 333, 500, 500, 500, 500, 200, 500, // 160 - 167
+ 333, 760, 276, 500, 564, 333, 760, 333, // 168 - 175
+ 400, 564, 300, 300, 333, 500, 453, 250, // 176 - 183
+ 333, 300, 310, 500, 750, 750, 750, 444, // 184 - 191
+ 722, 722, 722, 722, 722, 722, 889, 667, // 192 - 199
+ 611, 611, 611, 611, 333, 333, 333, 333, // 200 - 207
+ 722, 722, 722, 722, 722, 722, 722, 564, // 208 - 215
+ 722, 722, 722, 722, 722, 722, 556, 500, // 216 - 223
+ 444, 444, 444, 444, 444, 444, 667, 444, // 224 - 231
+ 444, 444, 444, 444, 278, 278, 278, 278, // 232 - 239
+ 500, 500, 500, 500, 500, 500, 500, 564, // 240 - 247
+ 500, 500, 500, 500, 500, 500, 500, 500 // 248 - 255
+ }
+},
+
+{ "Times", // family name
+ "Italic", // style
+ "Times-Italic", // PSName
+ 683, -217, // ascend, descend
+ FAMILY_ROMAN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NORMAL, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 250, 333, 420, 500, 500, 833, 778, 214, // 32 - 39
+ 333, 333, 500, 675, 250, 333, 250, 278, // 40 - 47
+ 500, 500, 500, 500, 500, 500, 500, 500, // 48 - 55
+ 500, 500, 333, 333, 675, 675, 675, 500, // 56 - 63
+ 920, 611, 611, 667, 722, 611, 611, 722, // 64 - 71
+ 722, 333, 444, 667, 556, 833, 667, 722, // 72 - 79
+ 611, 722, 611, 500, 556, 722, 611, 833, // 80 - 87
+ 611, 556, 556, 389, 278, 389, 422, 500, // 88 - 95
+ 333, 500, 500, 444, 500, 444, 278, 500, // 96 - 103
+ 500, 278, 278, 444, 278, 722, 500, 500, // 104 - 111
+ 500, 500, 389, 389, 278, 500, 444, 667, // 112 - 119
+ 444, 444, 389, 400, 275, 400, 541, 0, // 120 - 127
+ 500, 0, 333, 500, 556, 889, 500, 500, // 128 - 135
+ 333, 1000, 500, 333, 944, 0, 389, 0, // 136 - 143
+ 0, 333, 333, 556, 556, 350, 500, 889, // 144 - 151
+ 333, 980, 389, 333, 667, 0, 389, 556, // 152 - 159
+ 250, 389, 500, 500, 500, 500, 275, 500, // 160 - 167
+ 333, 760, 276, 500, 675, 333, 760, 333, // 168 - 175
+ 400, 675, 300, 300, 333, 500, 523, 250, // 176 - 183
+ 333, 300, 310, 500, 750, 750, 750, 500, // 184 - 191
+ 611, 611, 611, 611, 611, 611, 889, 667, // 192 - 199
+ 611, 611, 611, 611, 333, 333, 333, 333, // 200 - 207
+ 722, 667, 722, 722, 722, 722, 722, 675, // 208 - 215
+ 722, 722, 722, 722, 722, 556, 611, 500, // 216 - 223
+ 500, 500, 500, 500, 500, 500, 667, 444, // 224 - 231
+ 444, 444, 444, 444, 278, 278, 278, 278, // 232 - 239
+ 500, 500, 500, 500, 500, 500, 500, 675, // 240 - 247
+ 500, 500, 500, 500, 500, 444, 500, 444 // 248 - 255
+ }
+},
+
+{ "Times", // family name
+ "Bold", // style
+ "Times-Bold", // PSName
+ 683, -217, // ascend, descend
+ FAMILY_ROMAN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_BOLD, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 250, 333, 555, 500, 500, 1000, 833, 278, // 32 - 39
+ 333, 333, 500, 570, 250, 333, 250, 278, // 40 - 47
+ 500, 500, 500, 500, 500, 500, 500, 500, // 48 - 55
+ 500, 500, 333, 333, 570, 570, 570, 500, // 56 - 63
+ 930, 722, 667, 722, 722, 667, 611, 778, // 64 - 71
+ 778, 389, 500, 778, 667, 944, 722, 778, // 72 - 79
+ 611, 778, 722, 556, 667, 722, 722, 1000, // 80 - 87
+ 722, 722, 667, 333, 278, 333, 581, 500, // 88 - 95
+ 333, 500, 556, 444, 556, 444, 333, 500, // 96 - 103
+ 556, 278, 333, 556, 278, 833, 556, 500, // 104 - 111
+ 556, 556, 444, 389, 333, 556, 500, 722, // 112 - 119
+ 500, 500, 444, 394, 220, 394, 520, 0, // 120 - 127
+ 500, 0, 333, 500, 500, 1000, 500, 500, // 128 - 135
+ 333, 1000, 556, 333, 1000, 0, 444, 0, // 136 - 143
+ 0, 333, 333, 500, 500, 350, 500, 1000, // 144 - 151
+ 333, 1000, 389, 333, 722, 0, 444, 722, // 152 - 159
+ 250, 333, 500, 500, 500, 500, 220, 500, // 160 - 167
+ 333, 747, 300, 500, 570, 333, 747, 333, // 168 - 175
+ 400, 570, 300, 300, 333, 556, 540, 250, // 176 - 183
+ 333, 300, 330, 500, 750, 750, 750, 500, // 184 - 191
+ 722, 722, 722, 722, 722, 722, 1000, 722, // 192 - 199
+ 667, 667, 667, 667, 389, 389, 389, 389, // 200 - 207
+ 722, 722, 778, 778, 778, 778, 778, 570, // 208 - 215
+ 778, 722, 722, 722, 722, 722, 611, 556, // 216 - 223
+ 500, 500, 500, 500, 500, 500, 722, 444, // 224 - 231
+ 444, 444, 444, 444, 278, 278, 278, 278, // 232 - 239
+ 500, 556, 500, 500, 500, 500, 500, 570, // 240 - 247
+ 500, 556, 556, 556, 556, 500, 556, 500 // 248 - 255
+ }
+},
+
+{ "Times", // family name
+ "Bold Italic", // style
+ "Times-BoldItalic", // PSName
+ 683, -217, // ascend, descend
+ FAMILY_ROMAN, // family style
+ RTL_TEXTENCODING_MS_1252, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_BOLD, // weight type
+ ITALIC_NORMAL, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 250, 389, 555, 500, 500, 833, 778, 278, // 32 - 39
+ 333, 333, 500, 570, 250, 333, 250, 278, // 40 - 47
+ 500, 500, 500, 500, 500, 500, 500, 500, // 48 - 55
+ 500, 500, 333, 333, 570, 570, 570, 500, // 56 - 63
+ 832, 667, 667, 667, 722, 667, 667, 722, // 64 - 71
+ 778, 389, 500, 667, 611, 889, 722, 722, // 72 - 79
+ 611, 722, 667, 556, 611, 722, 667, 889, // 80 - 87
+ 667, 611, 611, 333, 278, 333, 570, 500, // 88 - 95
+ 333, 500, 500, 444, 500, 444, 333, 500, // 96 - 103
+ 556, 278, 278, 500, 278, 778, 556, 500, // 104 - 111
+ 500, 500, 389, 389, 278, 556, 444, 667, // 112 - 119
+ 500, 444, 389, 348, 220, 348, 570, 0, // 120 - 127
+ 500, 0, 333, 500, 500, 1000, 500, 500, // 128 - 135
+ 333, 1000, 556, 333, 944, 0, 389, 0, // 136 - 143
+ 0, 333, 333, 500, 500, 350, 500, 1000, // 144 - 151
+ 333, 1000, 389, 333, 722, 0, 389, 611, // 152 - 159
+ 250, 389, 500, 500, 500, 500, 220, 500, // 160 - 167
+ 333, 747, 266, 500, 606, 333, 747, 333, // 168 - 175
+ 400, 570, 300, 300, 333, 576, 500, 250, // 176 - 183
+ 333, 300, 300, 500, 750, 750, 750, 500, // 184 - 191
+ 667, 667, 667, 667, 667, 667, 944, 667, // 192 - 199
+ 667, 667, 667, 667, 389, 389, 389, 389, // 200 - 207
+ 722, 722, 722, 722, 722, 722, 722, 570, // 208 - 215
+ 722, 722, 722, 722, 722, 611, 611, 500, // 216 - 223
+ 500, 500, 500, 500, 500, 500, 722, 444, // 224 - 231
+ 444, 444, 444, 444, 278, 278, 278, 278, // 232 - 239
+ 500, 556, 500, 500, 500, 500, 500, 570, // 240 - 247
+ 500, 556, 556, 556, 556, 444, 500, 444 // 248 - 255
+ }
+},
+
+{ "Symbol", // family name
+ "Normal", // style
+ "Symbol", // PSName
+ 1010, -293, // ascend, descend
+ FAMILY_DONTKNOW, // family style
+ RTL_TEXTENCODING_ADOBE_SYMBOL, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 250, 333, 713, 500, 549, 833, 778, 439, // 32 - 39
+ 333, 333, 500, 549, 250, 549, 250, 278, // 40 - 47
+ 500, 500, 500, 500, 500, 500, 500, 500, // 48 - 55
+ 500, 500, 278, 278, 549, 549, 549, 444, // 56 - 63
+ 549, 722, 667, 722, 612, 611, 763, 603, // 64 - 71
+ 722, 333, 631, 722, 686, 889, 722, 722, // 72 - 79
+ 768, 741, 556, 592, 611, 690, 439, 768, // 80 - 87
+ 645, 795, 611, 333, 863, 333, 658, 500, // 88 - 95
+ 500, 631, 549, 549, 494, 439, 521, 411, // 96 - 103
+ 603, 329, 603, 549, 549, 576, 521, 549, // 104 - 111
+ 549, 521, 549, 603, 439, 576, 713, 686, // 112 - 119
+ 493, 686, 494, 480, 200, 480, 549, 0, // 120 - 127
+ 0, 0, 0, 0, 0, 0, 0, 0, // 128 - 135
+ 0, 0, 0, 0, 0, 0, 0, 0, // 136 - 143
+ 0, 0, 0, 0, 0, 0, 0, 0, // 144 - 151
+ 0, 0, 0, 0, 0, 0, 0, 0, // 152 - 159
+ 750, 620, 247, 549, 167, 713, 500, 753, // 160 - 167
+ 753, 753, 753, 1042, 987, 603, 987, 603, // 168 - 175
+ 400, 549, 411, 549, 549, 713, 494, 460, // 176 - 183
+ 549, 549, 549, 549, 1000, 603, 1000, 658, // 184 - 191
+ 823, 686, 795, 987, 768, 768, 823, 768, // 192 - 199
+ 768, 713, 713, 713, 713, 713, 713, 713, // 200 - 207
+ 768, 713, 790, 790, 890, 823, 549, 250, // 208 - 215
+ 713, 603, 603, 1042, 987, 603, 987, 603, // 216 - 223
+ 494, 329, 790, 790, 786, 713, 384, 384, // 224 - 231
+ 384, 384, 384, 384, 494, 494, 494, 494, // 232 - 239
+ 0, 329, 274, 686, 686, 686, 384, 384, // 240 - 247
+ 384, 384, 384, 384, 494, 494, 494, 0 // 248 - 255
+ }
+},
+
+{ "ZapfDingbats", // family name
+ "Normal", // style
+ "ZapfDingbats", // PSName
+ 820, -143, // ascend, descend
+ FAMILY_DONTKNOW, // family style
+ RTL_TEXTENCODING_ADOBE_DINGBATS, // charset
+ PITCH_VARIABLE, // pitch
+ WIDTH_NORMAL, // width type
+ WEIGHT_NORMAL, // weight type
+ ITALIC_NONE, // italic type
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7
+ 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23
+ 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31
+ 278, 974, 961, 974, 980, 719, 789, 790, // 32 - 39
+ 791, 690, 960, 939, 549, 855, 911, 933, // 40 - 47
+ 911, 945, 974, 755, 846, 762, 761, 571, // 48 - 55
+ 677, 763, 760, 759, 754, 494, 552, 537, // 56 - 63
+ 577, 692, 786, 788, 788, 790, 793, 794, // 64 - 71
+ 816, 823, 789, 841, 823, 833, 816, 831, // 72 - 79
+ 923, 744, 723, 749, 790, 792, 695, 776, // 80 - 87
+ 768, 792, 759, 707, 708, 682, 701, 826, // 88 - 95
+ 815, 789, 789, 707, 687, 696, 689, 786, // 96 - 103
+ 787, 713, 791, 785, 791, 873, 761, 762, // 104 - 111
+ 762, 759, 759, 892, 892, 788, 784, 438, // 112 - 119
+ 138, 277, 415, 392, 392, 668, 668, 0, // 120 - 127
+ 390, 390, 317, 317, 276, 276, 509, 509, // 128 - 135
+ 410, 410, 234, 234, 334, 334, 0, 0, // 136 - 143
+ 0, 0, 0, 0, 0, 0, 0, 0, // 144 - 151
+ 0, 0, 0, 0, 0, 0, 0, 0, // 152 - 159
+ 0, 732, 544, 544, 910, 667, 760, 760, // 160 - 167
+ 776, 595, 694, 626, 788, 788, 788, 788, // 168 - 175
+ 788, 788, 788, 788, 788, 788, 788, 788, // 176 - 183
+ 788, 788, 788, 788, 788, 788, 788, 788, // 184 - 191
+ 788, 788, 788, 788, 788, 788, 788, 788, // 192 - 199
+ 788, 788, 788, 788, 788, 788, 788, 788, // 200 - 207
+ 788, 788, 788, 788, 894, 838, 1016, 458, // 208 - 215
+ 748, 924, 748, 918, 927, 928, 928, 834, // 216 - 223
+ 873, 828, 924, 924, 917, 930, 931, 463, // 224 - 231
+ 883, 836, 836, 867, 867, 696, 696, 874, // 232 - 239
+ 0, 874, 760, 946, 771, 865, 771, 888, // 240 - 247
+ 967, 888, 831, 873, 927, 970, 918, 0 // 248 - 255
+ }
+}
+
+};
+
diff --git a/vcl/source/gdi/bitmap.cxx b/vcl/source/gdi/bitmap.cxx
new file mode 100644
index 000000000000..074935086b0b
--- /dev/null
+++ b/vcl/source/gdi/bitmap.cxx
@@ -0,0 +1,1968 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <rtl/crc.h>
+#include <vcl/salbtype.hxx>
+#include <tools/stream.hxx>
+#include <vcl/bmpacc.hxx>
+#include <tools/poly.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/salbmp.hxx>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/image.hxx>
+
+// ----------
+// - Bitmap -
+// ----------
+
+Bitmap::Bitmap() :
+ mpImpBmp( NULL )
+{
+}
+
+// ------------------------------------------------------------------
+
+Bitmap::Bitmap( const ResId& rResId ) :
+ mpImpBmp( NULL )
+{
+ const BitmapEx aBmpEx( rResId );
+
+ if( !aBmpEx.IsEmpty() )
+ *this = aBmpEx.GetBitmap();
+}
+
+// ------------------------------------------------------------------
+
+Bitmap::Bitmap( const Bitmap& rBitmap ) :
+ maPrefMapMode ( rBitmap.maPrefMapMode ),
+ maPrefSize ( rBitmap.maPrefSize )
+{
+ mpImpBmp = rBitmap.mpImpBmp;
+
+ if ( mpImpBmp )
+ mpImpBmp->ImplIncRefCount();
+}
+
+// ------------------------------------------------------------------
+
+Bitmap::Bitmap( SalBitmap* pSalBitmap )
+{
+ mpImpBmp = new ImpBitmap();
+ mpImpBmp->ImplSetSalBitmap( pSalBitmap );
+ maPrefMapMode = MapMode( MAP_PIXEL );
+ maPrefSize = mpImpBmp->ImplGetSize();
+}
+
+// ------------------------------------------------------------------
+
+Bitmap::Bitmap( const Size& rSizePixel, USHORT nBitCount, const BitmapPalette* pPal )
+{
+ if( rSizePixel.Width() && rSizePixel.Height() )
+ {
+ BitmapPalette aPal;
+ BitmapPalette* pRealPal = NULL;
+
+ if( nBitCount <= 8 )
+ {
+ if( !pPal )
+ {
+ if( 1 == nBitCount )
+ {
+ aPal.SetEntryCount( 2 );
+ aPal[ 0 ] = Color( COL_BLACK );
+ aPal[ 1 ] = Color( COL_WHITE );
+ }
+ else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) )
+ {
+ aPal.SetEntryCount( 1 << nBitCount );
+ aPal[ 0 ] = Color( COL_BLACK );
+ aPal[ 1 ] = Color( COL_BLUE );
+ aPal[ 2 ] = Color( COL_GREEN );
+ aPal[ 3 ] = Color( COL_CYAN );
+ aPal[ 4 ] = Color( COL_RED );
+ aPal[ 5 ] = Color( COL_MAGENTA );
+ aPal[ 6 ] = Color( COL_BROWN );
+ aPal[ 7 ] = Color( COL_GRAY );
+ aPal[ 8 ] = Color( COL_LIGHTGRAY );
+ aPal[ 9 ] = Color( COL_LIGHTBLUE );
+ aPal[ 10 ] = Color( COL_LIGHTGREEN );
+ aPal[ 11 ] = Color( COL_LIGHTCYAN );
+ aPal[ 12 ] = Color( COL_LIGHTRED );
+ aPal[ 13 ] = Color( COL_LIGHTMAGENTA );
+ aPal[ 14 ] = Color( COL_YELLOW );
+ aPal[ 15 ] = Color( COL_WHITE );
+
+ // Dither-Palette erzeugen
+ if( 8 == nBitCount )
+ {
+ USHORT nActCol = 16;
+
+ for( USHORT nB = 0; nB < 256; nB += 51 )
+ for( USHORT nG = 0; nG < 256; nG += 51 )
+ for( USHORT nR = 0; nR < 256; nR += 51 )
+ aPal[ nActCol++ ] = BitmapColor( (BYTE) nR, (BYTE) nG, (BYTE) nB );
+
+ // Standard-Office-Farbe setzen
+ aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
+ }
+ }
+ }
+ else
+ pRealPal = (BitmapPalette*) pPal;
+ }
+
+ mpImpBmp = new ImpBitmap;
+ mpImpBmp->ImplCreate( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal );
+ }
+ else
+ mpImpBmp = NULL;
+}
+
+// ------------------------------------------------------------------
+
+Bitmap::~Bitmap()
+{
+ ImplReleaseRef();
+}
+
+// ------------------------------------------------------------------
+
+const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
+{
+ static BitmapPalette aGreyPalette2;
+ static BitmapPalette aGreyPalette4;
+ static BitmapPalette aGreyPalette16;
+ static BitmapPalette aGreyPalette256;
+
+ // create greyscale palette with 2, 4, 16 or 256 entries
+ if( 2 == nEntries || 4 == nEntries || 16 == nEntries || 256 == nEntries )
+ {
+ if( 2 == nEntries )
+ {
+ if( !aGreyPalette2.GetEntryCount() )
+ {
+ aGreyPalette2.SetEntryCount( 2 );
+ aGreyPalette2[ 0 ] = BitmapColor( 0, 0, 0 );
+ aGreyPalette2[ 1 ] = BitmapColor( 255, 255, 255 );
+ }
+
+ return aGreyPalette2;
+ }
+ else if( 4 == nEntries )
+ {
+ if( !aGreyPalette4.GetEntryCount() )
+ {
+ aGreyPalette4.SetEntryCount( 4 );
+ aGreyPalette4[ 0 ] = BitmapColor( 0, 0, 0 );
+ aGreyPalette4[ 1 ] = BitmapColor( 85, 85, 85 );
+ aGreyPalette4[ 2 ] = BitmapColor( 170, 170, 170 );
+ aGreyPalette4[ 3 ] = BitmapColor( 255, 255, 255 );
+ }
+
+ return aGreyPalette4;
+ }
+ else if( 16 == nEntries )
+ {
+ if( !aGreyPalette16.GetEntryCount() )
+ {
+ BYTE cGrey = 0, cGreyInc = 17;
+
+ aGreyPalette16.SetEntryCount( 16 );
+
+ for( USHORT i = 0; i < 16; i++, cGrey = sal::static_int_cast<BYTE>(cGrey + cGreyInc) )
+ aGreyPalette16[ i ] = BitmapColor( cGrey, cGrey, cGrey );
+ }
+
+ return aGreyPalette16;
+ }
+ else
+ {
+ if( !aGreyPalette256.GetEntryCount() )
+ {
+ aGreyPalette256.SetEntryCount( 256 );
+
+ for( USHORT i = 0; i < 256; i++ )
+ aGreyPalette256[ i ] = BitmapColor( (BYTE) i, (BYTE) i, (BYTE) i );
+ }
+
+ return aGreyPalette256;
+ }
+ }
+ else
+ {
+ DBG_ERROR( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" );
+ return aGreyPalette2;
+ }
+}
+
+// ------------------------------------------------------------------
+
+bool BitmapPalette::IsGreyPalette() const
+{
+ // TODO: add an IsGreyPalette flag to BitmapPalette
+ // TODO: unless this causes problems binary compatibility
+ const int nEntryCount = GetEntryCount();
+ if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
+ return true;
+ const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
+ if( rGreyPalette == *this )
+ return true;
+ // TODO: is it worth to compare the entries?
+ return false;
+}
+
+// ------------------------------------------------------------------
+
+Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
+{
+ maPrefSize = rBitmap.maPrefSize;
+ maPrefMapMode = rBitmap.maPrefMapMode;
+
+ if ( rBitmap.mpImpBmp )
+ rBitmap.mpImpBmp->ImplIncRefCount();
+
+ ImplReleaseRef();
+ mpImpBmp = rBitmap.mpImpBmp;
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::IsEqual( const Bitmap& rBmp ) const
+{
+ return( IsSameInstance( rBmp ) ||
+ ( rBmp.GetSizePixel() == GetSizePixel() &&
+ rBmp.GetBitCount() == GetBitCount() &&
+ rBmp.GetChecksum() == GetChecksum() ) );
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::SetEmpty()
+{
+ maPrefMapMode = MapMode();
+ maPrefSize = Size();
+
+ ImplReleaseRef();
+ mpImpBmp = NULL;
+}
+
+// ------------------------------------------------------------------
+
+Size Bitmap::GetSizePixel() const
+{
+ return( mpImpBmp ? mpImpBmp->ImplGetSize() : Size() );
+}
+// ------------------------------------------------------------------
+
+void Bitmap::SetSizePixel( const Size& rNewSize )
+{
+ Scale( rNewSize );
+}
+
+// ------------------------------------------------------------------
+
+Size Bitmap::GetSourceSizePixel() const
+{
+ return( mpImpBmp ? mpImpBmp->ImplGetSourceSize() : Size() );
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::SetSourceSizePixel( const Size& rSize)
+{
+ if( mpImpBmp )
+ mpImpBmp->ImplSetSourceSize( rSize);
+}
+
+// ------------------------------------------------------------------
+
+USHORT Bitmap::GetBitCount() const
+{
+ return( mpImpBmp ? mpImpBmp->ImplGetBitCount() : 0 );
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::HasGreyPalette() const
+{
+ const USHORT nBitCount = GetBitCount();
+ BOOL bRet = FALSE;
+
+ if( 1 == nBitCount )
+ {
+ BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess();
+
+ if( pRAcc )
+ {
+ const BitmapColor& rCol0( pRAcc->GetPaletteColor( 0 ) );
+ const BitmapColor& rCol1( pRAcc->GetPaletteColor( 1 ) );
+ if( rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() &&
+ rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue() )
+ {
+ bRet = TRUE;
+ }
+ ( (Bitmap*) this )->ReleaseAccess( pRAcc );
+ }
+ else
+ bRet = TRUE;
+ }
+ else if( 4 == nBitCount || 8 == nBitCount )
+ {
+ BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess();
+
+ if( pRAcc )
+ {
+ if( pRAcc->HasPalette() && ( (BitmapPalette&) pRAcc->GetPalette() == GetGreyPalette( 1 << nBitCount ) ) )
+ bRet = TRUE;
+
+ ( (Bitmap*) this )->ReleaseAccess( pRAcc );
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+ULONG Bitmap::GetChecksum() const
+{
+ ULONG nRet = 0UL;
+
+ if( mpImpBmp )
+ {
+ nRet = mpImpBmp->ImplGetChecksum();
+
+ if( !nRet )
+ {
+ BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess();
+
+ if( pRAcc && pRAcc->Width() && pRAcc->Height() )
+ {
+ sal_uInt32 nCrc = 0;
+ SVBT32 aBT32;
+
+ pRAcc->ImplZeroInitUnusedBits();
+
+ UInt32ToSVBT32( pRAcc->Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pRAcc->Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pRAcc->GetBitCount(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pRAcc->GetColorMask().GetRedMask(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pRAcc->GetColorMask().GetGreenMask(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pRAcc->GetColorMask().GetBlueMask(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ if( pRAcc->HasPalette() )
+ {
+ nCrc = rtl_crc32( nCrc, pRAcc->GetPalette().ImplGetColorBuffer(),
+ pRAcc->GetPaletteEntryCount() * sizeof( BitmapColor ) );
+ }
+
+ nCrc = rtl_crc32( nCrc, pRAcc->GetBuffer(), pRAcc->GetScanlineSize() * pRAcc->Height() );
+
+ mpImpBmp->ImplSetChecksum( nRet = nCrc );
+ }
+
+ if (pRAcc) ( (Bitmap*) this )->ReleaseAccess( pRAcc );
+ }
+ }
+
+ return nRet;
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::ImplReleaseRef()
+{
+ if( mpImpBmp )
+ {
+ if( mpImpBmp->ImplGetRefCount() > 1UL )
+ mpImpBmp->ImplDecRefCount();
+ else
+ {
+ delete mpImpBmp;
+ mpImpBmp = NULL;
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::ImplMakeUnique()
+{
+ if( mpImpBmp && mpImpBmp->ImplGetRefCount() > 1UL )
+ {
+ ImpBitmap* pOldImpBmp = mpImpBmp;
+
+ pOldImpBmp->ImplDecRefCount();
+
+ mpImpBmp = new ImpBitmap;
+ mpImpBmp->ImplCreate( *pOldImpBmp );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::ImplAssignWithSize( const Bitmap& rBitmap )
+{
+ const Size aOldSizePix( GetSizePixel() );
+ const Size aNewSizePix( rBitmap.GetSizePixel() );
+ const MapMode aOldMapMode( maPrefMapMode );
+ Size aNewPrefSize;
+
+ if( ( aOldSizePix != aNewSizePix ) && aOldSizePix.Width() && aOldSizePix.Height() )
+ {
+ aNewPrefSize.Width() = FRound( maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width() );
+ aNewPrefSize.Height() = FRound( maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height() );
+ }
+ else
+ aNewPrefSize = maPrefSize;
+
+ *this = rBitmap;
+
+ maPrefSize = aNewPrefSize;
+ maPrefMapMode = aOldMapMode;
+}
+
+// ------------------------------------------------------------------
+
+ImpBitmap* Bitmap::ImplGetImpBitmap() const
+{
+ return mpImpBmp;
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::ImplSetImpBitmap( ImpBitmap* pImpBmp )
+{
+ if( pImpBmp != mpImpBmp )
+ {
+ ImplReleaseRef();
+ mpImpBmp = pImpBmp;
+ }
+}
+
+// ------------------------------------------------------------------
+
+BitmapReadAccess* Bitmap::AcquireReadAccess()
+{
+ BitmapReadAccess* pReadAccess = new BitmapReadAccess( *this );
+
+ if( !*pReadAccess )
+ {
+ delete pReadAccess;
+ pReadAccess = NULL;
+ }
+
+ return pReadAccess;
+}
+
+// ------------------------------------------------------------------
+
+BitmapWriteAccess* Bitmap::AcquireWriteAccess()
+{
+ BitmapWriteAccess* pWriteAccess = new BitmapWriteAccess( *this );
+
+ if( !*pWriteAccess )
+ {
+ delete pWriteAccess;
+ pWriteAccess = NULL;
+ }
+
+ return pWriteAccess;
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::ReleaseAccess( BitmapReadAccess* pBitmapAccess )
+{
+ delete pBitmapAccess;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Erase( const Color& rFillColor )
+{
+ if( !(*this) )
+ return TRUE;
+
+ BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pWriteAcc )
+ {
+ const ULONG nFormat = pWriteAcc->GetScanlineFormat();
+ BYTE cIndex = 0;
+ BOOL bFast = FALSE;
+
+ switch( nFormat )
+ {
+ case( BMP_FORMAT_1BIT_MSB_PAL ):
+ case( BMP_FORMAT_1BIT_LSB_PAL ):
+ {
+ cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor );
+ cIndex = ( cIndex ? 255 : 0 );
+ bFast = TRUE;
+ }
+ break;
+
+ case( BMP_FORMAT_4BIT_MSN_PAL ):
+ case( BMP_FORMAT_4BIT_LSN_PAL ):
+ {
+ cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor );
+ cIndex = cIndex | ( cIndex << 4 );
+ bFast = TRUE;
+ }
+ break;
+
+ case( BMP_FORMAT_8BIT_PAL ):
+ {
+ cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor );
+ bFast = TRUE;
+ }
+ break;
+
+ case( BMP_FORMAT_24BIT_TC_BGR ):
+ case( BMP_FORMAT_24BIT_TC_RGB ):
+ {
+ if( ( rFillColor.GetRed() == rFillColor.GetGreen() ) &&
+ ( rFillColor.GetRed() == rFillColor.GetBlue() ) )
+ {
+ cIndex = rFillColor.GetRed();
+ bFast = TRUE;
+ }
+ else
+ bFast = FALSE;
+ }
+ break;
+
+ default:
+ bFast = FALSE;
+ break;
+ }
+
+ if( bFast )
+ {
+ const ULONG nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height();
+ memset( pWriteAcc->GetBuffer(), cIndex, nBufSize );
+ }
+ else
+ {
+ Point aTmpPoint;
+ const Rectangle aRect( aTmpPoint, Size( pWriteAcc->Width(), pWriteAcc->Height() ) );
+ pWriteAcc->SetFillColor( rFillColor );
+ pWriteAcc->FillRect( aRect );
+ }
+
+ ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Invert()
+{
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pAcc )
+ {
+ if( pAcc->HasPalette() )
+ {
+ BitmapPalette aBmpPal( pAcc->GetPalette() );
+ const USHORT nCount = aBmpPal.GetEntryCount();
+
+ for( USHORT i = 0; i < nCount; i++ )
+ aBmpPal[ i ].Invert();
+
+ pAcc->SetPalette( aBmpPal );
+ }
+ else
+ {
+ const long nWidth = pAcc->Width();
+ const long nHeight = pAcc->Height();
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ for( long nY = 0L; nY < nHeight; nY++ )
+ pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nX ).Invert() );
+ }
+
+ ReleaseAccess( pAcc );
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Mirror( ULONG nMirrorFlags )
+{
+ BOOL bHorz = ( ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ );
+ BOOL bVert = ( ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT );
+ BOOL bRet = FALSE;
+
+ if( bHorz && !bVert )
+ {
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+
+ if( pAcc )
+ {
+ const long nWidth = pAcc->Width();
+ const long nHeight = pAcc->Height();
+ const long nWidth1 = nWidth - 1L;
+ const long nWidth_2 = nWidth >> 1L;
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L, nOther = nWidth1; nX < nWidth_2; nX++, nOther-- )
+ {
+ const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
+
+ pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nOther ) );
+ pAcc->SetPixel( nY, nOther, aTemp );
+ }
+ }
+
+ ReleaseAccess( pAcc );
+ bRet = TRUE;
+ }
+ }
+ else if( bVert && !bHorz )
+ {
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+
+ if( pAcc )
+ {
+ const long nScanSize = pAcc->GetScanlineSize();
+ BYTE* pBuffer = new BYTE[ nScanSize ];
+ const long nHeight = pAcc->Height();
+ const long nHeight1 = nHeight - 1L;
+ const long nHeight_2 = nHeight >> 1L;
+
+ for( long nY = 0L, nOther = nHeight1; nY < nHeight_2; nY++, nOther-- )
+ {
+ memcpy( pBuffer, pAcc->GetScanline( nY ), nScanSize );
+ memcpy( pAcc->GetScanline( nY ), pAcc->GetScanline( nOther ), nScanSize );
+ memcpy( pAcc->GetScanline( nOther ), pBuffer, nScanSize );
+ }
+
+ delete[] pBuffer;
+ ReleaseAccess( pAcc );
+ bRet = TRUE;
+ }
+ }
+ else if( bHorz && bVert )
+ {
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+
+ if( pAcc )
+ {
+ const long nWidth = pAcc->Width();
+ const long nWidth1 = nWidth - 1L;
+ const long nHeight = pAcc->Height();
+ long nHeight_2 = nHeight >> 1;
+
+ for( long nY = 0L, nOtherY = nHeight - 1L; nY < nHeight_2; nY++, nOtherY-- )
+ {
+ for( long nX = 0L, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX-- )
+ {
+ const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
+
+ pAcc->SetPixel( nY, nX, pAcc->GetPixel( nOtherY, nOtherX ) );
+ pAcc->SetPixel( nOtherY, nOtherX, aTemp );
+ }
+ }
+
+ // ggf. noch mittlere Zeile horizontal spiegeln
+ if( nHeight & 1 )
+ {
+ for( long nX = 0L, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; nX++, nOtherX-- )
+ {
+ const BitmapColor aTemp( pAcc->GetPixel( nHeight_2, nX ) );
+ pAcc->SetPixel( nHeight_2, nX, pAcc->GetPixel( nHeight_2, nOtherX ) );
+ pAcc->SetPixel( nHeight_2, nOtherX, aTemp );
+ }
+ }
+
+ ReleaseAccess( pAcc );
+ bRet = TRUE;
+ }
+ }
+ else
+ bRet = TRUE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Rotate( long nAngle10, const Color& rFillColor )
+{
+ BOOL bRet = FALSE;
+
+ nAngle10 %= 3600L;
+ nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10;
+
+ if( !nAngle10 )
+ bRet = TRUE;
+ else if( 1800L == nAngle10 )
+ bRet = Mirror( BMP_MIRROR_HORZ | BMP_MIRROR_VERT );
+ else
+ {
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ Bitmap aRotatedBmp;
+
+ if( pReadAcc )
+ {
+ const Size aSizePix( GetSizePixel() );
+
+ if( ( 900L == nAngle10 ) || ( 2700L == nAngle10 ) )
+ {
+ const Size aNewSizePix( aSizePix.Height(), aSizePix.Width() );
+ Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = aSizePix.Width();
+ const long nWidth1 = nWidth - 1L;
+ const long nHeight = aSizePix.Height();
+ const long nHeight1 = nHeight - 1L;
+ const long nNewWidth = aNewSizePix.Width();
+ const long nNewHeight = aNewSizePix.Height();
+
+ if( 900L == nAngle10 )
+ {
+ for( long nY = 0L, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX-- )
+ for( long nX = 0L, nOtherY = 0L; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY++, nOtherX ) );
+ }
+ else if( 2700L == nAngle10 )
+ {
+ for( long nY = 0L, nOtherX = 0L; nY < nNewHeight; nY++, nOtherX++ )
+ for( long nX = 0L, nOtherY = nHeight1; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY--, nOtherX ) );
+ }
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ }
+
+ aRotatedBmp = aNewBmp;
+ }
+ else
+ {
+ Point aTmpPoint;
+ Rectangle aTmpRectangle( aTmpPoint, aSizePix );
+ Polygon aPoly( aTmpRectangle );
+ aPoly.Rotate( aTmpPoint, (USHORT) nAngle10 );
+
+ Rectangle aNewBound( aPoly.GetBoundRect() );
+ const Size aNewSizePix( aNewBound.GetSize() );
+ Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const BitmapColor aFillColor( pWriteAcc->GetBestMatchingColor( rFillColor ) );
+ const double fCosAngle = cos( nAngle10 * F_PI1800 );
+ const double fSinAngle = sin( nAngle10 * F_PI1800 );
+ const double fXMin = aNewBound.Left();
+ const double fYMin = aNewBound.Top();
+ const long nWidth = aSizePix.Width();
+ const long nHeight = aSizePix.Height();
+ const long nNewWidth = aNewSizePix.Width();
+ const long nNewHeight = aNewSizePix.Height();
+ long nX;
+ long nY;
+ long nRotX;
+ long nRotY;
+ long nSinY;
+ long nCosY;
+ long* pCosX = new long[ nNewWidth ];
+ long* pSinX = new long[ nNewWidth ];
+ long* pCosY = new long[ nNewHeight ];
+ long* pSinY = new long[ nNewHeight ];
+
+ for ( nX = 0; nX < nNewWidth; nX++ )
+ {
+ const double fTmp = ( fXMin + nX ) * 64.;
+
+ pCosX[ nX ] = FRound( fCosAngle * fTmp );
+ pSinX[ nX ] = FRound( fSinAngle * fTmp );
+ }
+
+ for ( nY = 0; nY < nNewHeight; nY++ )
+ {
+ const double fTmp = ( fYMin + nY ) * 64.;
+
+ pCosY[ nY ] = FRound( fCosAngle * fTmp );
+ pSinY[ nY ] = FRound( fSinAngle * fTmp );
+ }
+
+ for( nY = 0L; nY < nNewHeight; nY++ )
+ {
+ nSinY = pSinY[ nY ];
+ nCosY = pCosY[ nY ];
+
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ {
+ nRotX = ( pCosX[ nX ] - nSinY ) >> 6;
+ nRotY = ( pSinX[ nX ] + nCosY ) >> 6;
+
+ if ( ( nRotX > -1L ) && ( nRotX < nWidth ) && ( nRotY > -1L ) && ( nRotY < nHeight ) )
+ pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nRotY, nRotX ) );
+ else
+ pWriteAcc->SetPixel( nY, nX, aFillColor );
+ }
+ }
+
+ delete[] pSinX;
+ delete[] pCosX;
+ delete[] pSinY;
+ delete[] pCosY;
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ }
+
+ aRotatedBmp = aNewBmp;
+ }
+
+ ReleaseAccess( pReadAcc );
+ }
+
+ if( ( bRet = !!aRotatedBmp ) == TRUE )
+ ImplAssignWithSize( aRotatedBmp );
+ }
+
+ return bRet;
+};
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Crop( const Rectangle& rRectPixel )
+{
+ const Size aSizePix( GetSizePixel() );
+ Rectangle aRect( rRectPixel );
+ BOOL bRet = FALSE;
+
+ aRect.Intersection( Rectangle( Point(), aSizePix ) );
+
+ if( !aRect.IsEmpty() )
+ {
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+
+ if( pReadAcc )
+ {
+ Point aTmpPoint;
+ const Rectangle aNewRect( aTmpPoint, aRect.GetSize() );
+ Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nOldX = aRect.Left();
+ const long nOldY = aRect.Top();
+ const long nNewWidth = aNewRect.GetWidth();
+ const long nNewHeight = aNewRect.GetHeight();
+
+ for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
+ for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
+ pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY2, nX2 ) );
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ ImplAssignWithSize( aNewBmp );
+ }
+ }
+
+ return bRet;
+};
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::CopyPixel( const Rectangle& rRectDst,
+ const Rectangle& rRectSrc, const Bitmap* pBmpSrc )
+{
+ const Size aSizePix( GetSizePixel() );
+ Rectangle aRectDst( rRectDst );
+ BOOL bRet = FALSE;
+
+ aRectDst.Intersection( Rectangle( Point(), aSizePix ) );
+
+ if( !aRectDst.IsEmpty() )
+ {
+ if( pBmpSrc && ( *pBmpSrc != *this ) )
+ {
+ Bitmap* pSrc = (Bitmap*) pBmpSrc;
+ const Size aCopySizePix( pSrc->GetSizePixel() );
+ Rectangle aRectSrc( rRectSrc );
+ const USHORT nSrcBitCount = pBmpSrc->GetBitCount();
+ const USHORT nDstBitCount = GetBitCount();
+
+ if( nSrcBitCount > nDstBitCount )
+ {
+ long nNextIndex = 0L;
+
+ if( ( nSrcBitCount == 24 ) && ( nDstBitCount < 24 ) )
+ Convert( BMP_CONVERSION_24BIT );
+ else if( ( nSrcBitCount == 8 ) && ( nDstBitCount < 8 ) )
+ {
+ Convert( BMP_CONVERSION_8BIT_COLORS );
+ nNextIndex = 16;
+ }
+ else if( ( nSrcBitCount == 4 ) && ( nDstBitCount < 4 ) )
+ {
+ Convert( BMP_CONVERSION_4BIT_COLORS );
+ nNextIndex = 2;
+ }
+
+ if( nNextIndex )
+ {
+ BitmapReadAccess* pSrcAcc = pSrc->AcquireReadAccess();
+ BitmapWriteAccess* pDstAcc = AcquireWriteAccess();
+
+ if( pSrcAcc && pDstAcc )
+ {
+ const long nSrcCount = pDstAcc->GetPaletteEntryCount();
+ const long nDstCount = 1 << nDstBitCount;
+ BOOL bFound;
+
+ for( long i = 0L; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); i++ )
+ {
+ const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( (USHORT) i );
+
+ bFound = FALSE;
+
+ for( long j = 0L; j < nDstCount; j++ )
+ {
+ if( rSrcCol == pDstAcc->GetPaletteColor( (USHORT) j ) )
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if( !bFound )
+ pDstAcc->SetPaletteColor( (USHORT) nNextIndex++, rSrcCol );
+ }
+ }
+
+ if( pSrcAcc )
+ pSrc->ReleaseAccess( pSrcAcc );
+
+ if( pDstAcc )
+ ReleaseAccess( pDstAcc );
+ }
+ }
+
+ aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) );
+
+ if( !aRectSrc.IsEmpty() )
+ {
+ BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess();
+
+ if( pReadAcc )
+ {
+ BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcEndX = aRectSrc.Left() + nWidth;
+ const long nSrcEndY = aRectSrc.Top() + nHeight;
+ long nDstY = aRectDst.Top();
+
+ if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
+ {
+ const USHORT nCount = pReadAcc->GetPaletteEntryCount();
+ BYTE* pMap = new BYTE[ nCount ];
+
+ // Index-Map fuer Farbtabelle
+ // aufbauen, da das Bild ja (relativ) farbgenau
+ // kopiert werden soll
+ for( USHORT i = 0; i < nCount; i++ )
+ pMap[ i ] = (BYTE) pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) );
+
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixel( nDstY, nDstX, pMap[ pReadAcc->GetPixel( nSrcY, nSrcX ).GetIndex() ] );
+
+ delete[] pMap;
+ }
+ else if( pReadAcc->HasPalette() )
+ {
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nSrcY, nSrcX ) ) );
+ }
+ else
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) );
+
+ ReleaseAccess( pWriteAcc );
+ bRet = ( nWidth > 0L ) && ( nHeight > 0L );
+ }
+
+ pSrc->ReleaseAccess( pReadAcc );
+ }
+ }
+ }
+ else
+ {
+ Rectangle aRectSrc( rRectSrc );
+
+ aRectSrc.Intersection( Rectangle( Point(), aSizePix ) );
+
+ if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
+ {
+ BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcX = aRectSrc.Left();
+ const long nSrcY = aRectSrc.Top();
+ const long nSrcEndX1 = nSrcX + nWidth - 1L;
+ const long nSrcEndY1 = nSrcY + nHeight - 1L;
+ const long nDstX = aRectDst.Left();
+ const long nDstY = aRectDst.Top();
+ const long nDstEndX1 = nDstX + nWidth - 1L;
+ const long nDstEndY1 = nDstY + nHeight - 1L;
+
+ if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+ else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+ else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+ else
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
+ }
+
+ ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Expand( ULONG nDX, ULONG nDY, const Color* pInitColor )
+{
+ BOOL bRet = FALSE;
+
+ if( nDX || nDY )
+ {
+ const Size aSizePixel( GetSizePixel() );
+ const long nWidth = aSizePixel.Width();
+ const long nHeight = aSizePixel.Height();
+ const Size aNewSize( nWidth + nDX, nHeight + nDY );
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+
+ if( pReadAcc )
+ {
+ BitmapPalette aBmpPal( pReadAcc->GetPalette() );
+ Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ BitmapColor aColor;
+ const long nNewX = nWidth;
+ const long nNewY = nHeight;
+ const long nNewWidth = pWriteAcc->Width();
+ const long nNewHeight = pWriteAcc->Height();
+ long nX;
+ long nY;
+
+ if( pInitColor )
+ aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
+
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ pWriteAcc->CopyScanline( nY, *pReadAcc );
+
+ if( pInitColor && nDX )
+ for( nX = nNewX; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, aColor );
+ }
+
+ if( pInitColor && nDY )
+ for( nY = nNewY; nY < nNewHeight; nY++ )
+ for( nX = 0; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, aColor );
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ ImplAssignWithSize( aNewBmp );
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+Bitmap Bitmap::CreateMask( const Color& rTransColor, ULONG nTol ) const
+{
+ Bitmap aNewBmp( GetSizePixel(), 1 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pWriteAcc )
+ {
+ BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess();
+
+ if( pReadAcc )
+ {
+ const long nWidth = pReadAcc->Width();
+ const long nHeight = pReadAcc->Height();
+ const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ if( !nTol )
+ {
+ const BitmapColor aTest( pReadAcc->GetBestMatchingColor( rTransColor ) );
+ long nX, nY, nShift;
+
+ if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ||
+ pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_LSN_PAL )
+ {
+ // optimized for 4Bit-MSN/LSN source palette
+ const BYTE cTest = aTest.GetIndex();
+ const long nShiftInit = ( ( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ) ? 4 : 0 );
+
+ if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
+ aWhite.GetIndex() == 1 )
+ {
+ // optimized for 1Bit-MSB destination palette
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ Scanline pSrc = pReadAcc->GetScanline( nY );
+ Scanline pDst = pWriteAcc->GetScanline( nY );
+ for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
+ {
+ if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
+ pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
+ else
+ pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ Scanline pSrc = pReadAcc->GetScanline( nY );
+ for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
+ {
+ if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+ }
+ else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ // optimized for 8Bit source palette
+ const BYTE cTest = aTest.GetIndex();
+
+ if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
+ aWhite.GetIndex() == 1 )
+ {
+ // optimized for 1Bit-MSB destination palette
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ Scanline pSrc = pReadAcc->GetScanline( nY );
+ Scanline pDst = pWriteAcc->GetScanline( nY );
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ if( cTest == pSrc[ nX ] )
+ pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
+ else
+ pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ Scanline pSrc = pReadAcc->GetScanline( nY );
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ if( cTest == pSrc[ nX ] )
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+ }
+ else
+ {
+ // not optimized
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ if( aTest == pReadAcc->GetPixel( nY, nX ) )
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol;
+ long nR, nG, nB;
+ const long nMinR = MinMax( (long) rTransColor.GetRed() - nTol, 0, 255 );
+ const long nMaxR = MinMax( (long) rTransColor.GetRed() + nTol, 0, 255 );
+ const long nMinG = MinMax( (long) rTransColor.GetGreen() - nTol, 0, 255 );
+ const long nMaxG = MinMax( (long) rTransColor.GetGreen() + nTol, 0, 255 );
+ const long nMinB = MinMax( (long) rTransColor.GetBlue() - nTol, 0, 255 );
+ const long nMaxB = MinMax( (long) rTransColor.GetBlue() + nTol, 0, 255 );
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aCol = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) );
+ nR = aCol.GetRed();
+ nG = aCol.GetGreen();
+ nB = aCol.GetBlue();
+
+ if( nMinR <= nR && nMaxR >= nR &&
+ nMinG <= nG && nMaxG >= nG &&
+ nMinB <= nB && nMaxB >= nB )
+ {
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ }
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+ else
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aCol = pReadAcc->GetPixel( nY, nX );
+ nR = aCol.GetRed();
+ nG = aCol.GetGreen();
+ nB = aCol.GetBlue();
+
+ if( nMinR <= nR && nMaxR >= nR &&
+ nMinG <= nG && nMaxG >= nG &&
+ nMinB <= nB && nMaxB >= nB )
+ {
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ }
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+ }
+
+ ( (Bitmap*) this )->ReleaseAccess( pReadAcc );
+ bRet = TRUE;
+ }
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ }
+
+ if( bRet )
+ {
+ aNewBmp.maPrefSize = maPrefSize;
+ aNewBmp.maPrefMapMode = maPrefMapMode;
+ }
+ else
+ aNewBmp = Bitmap();
+
+ return aNewBmp;
+}
+
+// ------------------------------------------------------------------
+
+Region Bitmap::CreateRegion( const Color& rColor, const Rectangle& rRect ) const
+{
+ Region aRegion;
+ Rectangle aRect( rRect );
+ BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess();
+
+ aRect.Intersection( Rectangle( Point(), GetSizePixel() ) );
+ aRect.Justify();
+
+ if( pReadAcc )
+ {
+ Rectangle aSubRect;
+ const long nLeft = aRect.Left();
+ const long nTop = aRect.Top();
+ const long nRight = aRect.Right();
+ const long nBottom = aRect.Bottom();
+ const BitmapColor aMatch( pReadAcc->GetBestMatchingColor( rColor ) );
+
+ aRegion.ImplBeginAddRect();
+
+ for( long nY = nTop; nY <= nBottom; nY++ )
+ {
+ aSubRect.Top() = aSubRect.Bottom() = nY;
+
+ for( long nX = nLeft; nX <= nRight; )
+ {
+ while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixel( nY, nX ) ) )
+ nX++;
+
+ if( nX <= nRight )
+ {
+ aSubRect.Left() = nX;
+
+ while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixel( nY, nX ) ) )
+ nX++;
+
+ aSubRect.Right() = nX - 1L;
+ aRegion.ImplAddRect( aSubRect );
+ }
+ }
+ }
+
+ aRegion.ImplEndAddRect();
+ ( (Bitmap*) this )->ReleaseAccess( pReadAcc );
+ }
+ else
+ aRegion = aRect;
+
+ return aRegion;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Replace( const Bitmap& rMask, const Color& rReplaceColor )
+{
+ BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pMaskAcc && pAcc )
+ {
+ const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() );
+ const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() );
+ const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+ BitmapColor aReplace;
+
+ if( pAcc->HasPalette() )
+ {
+ const USHORT nActColors = pAcc->GetPaletteEntryCount();
+ const USHORT nMaxColors = 1 << pAcc->GetBitCount();
+
+ // erst einmal naechste Farbe nehmen
+ aReplace = pAcc->GetBestMatchingColor( rReplaceColor );
+
+ // falls Palettenbild, und die zu setzende Farbe ist nicht
+ // in der Palette, suchen wir nach freien Eintraegen (teuer)
+ if( pAcc->GetPaletteColor( (BYTE) aReplace ) != BitmapColor( rReplaceColor ) )
+ {
+ // erst einmal nachsehen, ob wir unsere ReplaceColor
+ // nicht auf einen freien Platz am Ende der Palette
+ // setzen koennen
+ if( nActColors < nMaxColors )
+ {
+ pAcc->SetPaletteEntryCount( nActColors + 1 );
+ pAcc->SetPaletteColor( nActColors, rReplaceColor );
+ aReplace = BitmapColor( (BYTE) nActColors );
+ }
+ else
+ {
+ BOOL* pFlags = new BOOL[ nMaxColors ];
+
+ // alle Eintraege auf 0 setzen
+ memset( pFlags, 0, nMaxColors );
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pFlags[ (BYTE) pAcc->GetPixel( nY, nX ) ] = TRUE;
+
+ for( USHORT i = 0UL; i < nMaxColors; i++ )
+ {
+ // Hurra, wir haben einen unbenutzten Eintrag
+ if( !pFlags[ i ] )
+ {
+ pAcc->SetPaletteColor( (USHORT) i, rReplaceColor );
+ aReplace = BitmapColor( (BYTE) i );
+ }
+ }
+
+ delete[] pFlags;
+ }
+ }
+ }
+ else
+ aReplace = rReplaceColor;
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite )
+ pAcc->SetPixel( nY, nX, aReplace );
+
+ bRet = TRUE;
+ }
+
+ ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
+ ReleaseAccess( pAcc );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Replace( const AlphaMask& rAlpha, const Color& rMergeColor )
+{
+ Bitmap aNewBmp( GetSizePixel(), 24 );
+ BitmapReadAccess* pAcc = AcquireReadAccess();
+ BitmapReadAccess* pAlphaAcc = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
+ BitmapWriteAccess* pNewAcc = aNewBmp.AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pAcc && pAlphaAcc && pNewAcc )
+ {
+ BitmapColor aCol;
+ const long nWidth = Min( pAlphaAcc->Width(), pAcc->Width() );
+ const long nHeight = Min( pAlphaAcc->Height(), pAcc->Height() );
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aCol = pAcc->GetColor( nY, nX );
+ pNewAcc->SetPixel( nY, nX, aCol.Merge( rMergeColor, 255 - (BYTE) pAlphaAcc->GetPixel( nY, nX ) ) );
+ }
+ }
+
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pAcc );
+ ( (AlphaMask&) rAlpha ).ReleaseAccess( pAlphaAcc );
+ aNewBmp.ReleaseAccess( pNewAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol )
+{
+ // Bitmaps with 1 bit color depth can cause problems
+ // if they have other entries than black/white in their palette
+ if( 1 == GetBitCount() )
+ Convert( BMP_CONVERSION_4BIT_COLORS );
+
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pAcc )
+ {
+ const long nMinR = MinMax( (long) rSearchColor.GetRed() - nTol, 0, 255 );
+ const long nMaxR = MinMax( (long) rSearchColor.GetRed() + nTol, 0, 255 );
+ const long nMinG = MinMax( (long) rSearchColor.GetGreen() - nTol, 0, 255 );
+ const long nMaxG = MinMax( (long) rSearchColor.GetGreen() + nTol, 0, 255 );
+ const long nMinB = MinMax( (long) rSearchColor.GetBlue() - nTol, 0, 255 );
+ const long nMaxB = MinMax( (long) rSearchColor.GetBlue() + nTol, 0, 255 );
+
+ if( pAcc->HasPalette() )
+ {
+ for( USHORT i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++ )
+ {
+ const BitmapColor& rCol = pAcc->GetPaletteColor( i );
+
+ if( nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() &&
+ nMinG <= rCol.GetGreen() && nMaxG >= rCol.GetGreen() &&
+ nMinB <= rCol.GetBlue() && nMaxB >= rCol.GetBlue() )
+ {
+ pAcc->SetPaletteColor( i, rReplaceColor );
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol;
+ const BitmapColor aReplace( pAcc->GetBestMatchingColor( rReplaceColor ) );
+
+ for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
+ {
+ for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
+ {
+ aCol = pAcc->GetPixel( nY, nX );
+
+ if( nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() &&
+ nMinG <= aCol.GetGreen() && nMaxG >= aCol.GetGreen() &&
+ nMinB <= aCol.GetBlue() && nMaxB >= aCol.GetBlue() )
+ {
+ pAcc->SetPixel( nY, nX, aReplace );
+ }
+ }
+ }
+ }
+
+ ReleaseAccess( pAcc );
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors,
+ ULONG nColorCount, ULONG* _pTols )
+{
+ // Bitmaps with 1 bit color depth can cause problems
+ // if they have other entries than black/white in their palette
+ if( 1 == GetBitCount() )
+ Convert( BMP_CONVERSION_4BIT_COLORS );
+
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pAcc )
+ {
+ long* pMinR = new long[ nColorCount ];
+ long* pMaxR = new long[ nColorCount ];
+ long* pMinG = new long[ nColorCount ];
+ long* pMaxG = new long[ nColorCount ];
+ long* pMinB = new long[ nColorCount ];
+ long* pMaxB = new long[ nColorCount ];
+ long* pTols;
+ ULONG i;
+
+ if( !_pTols )
+ {
+ pTols = new long[ nColorCount ];
+ memset( pTols, 0, nColorCount * sizeof( long ) );
+ }
+ else
+ pTols = (long*) _pTols;
+
+ for( i = 0UL; i < nColorCount; i++ )
+ {
+ const Color& rCol = pSearchColors[ i ];
+ const long nTol = pTols[ i ];
+
+ pMinR[ i ] = MinMax( (long) rCol.GetRed() - nTol, 0, 255 );
+ pMaxR[ i ] = MinMax( (long) rCol.GetRed() + nTol, 0, 255 );
+ pMinG[ i ] = MinMax( (long) rCol.GetGreen() - nTol, 0, 255 );
+ pMaxG[ i ] = MinMax( (long) rCol.GetGreen() + nTol, 0, 255 );
+ pMinB[ i ] = MinMax( (long) rCol.GetBlue() - nTol, 0, 255 );
+ pMaxB[ i ] = MinMax( (long) rCol.GetBlue() + nTol, 0, 255 );
+ }
+
+ if( pAcc->HasPalette() )
+ {
+ for( USHORT nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount; nEntry++ )
+ {
+ const BitmapColor& rCol = pAcc->GetPaletteColor( nEntry );
+
+ for( i = 0UL; i < nColorCount; i++ )
+ {
+ if( pMinR[ i ] <= rCol.GetRed() && pMaxR[ i ] >= rCol.GetRed() &&
+ pMinG[ i ] <= rCol.GetGreen() && pMaxG[ i ] >= rCol.GetGreen() &&
+ pMinB[ i ] <= rCol.GetBlue() && pMaxB[ i ] >= rCol.GetBlue() )
+ {
+ pAcc->SetPaletteColor( (USHORT)nEntry, pReplaceColors[ i ] );
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol;
+ BitmapColor* pReplaces = new BitmapColor[ nColorCount ];
+
+ for( i = 0UL; i < nColorCount; i++ )
+ pReplaces[ i ] = pAcc->GetBestMatchingColor( pReplaceColors[ i ] );
+
+ for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
+ {
+ for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
+ {
+ aCol = pAcc->GetPixel( nY, nX );
+
+ for( i = 0UL; i < nColorCount; i++ )
+ {
+ if( pMinR[ i ] <= aCol.GetRed() && pMaxR[ i ] >= aCol.GetRed() &&
+ pMinG[ i ] <= aCol.GetGreen() && pMaxG[ i ] >= aCol.GetGreen() &&
+ pMinB[ i ] <= aCol.GetBlue() && pMaxB[ i ] >= aCol.GetBlue() )
+ {
+ pAcc->SetPixel( nY, nX, pReplaces[ i ] );
+ break;
+ }
+ }
+ }
+ }
+
+ delete[] pReplaces;
+ }
+
+ if( !_pTols )
+ delete[] pTols;
+
+ delete[] pMinR;
+ delete[] pMaxR;
+ delete[] pMinG;
+ delete[] pMaxG;
+ delete[] pMinB;
+ delete[] pMaxB;
+ ReleaseAccess( pAcc );
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay )
+{
+ Bitmap aDispBmp( *this );
+
+ if( mpImpBmp && ( pDisplay->mpGraphics || pDisplay->ImplGetGraphics() ) )
+ {
+ ImpBitmap* pImpDispBmp = new ImpBitmap;
+
+ if( pImpDispBmp->ImplCreate( *mpImpBmp, pDisplay->mpGraphics ) )
+ aDispBmp.ImplSetImpBitmap( pImpDispBmp );
+ else
+ delete pImpDispBmp;
+ }
+
+ return aDispBmp;
+}
+
+// ------------------------------------------------------------------
+
+Bitmap Bitmap::GetColorTransformedBitmap( BmpColorMode eColorMode ) const
+{
+ Bitmap aRet;
+
+ if( BMP_COLOR_HIGHCONTRAST == eColorMode )
+ {
+ Color* pSrcColors = NULL;
+ Color* pDstColors = NULL;
+ ULONG nColorCount = 0;
+
+ aRet = *this;
+
+ Image::GetColorTransformArrays( (ImageColorTransform) eColorMode, pSrcColors, pDstColors, nColorCount );
+
+ if( nColorCount && pSrcColors && pDstColors )
+ aRet.Replace( pSrcColors, pDstColors, nColorCount );
+
+ delete[] pSrcColors;
+ delete[] pDstColors;
+ }
+ else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
+ BMP_COLOR_MONOCHROME_WHITE == eColorMode )
+ {
+ aRet = *this;
+ aRet.MakeMono( BMP_COLOR_MONOCHROME_THRESHOLD );
+ }
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::CombineSimple( const Bitmap& rMask, BmpCombine eCombine )
+{
+ BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pMaskAcc && pAcc )
+ {
+ const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() );
+ const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() );
+ const Color aColBlack( COL_BLACK );
+ BitmapColor aPixel;
+ BitmapColor aMaskPixel;
+ const BitmapColor aWhite( pAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+ const BitmapColor aBlack( pAcc->GetBestMatchingColor( aColBlack ) );
+ const BitmapColor aMaskBlack( pMaskAcc->GetBestMatchingColor( aColBlack ) );
+
+ switch( eCombine )
+ {
+ case( BMP_COMBINE_COPY ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pMaskAcc->GetPixel( nY, nX ) == aMaskBlack )
+ pAcc->SetPixel( nY, nX, aBlack );
+ else
+ pAcc->SetPixel( nY, nX, aWhite );
+ }
+ }
+ break;
+
+ case( BMP_COMBINE_INVERT ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pAcc->GetPixel( nY, nX ) == aBlack )
+ pAcc->SetPixel( nY, nX, aWhite );
+ else
+ pAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ break;
+
+ case( BMP_COMBINE_AND ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
+ pAcc->SetPixel( nY, nX, aWhite );
+ else
+ pAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ break;
+
+ case( BMP_COMBINE_NAND ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
+ pAcc->SetPixel( nY, nX, aBlack );
+ else
+ pAcc->SetPixel( nY, nX, aWhite );
+ }
+ }
+ break;
+
+ case( BMP_COMBINE_OR ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
+ pAcc->SetPixel( nY, nX, aWhite );
+ else
+ pAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ break;
+
+ case( BMP_COMBINE_NOR ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
+ pAcc->SetPixel( nY, nX, aBlack );
+ else
+ pAcc->SetPixel( nY, nX, aWhite );
+ }
+ }
+ break;
+
+ case( BMP_COMBINE_XOR ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aPixel = pAcc->GetPixel( nY, nX );
+ aMaskPixel = pMaskAcc->GetPixel( nY, nX );
+
+ if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
+ ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
+ {
+ pAcc->SetPixel( nY, nX, aWhite );
+ }
+ else
+ pAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ break;
+
+ case( BMP_COMBINE_NXOR ):
+ {
+ for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aPixel = pAcc->GetPixel( nY, nX );
+ aMaskPixel = pMaskAcc->GetPixel( nY, nX );
+
+ if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
+ ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
+ {
+ pAcc->SetPixel( nY, nX, aBlack );
+ }
+ else
+ pAcc->SetPixel( nY, nX, aWhite );
+ }
+ }
+ break;
+ }
+
+ bRet = TRUE;
+ }
+
+ ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
+ ReleaseAccess( pAcc );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Blend( const AlphaMask& rAlpha, const Color& rBackgroundColor )
+{
+ // TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
+ // optimizations. Might even consolidate the code here and there.
+
+ // convert to a truecolor bitmap, if we're a paletted one. There's
+ // room for tradeoff decision here, maybe later for an overload (or a flag)
+ if( GetBitCount() <= 8 )
+ Convert( BMP_CONVERSION_24BIT );
+
+ BitmapReadAccess* pAlphaAcc = const_cast<AlphaMask&>(rAlpha).AcquireReadAccess();
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pAlphaAcc && pAcc )
+ {
+ const long nWidth = Min( pAlphaAcc->Width(), pAcc->Width() );
+ const long nHeight = Min( pAlphaAcc->Height(), pAcc->Height() );
+
+ for( long nY = 0L; nY < nHeight; ++nY )
+ for( long nX = 0L; nX < nWidth; ++nX )
+ pAcc->SetPixel( nY, nX,
+ pAcc->GetPixel( nY, nX ).Merge( rBackgroundColor,
+ 255 - pAlphaAcc->GetPixel( nY, nX ) ) );
+
+ bRet = TRUE;
+ }
+
+ const_cast<AlphaMask&>(rAlpha).ReleaseAccess( pAlphaAcc );
+ ReleaseAccess( pAcc );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::MakeMono( BYTE cThreshold )
+{
+ return ImplMakeMono( cThreshold );
+}
+
+// ------------------------------------------------------------------
+
+bool Bitmap::GetSystemData( BitmapSystemData& rData ) const
+{
+ bool bRet = false;
+ if( mpImpBmp )
+ {
+ SalBitmap* pSalBitmap = mpImpBmp->ImplGetSalBitmap();
+ if( pSalBitmap )
+ bRet = pSalBitmap->GetSystemData( rData );
+ }
+
+ return bRet;
+}
diff --git a/vcl/source/gdi/bitmap2.cxx b/vcl/source/gdi/bitmap2.cxx
new file mode 100644
index 000000000000..de926a0446ca
--- /dev/null
+++ b/vcl/source/gdi/bitmap2.cxx
@@ -0,0 +1,1277 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/zcodec.hxx>
+#ifndef _TOOLS_STREAM_HXX
+#include <tools/stream.hxx>
+#endif
+#include <vcl/salbtype.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/bitmap.hxx>
+
+#include <utility>
+
+
+// -----------
+// - Defines -
+// -----------
+
+#define DIBCOREHEADERSIZE ( 12UL )
+#define DIBINFOHEADERSIZE ( sizeof( DIBInfoHeader ) )
+#define SETPIXEL4( pBuf, nX, cChar )( (pBuf)[ (nX) >> 1 ] |= ( (nX) & 1 ) ? ( cChar ): (cChar) << 4 );
+
+// ----------------------
+// - Compression defines
+// ----------------------
+
+#define COMPRESS_OWN ('S'|('D'<<8UL))
+#define COMPRESS_NONE ( 0UL )
+#define RLE_8 ( 1UL )
+#define RLE_4 ( 2UL )
+#define BITFIELDS ( 3UL )
+#define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */
+
+// -----------------
+// - DIBInfoHeader -
+// -----------------
+
+struct DIBInfoHeader
+{
+ sal_uInt32 nSize;
+ sal_Int32 nWidth;
+ sal_Int32 nHeight;
+ sal_uInt16 nPlanes;
+ sal_uInt16 nBitCount;
+ sal_uInt32 nCompression;
+ sal_uInt32 nSizeImage;
+ sal_Int32 nXPelsPerMeter;
+ sal_Int32 nYPelsPerMeter;
+ sal_uInt32 nColsUsed;
+ sal_uInt32 nColsImportant;
+
+ DIBInfoHeader() :
+ nSize( 0UL ),
+ nWidth( 0UL ),
+ nHeight( 0UL ),
+ nPlanes( 0 ),
+ nBitCount( 0 ),
+ nCompression( 0 ),
+ nSizeImage( 0 ),
+ nXPelsPerMeter( 0UL ),
+ nYPelsPerMeter( 0UL ),
+ nColsUsed( 0UL ),
+ nColsImportant( 0UL ) {}
+
+ ~DIBInfoHeader() {}
+};
+
+namespace
+{
+ inline USHORT discretizeBitcount( UINT16 nInputCount )
+ {
+ return ( nInputCount <= 1 ) ? 1 :
+ ( nInputCount <= 4 ) ? 4 :
+ ( nInputCount <= 8 ) ? 8 : 24;
+ }
+
+ inline bool isBitfieldCompression( ULONG nScanlineFormat )
+ {
+ return nScanlineFormat == BMP_FORMAT_16BIT_TC_LSB_MASK ||
+ nScanlineFormat == BMP_FORMAT_32BIT_TC_MASK;
+ }
+}
+
+// ----------
+// - Bitmap -
+// ----------
+
+SvStream& operator>>( SvStream& rIStm, Bitmap& rBitmap )
+{
+ rBitmap.Read( rIStm, TRUE );
+ return rIStm;
+}
+
+// ------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Bitmap& rBitmap )
+{
+ rBitmap.Write( rOStm, FALSE, TRUE );
+ return rOStm;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Read( SvStream& rIStm, BOOL bFileHeader )
+{
+ const USHORT nOldFormat = rIStm.GetNumberFormatInt();
+ const ULONG nOldPos = rIStm.Tell();
+ ULONG nOffset = 0UL;
+ BOOL bRet = FALSE;
+
+ rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ if( bFileHeader )
+ {
+ if( ImplReadDIBFileHeader( rIStm, nOffset ) )
+ bRet = ImplReadDIB( rIStm, *this, nOffset );
+ }
+ else
+ bRet = ImplReadDIB( rIStm, *this, nOffset );
+
+ if( !bRet )
+ {
+ if( !rIStm.GetError() )
+ rIStm.SetError( SVSTREAM_GENERALERROR );
+
+ rIStm.Seek( nOldPos );
+ }
+
+ rIStm.SetNumberFormatInt( nOldFormat );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplReadDIB( SvStream& rIStm, Bitmap& rBmp, ULONG nOffset )
+{
+ DIBInfoHeader aHeader;
+ const ULONG nStmPos = rIStm.Tell();
+ BOOL bRet = FALSE;
+ sal_Bool bTopDown = sal_False;
+
+ if( ImplReadDIBInfoHeader( rIStm, aHeader, bTopDown ) && aHeader.nWidth && aHeader.nHeight && aHeader.nBitCount )
+ {
+ const USHORT nBitCount( discretizeBitcount(aHeader.nBitCount) );
+
+ const Size aSizePixel( aHeader.nWidth, aHeader.nHeight );
+ BitmapPalette aDummyPal;
+ Bitmap aNewBmp( aSizePixel, nBitCount, &aDummyPal );
+ BitmapWriteAccess* pAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pAcc )
+ {
+ USHORT nColors;
+ SvStream* pIStm;
+ SvMemoryStream* pMemStm = NULL;
+ BYTE* pData = NULL;
+
+ if( nBitCount <= 8 )
+ {
+ if( aHeader.nColsUsed )
+ nColors = (USHORT) aHeader.nColsUsed;
+ else
+ nColors = ( 1 << aHeader.nBitCount );
+ }
+ else
+ nColors = 0;
+
+ if( ZCOMPRESS == aHeader.nCompression )
+ {
+ ZCodec aCodec;
+ sal_uInt32 nCodedSize, nUncodedSize;
+ ULONG nCodedPos;
+
+ // read coding information
+ rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression;
+ pData = (BYTE*) rtl_allocateMemory( nUncodedSize );
+
+ // decode buffer
+ nCodedPos = rIStm.Tell();
+ aCodec.BeginCompression();
+ aCodec.Read( rIStm, pData, nUncodedSize );
+ aCodec.EndCompression();
+
+ // skip unread bytes from coded buffer
+ rIStm.SeekRel( nCodedSize - ( rIStm.Tell() - nCodedPos ) );
+
+ // set decoded bytes to memory stream,
+ // from which we will read the bitmap data
+ pIStm = pMemStm = new SvMemoryStream;
+ pMemStm->SetBuffer( (char*) pData, nUncodedSize, FALSE, nUncodedSize );
+ nOffset = 0;
+ }
+ else
+ pIStm = &rIStm;
+
+ // read palette
+ if( nColors )
+ {
+ pAcc->SetPaletteEntryCount( nColors );
+ ImplReadDIBPalette( *pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE );
+ }
+
+ // read bits
+ if( !pIStm->GetError() )
+ {
+ if( nOffset )
+ pIStm->SeekRel( nOffset - ( pIStm->Tell() - nStmPos ) );
+
+ bRet = ImplReadDIBBits( *pIStm, aHeader, *pAcc, bTopDown );
+
+ if( bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter )
+ {
+ MapMode aMapMode( MAP_MM, Point(),
+ Fraction( 1000, aHeader.nXPelsPerMeter ),
+ Fraction( 1000, aHeader.nYPelsPerMeter ) );
+
+ aNewBmp.SetPrefMapMode( aMapMode );
+ aNewBmp.SetPrefSize( Size( aHeader.nWidth, aHeader.nHeight ) );
+ }
+ }
+
+ if( pData )
+ rtl_freeMemory( pData );
+
+ delete pMemStm;
+ aNewBmp.ReleaseAccess( pAcc );
+
+ if( bRet )
+ rBmp = aNewBmp;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplReadDIBFileHeader( SvStream& rIStm, ULONG& rOffset )
+{
+ UINT32 nTmp32;
+ UINT16 nTmp16 = 0;
+ BOOL bRet = FALSE;
+
+ rIStm >> nTmp16;
+
+ if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) )
+ {
+ if ( 0x4142 == nTmp16 )
+ {
+ rIStm.SeekRel( 12L );
+ rIStm >> nTmp16;
+ rIStm.SeekRel( 8L );
+ rIStm >> nTmp32;
+ rOffset = nTmp32 - 28UL;;
+ bRet = ( 0x4D42 == nTmp16 );
+ }
+ else
+ {
+ rIStm.SeekRel( 8L );
+ rIStm >> nTmp32;
+ rOffset = nTmp32 - 14UL;
+ bRet = ( rIStm.GetError() == 0UL );
+ }
+ }
+ else
+ rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplReadDIBInfoHeader( SvStream& rIStm, DIBInfoHeader& rHeader, sal_Bool& bTopDown )
+{
+ // BITMAPINFOHEADER or BITMAPCOREHEADER
+ rIStm >> rHeader.nSize;
+
+ // BITMAPCOREHEADER
+ if ( rHeader.nSize == DIBCOREHEADERSIZE )
+ {
+ sal_Int16 nTmp16;
+
+ rIStm >> nTmp16; rHeader.nWidth = nTmp16;
+ rIStm >> nTmp16; rHeader.nHeight = nTmp16;
+ rIStm >> rHeader.nPlanes;
+ rIStm >> rHeader.nBitCount;
+ }
+ else
+ {
+ // unknown Header
+ if( rHeader.nSize < DIBINFOHEADERSIZE )
+ {
+ ULONG nUnknownSize = sizeof( rHeader.nSize );
+
+ rIStm >> rHeader.nWidth; nUnknownSize += sizeof( rHeader.nWidth );
+ rIStm >> rHeader.nHeight; nUnknownSize += sizeof( rHeader.nHeight );
+ rIStm >> rHeader.nPlanes; nUnknownSize += sizeof( rHeader.nPlanes );
+ rIStm >> rHeader.nBitCount; nUnknownSize += sizeof( rHeader.nBitCount );
+
+ if( nUnknownSize < rHeader.nSize )
+ {
+ rIStm >> rHeader.nCompression;
+ nUnknownSize += sizeof( rHeader.nCompression );
+
+ if( nUnknownSize < rHeader.nSize )
+ {
+ rIStm >> rHeader.nSizeImage;
+ nUnknownSize += sizeof( rHeader.nSizeImage );
+
+ if( nUnknownSize < rHeader.nSize )
+ {
+ rIStm >> rHeader.nXPelsPerMeter;
+ nUnknownSize += sizeof( rHeader.nXPelsPerMeter );
+
+ if( nUnknownSize < rHeader.nSize )
+ {
+ rIStm >> rHeader.nYPelsPerMeter;
+ nUnknownSize += sizeof( rHeader.nYPelsPerMeter );
+ }
+
+ if( nUnknownSize < rHeader.nSize )
+ {
+ rIStm >> rHeader.nColsUsed;
+ nUnknownSize += sizeof( rHeader.nColsUsed );
+
+ if( nUnknownSize < rHeader.nSize )
+ {
+ rIStm >> rHeader.nColsImportant;
+ nUnknownSize += sizeof( rHeader.nColsImportant );
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ rIStm >> rHeader.nWidth;
+ rIStm >> rHeader.nHeight;
+ rIStm >> rHeader.nPlanes;
+ rIStm >> rHeader.nBitCount;
+ rIStm >> rHeader.nCompression;
+ rIStm >> rHeader.nSizeImage;
+ rIStm >> rHeader.nXPelsPerMeter;
+ rIStm >> rHeader.nYPelsPerMeter;
+ rIStm >> rHeader.nColsUsed;
+ rIStm >> rHeader.nColsImportant;
+ }
+
+ // Eventuell bis zur Palette ueberlesen
+ if ( rHeader.nSize > DIBINFOHEADERSIZE )
+ rIStm.SeekRel( rHeader.nSize - DIBINFOHEADERSIZE );
+ }
+ if ( rHeader.nHeight < 0 )
+ {
+ bTopDown = sal_True;
+ rHeader.nHeight *= -1;
+ }
+ else
+ bTopDown = sal_False;
+
+ if ( rHeader.nWidth < 0 )
+ rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
+
+ // #144105# protect a little against damaged files
+ if( rHeader.nSizeImage > ( 16 * static_cast< sal_uInt32 >( rHeader.nWidth * rHeader.nHeight ) ) )
+ rHeader.nSizeImage = 0;
+
+ return( ( rHeader.nPlanes == 1 ) && ( rIStm.GetError() == 0UL ) );
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, BOOL bQuad )
+{
+ const USHORT nColors = rAcc.GetPaletteEntryCount();
+ const ULONG nPalSize = nColors * ( bQuad ? 4UL : 3UL );
+ BitmapColor aPalColor;
+
+ BYTE* pEntries = new BYTE[ nPalSize ];
+ rIStm.Read( pEntries, nPalSize );
+
+ BYTE* pTmpEntry = pEntries;
+ for( USHORT i = 0; i < nColors; i++ )
+ {
+ aPalColor.SetBlue( *pTmpEntry++ );
+ aPalColor.SetGreen( *pTmpEntry++ );
+ aPalColor.SetRed( *pTmpEntry++ );
+
+ if( bQuad )
+ pTmpEntry++;
+
+ rAcc.SetPaletteColor( i, aPalColor );
+ }
+
+ delete[] pEntries;
+
+ return( rIStm.GetError() == 0UL );
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplReadDIBBits( SvStream& rIStm, DIBInfoHeader& rHeader, BitmapWriteAccess& rAcc, sal_Bool bTopDown )
+{
+ const ULONG nAlignedWidth = AlignedWidth4Bytes( rHeader.nWidth * rHeader.nBitCount );
+ UINT32 nRMask = 0;
+ UINT32 nGMask = 0;
+ UINT32 nBMask = 0;
+ BOOL bNative;
+ BOOL bTCMask = ( rHeader.nBitCount == 16 ) || ( rHeader.nBitCount == 32 );
+ BOOL bRLE = ( RLE_8 == rHeader.nCompression && rHeader.nBitCount == 8 ) ||
+ ( RLE_4 == rHeader.nCompression && rHeader.nBitCount == 4 );
+
+ // Is native format?
+ switch( rAcc.GetScanlineFormat() )
+ {
+ case( BMP_FORMAT_1BIT_MSB_PAL ):
+ case( BMP_FORMAT_4BIT_MSN_PAL ):
+ case( BMP_FORMAT_8BIT_PAL ):
+ case( BMP_FORMAT_24BIT_TC_BGR ):
+ bNative = ( ( rAcc.IsBottomUp() != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) );
+ break;
+
+ default:
+ bNative = FALSE;
+ break;
+ }
+ // Read data
+ if( bNative )
+ {
+ // true color DIB's can have a (optimization) palette
+ if( rHeader.nColsUsed && rHeader.nBitCount > 8 )
+ rIStm.SeekRel( rHeader.nColsUsed * ( ( rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3 ) );
+
+ rIStm.Read( rAcc.GetBuffer(), rHeader.nHeight * nAlignedWidth );
+ }
+ else
+ {
+ // Read color mask
+ if( bTCMask )
+ {
+ if( rHeader.nCompression == BITFIELDS )
+ {
+ rIStm.SeekRel( -12L );
+ rIStm >> nRMask;
+ rIStm >> nGMask;
+ rIStm >> nBMask;
+ }
+ else
+ {
+ nRMask = ( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL;
+ nGMask = ( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL;
+ nBMask = ( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL;
+ }
+ }
+
+ if( bRLE )
+ {
+ if ( !rHeader.nSizeImage )
+ {
+ const ULONG nOldPos = rIStm.Tell();
+
+ rIStm.Seek( STREAM_SEEK_TO_END );
+ rHeader.nSizeImage = rIStm.Tell() - nOldPos;
+ rIStm.Seek( nOldPos );
+ }
+
+ BYTE* pBuffer = (BYTE*) rtl_allocateMemory( rHeader.nSizeImage );
+
+ rIStm.Read( (char*) pBuffer, rHeader.nSizeImage );
+ ImplDecodeRLE( pBuffer, rHeader, rAcc, RLE_4 == rHeader.nCompression );
+
+ rtl_freeMemory( pBuffer );
+ }
+ else
+ {
+ const long nWidth = rHeader.nWidth;
+ const long nHeight = rHeader.nHeight;
+ BYTE* pBuf = new BYTE[ nAlignedWidth ];
+
+ // true color DIB's can have a (optimization) palette
+ if( rHeader.nColsUsed && rHeader.nBitCount > 8 )
+ rIStm.SeekRel( rHeader.nColsUsed * ( ( rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3 ) );
+
+ const long nI = bTopDown ? 1 : -1;
+ long nY = bTopDown ? 0 : nHeight - 1;
+ long nCount = nHeight;
+
+ switch( rHeader.nBitCount )
+ {
+ case( 1 ):
+ {
+ BYTE* pTmp;
+ BYTE cTmp;
+
+ for( ; nCount--; nY += nI )
+ {
+ rIStm.Read( pTmp = pBuf, nAlignedWidth );
+ cTmp = *pTmp++;
+
+ for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
+ {
+ if( !nShift )
+ {
+ nShift = 8L,
+ cTmp = *pTmp++;
+ }
+
+ rAcc.SetPixel( nY, nX, sal::static_int_cast<BYTE>(( cTmp >> --nShift ) & 1) );
+ }
+ }
+ }
+ break;
+
+ case( 4 ):
+ {
+ BYTE* pTmp;
+ BYTE cTmp;
+
+ for( ; nCount--; nY += nI )
+ {
+ rIStm.Read( pTmp = pBuf, nAlignedWidth );
+ cTmp = *pTmp++;
+
+ for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
+ {
+ if( !nShift )
+ {
+ nShift = 2UL,
+ cTmp = *pTmp++;
+ }
+
+ rAcc.SetPixel( nY, nX, sal::static_int_cast<BYTE>(( cTmp >> ( --nShift << 2UL ) ) & 0x0f) );
+ }
+ }
+ }
+ break;
+
+ case( 8 ):
+ {
+ BYTE* pTmp;
+
+ for( ; nCount--; nY += nI )
+ {
+ rIStm.Read( pTmp = pBuf, nAlignedWidth );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ rAcc.SetPixel( nY, nX, *pTmp++ );
+ }
+ }
+ break;
+
+ case( 16 ):
+ {
+ ColorMask aMask( nRMask, nGMask, nBMask );
+ BitmapColor aColor;
+ UINT16* pTmp16;
+
+ for( ; nCount--; nY += nI )
+ {
+ rIStm.Read( (char*)( pTmp16 = (UINT16*) pBuf ), nAlignedWidth );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aMask.GetColorFor16BitLSB( aColor, (BYTE*) pTmp16++ );
+ rAcc.SetPixel( nY, nX, aColor );
+ }
+ }
+ }
+ break;
+
+ case( 24 ):
+ {
+ BitmapColor aPixelColor;
+ BYTE* pTmp;
+
+ for( ; nCount--; nY += nI )
+ {
+ rIStm.Read( pTmp = pBuf, nAlignedWidth );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aPixelColor.SetBlue( *pTmp++ );
+ aPixelColor.SetGreen( *pTmp++ );
+ aPixelColor.SetRed( *pTmp++ );
+ rAcc.SetPixel( nY, nX, aPixelColor );
+ }
+ }
+ }
+ break;
+
+ case( 32 ):
+ {
+ ColorMask aMask( nRMask, nGMask, nBMask );
+ BitmapColor aColor;
+ UINT32* pTmp32;
+
+ for( ; nCount--; nY += nI )
+ {
+ rIStm.Read( (char*)( pTmp32 = (UINT32*) pBuf ), nAlignedWidth );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aMask.GetColorFor32Bit( aColor, (BYTE*) pTmp32++ );
+ rAcc.SetPixel( nY, nX, aColor );
+ }
+ }
+ }
+ }
+
+ delete[] pBuf;
+ }
+ }
+
+ return( rIStm.GetError() == 0UL );
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::Write( SvStream& rOStm, BOOL bCompressed, BOOL bFileHeader ) const
+{
+ DBG_ASSERT( mpImpBmp, "Empty Bitmaps can't be saved" );
+
+ const Size aSizePix( GetSizePixel() );
+ BOOL bRet = FALSE;
+
+ if( mpImpBmp && aSizePix.Width() && aSizePix.Height() )
+ {
+ BitmapReadAccess* pAcc = ( (Bitmap*) this)->AcquireReadAccess();
+ const USHORT nOldFormat = rOStm.GetNumberFormatInt();
+ const ULONG nOldPos = rOStm.Tell();
+
+ rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ if( pAcc )
+ {
+ if( bFileHeader )
+ {
+ if( ImplWriteDIBFileHeader( rOStm, *pAcc ) )
+ bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed );
+ }
+ else
+ bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed );
+
+ ( (Bitmap*) this)->ReleaseAccess( pAcc );
+ }
+
+ if( !bRet )
+ {
+ rOStm.SetError( SVSTREAM_GENERALERROR );
+ rOStm.Seek( nOldPos );
+ }
+
+ rOStm.SetNumberFormatInt( nOldFormat );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplWriteDIB( SvStream& rOStm, BitmapReadAccess& rAcc, BOOL bCompressed ) const
+{
+ const MapMode aMapPixel( MAP_PIXEL );
+ DIBInfoHeader aHeader;
+ ULONG nImageSizePos;
+ ULONG nEndPos;
+ sal_uInt32 nCompression = 0;
+ BOOL bRet = FALSE;
+
+ aHeader.nSize = DIBINFOHEADERSIZE;
+ aHeader.nWidth = rAcc.Width();
+ aHeader.nHeight = rAcc.Height();
+ aHeader.nPlanes = 1;
+
+ if( isBitfieldCompression( rAcc.GetScanlineFormat() ) )
+ {
+ aHeader.nBitCount = ( rAcc.GetScanlineFormat() == BMP_FORMAT_16BIT_TC_LSB_MASK ) ? 16 : 32;
+ aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize();
+
+ nCompression = BITFIELDS;
+ }
+ else
+ {
+ // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are
+ // not handled properly below (would have to set color
+ // masks, and nCompression=BITFIELDS - but color mask is
+ // not set for formats != *_TC_*). Note that this very
+ // problem might cause trouble at other places - the
+ // introduction of 32 bit RGBA bitmaps is relatively
+ // recent.
+ // #i59239# discretize bitcount to 1,4,8,24 (other cases
+ // are not written below)
+ const UINT16 nBitCount( sal::static_int_cast<UINT16>(rAcc.GetBitCount()) );
+
+ aHeader.nBitCount = discretizeBitcount( nBitCount );
+ aHeader.nSizeImage = rAcc.Height() *
+ AlignedWidth4Bytes( rAcc.Width()*aHeader.nBitCount );
+
+ if( bCompressed )
+ {
+ if( 4 == nBitCount )
+ nCompression = RLE_4;
+ else if( 8 == nBitCount )
+ nCompression = RLE_8;
+ }
+ else
+ nCompression = COMPRESS_NONE;
+ }
+
+ if( ( rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP ) &&
+ ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40 ) )
+ {
+ aHeader.nCompression = ZCOMPRESS;
+ }
+ else
+ aHeader.nCompression = nCompression;
+
+ if( maPrefSize.Width() && maPrefSize.Height() && ( maPrefMapMode != aMapPixel ) )
+ {
+ // #i48108# Try to recover xpels/ypels as previously stored on
+ // disk. The problem with just converting maPrefSize to 100th
+ // mm and then relating that to the bitmap pixel size is that
+ // MapMode is integer-based, and suffers from roundoffs,
+ // especially if maPrefSize is small. Trying to circumvent
+ // that by performing part of the math in floating point.
+ const Size aScale100000(
+ OutputDevice::LogicToLogic( Size(100000L,
+ 100000L),
+ MAP_100TH_MM,
+ maPrefMapMode ) );
+ const double fBmpWidthM((double)maPrefSize.Width() / aScale100000.Width() );
+ const double fBmpHeightM((double)maPrefSize.Height() / aScale100000.Height() );
+ if( fabs(fBmpWidthM) > 0.000000001 &&
+ fabs(fBmpHeightM) > 0.000000001 )
+ {
+ aHeader.nXPelsPerMeter = (UINT32)(rAcc.Width() / fBmpWidthM + .5);
+ aHeader.nYPelsPerMeter = (UINT32)(rAcc.Height() / fBmpHeightM + .5);
+ }
+ }
+
+ aHeader.nColsUsed = ( ( aHeader.nBitCount <= 8 ) ? rAcc.GetPaletteEntryCount() : 0 );
+ aHeader.nColsImportant = 0;
+
+ rOStm << aHeader.nSize;
+ rOStm << aHeader.nWidth;
+ rOStm << aHeader.nHeight;
+ rOStm << aHeader.nPlanes;
+ rOStm << aHeader.nBitCount;
+ rOStm << aHeader.nCompression;
+
+ nImageSizePos = rOStm.Tell();
+ rOStm.SeekRel( sizeof( aHeader.nSizeImage ) );
+
+ rOStm << aHeader.nXPelsPerMeter;
+ rOStm << aHeader.nYPelsPerMeter;
+ rOStm << aHeader.nColsUsed;
+ rOStm << aHeader.nColsImportant;
+
+ if( aHeader.nCompression == ZCOMPRESS )
+ {
+ ZCodec aCodec;
+ SvMemoryStream aMemStm( aHeader.nSizeImage + 4096, 65535 );
+ ULONG nCodedPos = rOStm.Tell(), nLastPos;
+ sal_uInt32 nCodedSize, nUncodedSize;
+
+ // write uncoded data palette
+ if( aHeader.nColsUsed )
+ ImplWriteDIBPalette( aMemStm, rAcc );
+
+ // write uncoded bits
+ bRet = ImplWriteDIBBits( aMemStm, rAcc, nCompression, aHeader.nSizeImage );
+
+ // get uncoded size
+ nUncodedSize = aMemStm.Tell();
+
+ // seek over compress info
+ rOStm.SeekRel( 12 );
+
+ // write compressed data
+ aCodec.BeginCompression( 3 );
+ aCodec.Write( rOStm, (BYTE*) aMemStm.GetData(), nUncodedSize );
+ aCodec.EndCompression();
+
+ // update compress info ( coded size, uncoded size, uncoded compression )
+ nCodedSize = ( nLastPos = rOStm.Tell() ) - nCodedPos - 12;
+ rOStm.Seek( nCodedPos );
+ rOStm << nCodedSize << nUncodedSize << nCompression;
+ rOStm.Seek( nLastPos );
+
+ if( bRet )
+ bRet = ( rOStm.GetError() == ERRCODE_NONE );
+ }
+ else
+ {
+ if( aHeader.nColsUsed )
+ ImplWriteDIBPalette( rOStm, rAcc );
+
+ bRet = ImplWriteDIBBits( rOStm, rAcc, aHeader.nCompression, aHeader.nSizeImage );
+ }
+
+ nEndPos = rOStm.Tell();
+ rOStm.Seek( nImageSizePos );
+ rOStm << aHeader.nSizeImage;
+ rOStm.Seek( nEndPos );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplWriteDIBFileHeader( SvStream& rOStm, BitmapReadAccess& rAcc )
+{
+ UINT32 nPalCount = ( rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() :
+ isBitfieldCompression( rAcc.GetScanlineFormat() ) ? 3UL : 0UL );
+ UINT32 nOffset = 14 + DIBINFOHEADERSIZE + nPalCount * 4UL;
+
+ rOStm << (UINT16) 0x4D42;
+ rOStm << (UINT32) ( nOffset + ( rAcc.Height() * rAcc.GetScanlineSize() ) );
+ rOStm << (UINT16) 0;
+ rOStm << (UINT16) 0;
+ rOStm << nOffset;
+
+ return( rOStm.GetError() == 0UL );
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc )
+{
+ const USHORT nColors = rAcc.GetPaletteEntryCount();
+ const ULONG nPalSize = nColors * 4UL;
+ BYTE* pEntries = new BYTE[ nPalSize ];
+ BYTE* pTmpEntry = pEntries;
+ BitmapColor aPalColor;
+
+ for( USHORT i = 0; i < nColors; i++ )
+ {
+ const BitmapColor& rPalColor = rAcc.GetPaletteColor( i );
+
+ *pTmpEntry++ = rPalColor.GetBlue();
+ *pTmpEntry++ = rPalColor.GetGreen();
+ *pTmpEntry++ = rPalColor.GetRed();
+ *pTmpEntry++ = 0;
+ }
+
+ rOStm.Write( pEntries, nPalSize );
+ delete[] pEntries;
+
+ return( rOStm.GetError() == 0UL );
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplWriteDIBBits( SvStream& rOStm, BitmapReadAccess& rAcc,
+ ULONG nCompression, sal_uInt32& rImageSize )
+{
+ if( BITFIELDS == nCompression )
+ {
+ const ColorMask& rMask = rAcc.GetColorMask();
+ SVBT32 aVal32;
+
+ UInt32ToSVBT32( rMask.GetRedMask(), aVal32 );
+ rOStm.Write( (BYTE*) aVal32, 4UL );
+
+ UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 );
+ rOStm.Write( (BYTE*) aVal32, 4UL );
+
+ UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 );
+ rOStm.Write( (BYTE*) aVal32, 4UL );
+
+ rImageSize = rOStm.Tell();
+
+ if( rAcc.IsBottomUp() )
+ rOStm.Write( rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize() );
+ else
+ {
+ for( long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0L; nY-- )
+ rOStm.Write( rAcc.GetScanline( nY ), nScanlineSize );
+ }
+ }
+ else if( ( RLE_4 == nCompression ) || ( RLE_8 == nCompression ) )
+ {
+ rImageSize = rOStm.Tell();
+ ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression );
+ }
+ else if( !nCompression )
+ {
+ // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not
+ // handled properly below (would have to set color masks, and
+ // nCompression=BITFIELDS - but color mask is not set for
+ // formats != *_TC_*). Note that this very problem might cause
+ // trouble at other places - the introduction of 32 bit RGBA
+ // bitmaps is relatively recent.
+ // #i59239# discretize bitcount for aligned width to 1,4,8,24
+ // (other cases are not written below)
+ const USHORT nBitCount( sal::static_int_cast<USHORT>(rAcc.GetBitCount()) );
+ const ULONG nAlignedWidth = AlignedWidth4Bytes( rAcc.Width() *
+ discretizeBitcount(nBitCount));
+ BOOL bNative = FALSE;
+
+ switch( rAcc.GetScanlineFormat() )
+ {
+ case( BMP_FORMAT_1BIT_MSB_PAL ):
+ case( BMP_FORMAT_4BIT_MSN_PAL ):
+ case( BMP_FORMAT_8BIT_PAL ):
+ case( BMP_FORMAT_24BIT_TC_BGR ):
+ {
+ if( rAcc.IsBottomUp() && ( rAcc.GetScanlineSize() == nAlignedWidth ) )
+ bNative = TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ rImageSize = rOStm.Tell();
+
+ if( bNative )
+ rOStm.Write( rAcc.GetBuffer(), nAlignedWidth * rAcc.Height() );
+ else
+ {
+ const long nWidth = rAcc.Width();
+ const long nHeight = rAcc.Height();
+ BYTE* pBuf = new BYTE[ nAlignedWidth ];
+ BYTE* pTmp;
+ BYTE cTmp;
+
+ switch( nBitCount )
+ {
+ case( 1 ):
+ {
+ for( long nY = nHeight - 1; nY >= 0L; nY-- )
+ {
+ pTmp = pBuf;
+ cTmp = 0;
+
+ for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ )
+ {
+ if( !nShift )
+ {
+ nShift = 8L;
+ *pTmp++ = cTmp;
+ cTmp = 0;
+ }
+
+ cTmp |= ( (BYTE) rAcc.GetPixel( nY, nX ) << --nShift );
+ }
+
+ *pTmp = cTmp;
+ rOStm.Write( pBuf, nAlignedWidth );
+ }
+ }
+ break;
+
+ case( 4 ):
+ {
+ for( long nY = nHeight - 1; nY >= 0L; nY-- )
+ {
+ pTmp = pBuf;
+ cTmp = 0;
+
+ for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ )
+ {
+ if( !nShift )
+ {
+ nShift = 2L;
+ *pTmp++ = cTmp;
+ cTmp = 0;
+ }
+
+ cTmp |= ( (BYTE) rAcc.GetPixel( nY, nX ) << ( --nShift << 2L ) );
+ }
+ *pTmp = cTmp;
+ rOStm.Write( pBuf, nAlignedWidth );
+ }
+ }
+ break;
+
+ case( 8 ):
+ {
+ for( long nY = nHeight - 1; nY >= 0L; nY-- )
+ {
+ pTmp = pBuf;
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ *pTmp++ = rAcc.GetPixel( nY, nX );
+
+ rOStm.Write( pBuf, nAlignedWidth );
+ }
+ }
+ break;
+
+ // #i59239# fallback to 24 bit format, if bitcount is non-default
+ default:
+ // FALLTHROUGH intended
+ case( 24 ):
+ {
+ BitmapColor aPixelColor;
+
+ for( long nY = nHeight - 1; nY >= 0L; nY-- )
+ {
+ pTmp = pBuf;
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aPixelColor = rAcc.GetPixel( nY, nX );
+ *pTmp++ = aPixelColor.GetBlue();
+ *pTmp++ = aPixelColor.GetGreen();
+ *pTmp++ = aPixelColor.GetRed();
+ }
+
+ rOStm.Write( pBuf, nAlignedWidth );
+ }
+ }
+ break;
+ }
+
+ delete[] pBuf;
+ }
+ }
+
+ rImageSize = rOStm.Tell() - rImageSize;
+
+ return( rOStm.GetError() == 0UL );
+}
+
+// ------------------------------------------------------------------
+
+void Bitmap::ImplDecodeRLE( BYTE* pBuffer, DIBInfoHeader& rHeader,
+ BitmapWriteAccess& rAcc, BOOL bRLE4 )
+{
+ Scanline pRLE = pBuffer;
+ long nY = rHeader.nHeight - 1L;
+ const ULONG nWidth = rAcc.Width();
+ ULONG nCountByte;
+ ULONG nRunByte;
+ ULONG nX = 0UL;
+ BYTE cTmp;
+ BOOL bEndDecoding = FALSE;
+
+ do
+ {
+ if( ( nCountByte = *pRLE++ ) == 0 )
+ {
+ nRunByte = *pRLE++;
+
+ if( nRunByte > 2 )
+ {
+ if( bRLE4 )
+ {
+ nCountByte = nRunByte >> 1;
+
+ for( ULONG i = 0UL; i < nCountByte; i++ )
+ {
+ cTmp = *pRLE++;
+
+ if( nX < nWidth )
+ rAcc.SetPixel( nY, nX++, cTmp >> 4 );
+
+ if( nX < nWidth )
+ rAcc.SetPixel( nY, nX++, cTmp & 0x0f );
+ }
+
+ if( nRunByte & 1 )
+ {
+ if( nX < nWidth )
+ rAcc.SetPixel( nY, nX++, *pRLE >> 4 );
+
+ pRLE++;
+ }
+
+ if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
+ pRLE++;
+ }
+ else
+ {
+ for( ULONG i = 0UL; i < nRunByte; i++ )
+ {
+ if( nX < nWidth )
+ rAcc.SetPixel( nY, nX++, *pRLE );
+
+ pRLE++;
+ }
+
+ if( nRunByte & 1 )
+ pRLE++;
+ }
+ }
+ else if( !nRunByte )
+ {
+ nY--;
+ nX = 0UL;
+ }
+ else if( nRunByte == 1 )
+ bEndDecoding = TRUE;
+ else
+ {
+ nX += *pRLE++;
+ nY -= *pRLE++;
+ }
+ }
+ else
+ {
+ cTmp = *pRLE++;
+
+ if( bRLE4 )
+ {
+ nRunByte = nCountByte >> 1;
+
+ for( ULONG i = 0UL; i < nRunByte; i++ )
+ {
+ if( nX < nWidth )
+ rAcc.SetPixel( nY, nX++, cTmp >> 4 );
+
+ if( nX < nWidth )
+ rAcc.SetPixel( nY, nX++, cTmp & 0x0f );
+ }
+
+ if( ( nCountByte & 1 ) && ( nX < nWidth ) )
+ rAcc.SetPixel( nY, nX++, cTmp >> 4 );
+ }
+ else
+ {
+ for( ULONG i = 0UL; ( i < nCountByte ) && ( nX < nWidth ); i++ )
+ rAcc.SetPixel( nY, nX++, cTmp );
+ }
+ }
+ }
+ while ( !bEndDecoding && ( nY >= 0L ) );
+}
+
+// ------------------------------------------------------------------
+
+BOOL Bitmap::ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, BOOL bRLE4 )
+{
+ const ULONG nWidth = rAcc.Width();
+ const ULONG nHeight = rAcc.Height();
+ ULONG nX;
+ ULONG nSaveIndex;
+ ULONG nCount;
+ ULONG nBufCount;
+ BYTE* pBuf = new BYTE[ ( nWidth << 1 ) + 2 ];
+ BYTE* pTmp;
+ BYTE cPix;
+ BYTE cLast;
+ BOOL bFound;
+
+ for ( long nY = nHeight - 1L; nY >= 0L; nY-- )
+ {
+ pTmp = pBuf;
+ nX = nBufCount = 0UL;
+
+ while( nX < nWidth )
+ {
+ nCount = 1L;
+ cPix = rAcc.GetPixel( nY, nX++ );
+
+ while( ( nX < nWidth ) && ( nCount < 255L ) && ( cPix == rAcc.GetPixel( nY, nX ) ) )
+ {
+ nX++;
+ nCount++;
+ }
+
+ if ( nCount > 1 )
+ {
+ *pTmp++ = (BYTE) nCount;
+ *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix );
+ nBufCount += 2;
+ }
+ else
+ {
+ cLast = cPix;
+ nSaveIndex = nX - 1UL;
+ bFound = FALSE;
+
+ while( ( nX < nWidth ) && ( nCount < 256L ) && ( cPix = rAcc.GetPixel( nY, nX ) ) != cLast )
+ {
+ nX++; nCount++;
+ cLast = cPix;
+ bFound = TRUE;
+ }
+
+ if ( bFound )
+ nX--;
+
+ if ( nCount > 3 )
+ {
+ *pTmp++ = 0;
+ *pTmp++ = (BYTE) --nCount;
+
+ if( bRLE4 )
+ {
+ for ( ULONG i = 0; i < nCount; i++, pTmp++ )
+ {
+ *pTmp = (BYTE) rAcc.GetPixel( nY, nSaveIndex++ ) << 4;
+
+ if ( ++i < nCount )
+ *pTmp |= rAcc.GetPixel( nY, nSaveIndex++ );
+ }
+
+ nCount = ( nCount + 1 ) >> 1;
+ }
+ else
+ {
+ for( ULONG i = 0UL; i < nCount; i++ )
+ *pTmp++ = rAcc.GetPixel( nY, nSaveIndex++ );
+ }
+
+ if ( nCount & 1 )
+ {
+ *pTmp++ = 0;
+ nBufCount += ( nCount + 3 );
+ }
+ else
+ nBufCount += ( nCount + 2 );
+ }
+ else
+ {
+ *pTmp++ = 1;
+ *pTmp++ = (BYTE) rAcc.GetPixel( nY, nSaveIndex ) << ( bRLE4 ? 4 : 0 );
+
+ if ( nCount == 3 )
+ {
+ *pTmp++ = 1;
+ *pTmp++ = (BYTE) rAcc.GetPixel( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 );
+ nBufCount += 4;
+ }
+ else
+ nBufCount += 2;
+ }
+ }
+ }
+
+ pBuf[ nBufCount++ ] = 0;
+ pBuf[ nBufCount++ ] = 0;
+
+ rOStm.Write( pBuf, nBufCount );
+ }
+
+ rOStm << (BYTE) 0;
+ rOStm << (BYTE) 1;
+
+ delete[] pBuf;
+
+ return( rOStm.GetError() == 0UL );
+}
diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx
new file mode 100644
index 000000000000..9e2a21b43e37
--- /dev/null
+++ b/vcl/source/gdi/bitmap3.cxx
@@ -0,0 +1,2203 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdlib.h>
+#include <vcl/bmpacc.hxx>
+#include <vcl/impoct.hxx>
+#include <vcl/octree.hxx>
+#include <impvect.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/bitmap.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define RGB15( _def_cR, _def_cG, _def_cB ) (((ULONG)(_def_cR)<<10UL)|((ULONG)(_def_cG)<<5UL)|(ULONG)(_def_cB))
+#define GAMMA( _def_cVal, _def_InvGamma ) ((BYTE)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
+
+#define CALC_ERRORS \
+ nTemp = p1T[nX++] >> 12; \
+ nBErr = MinMax( nTemp, 0, 255 ); \
+ nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
+ nTemp = p1T[nX++] >> 12; \
+ nGErr = MinMax( nTemp, 0, 255 ); \
+ nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
+ nTemp = p1T[nX] >> 12; \
+ nRErr = MinMax( nTemp, 0, 255 ); \
+ nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
+
+#define CALC_TABLES3 \
+ p2T[nX++] += FloydError3[nBErr]; \
+ p2T[nX++] += FloydError3[nGErr]; \
+ p2T[nX++] += FloydError3[nRErr];
+
+#define CALC_TABLES5 \
+ p2T[nX++] += FloydError5[nBErr]; \
+ p2T[nX++] += FloydError5[nGErr]; \
+ p2T[nX++] += FloydError5[nRErr];
+
+#define CALC_TABLES7 \
+ p1T[++nX] += FloydError7[nBErr]; \
+ p2T[nX++] += FloydError1[nBErr]; \
+ p1T[nX] += FloydError7[nGErr]; \
+ p2T[nX++] += FloydError1[nGErr]; \
+ p1T[nX] += FloydError7[nRErr]; \
+ p2T[nX] += FloydError1[nRErr];
+
+// -----------
+// - Statics -
+// -----------
+
+ULONG nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
+ULONG nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
+ULONG nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
+
+// ------------------------------------------------------------------------
+
+ULONG nVCLDitherLut[ 256 ] =
+{
+ 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
+ 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
+ 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
+ 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
+ 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
+ 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
+ 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
+ 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
+ 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
+ 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
+ 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
+ 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
+ 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
+ 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
+ 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
+ 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
+ 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
+ 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
+ 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
+ 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
+ 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
+ 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
+ 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
+ 25856, 38144, 21760
+};
+
+// ------------------------------------------------------------------------
+
+ULONG nVCLLut[ 256 ] =
+{
+ 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
+ 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
+ 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
+ 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
+ 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
+ 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
+ 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
+ 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
+ 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
+ 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
+ 102880,104166,105452,106738,108024,109310,110596,111882,
+ 113168,114454,115740,117026,118312,119598,120884,122170,
+ 123456,124742,126028,127314,128600,129886,131172,132458,
+ 133744,135030,136316,137602,138888,140174,141460,142746,
+ 144032,145318,146604,147890,149176,150462,151748,153034,
+ 154320,155606,156892,158178,159464,160750,162036,163322,
+ 164608,165894,167180,168466,169752,171038,172324,173610,
+ 174896,176182,177468,178754,180040,181326,182612,183898,
+ 185184,186470,187756,189042,190328,191614,192900,194186,
+ 195472,196758,198044,199330,200616,201902,203188,204474,
+ 205760,207046,208332,209618,210904,212190,213476,214762,
+ 216048,217334,218620,219906,221192,222478,223764,225050,
+ 226336,227622,228908,230194,231480,232766,234052,235338,
+ 236624,237910,239196,240482,241768,243054,244340,245626,
+ 246912,248198,249484,250770,252056,253342,254628,255914,
+ 257200,258486,259772,261058,262344,263630,264916,266202,
+ 267488,268774,270060,271346,272632,273918,275204,276490,
+ 277776,279062,280348,281634,282920,284206,285492,286778,
+ 288064,289350,290636,291922,293208,294494,295780,297066,
+ 298352,299638,300924,302210,303496,304782,306068,307354,
+ 308640,309926,311212,312498,313784,315070,316356,317642,
+ 318928,320214,321500,322786,324072,325358,326644,327930
+};
+
+// ------------------------------------------------------------------------
+
+long FloydMap[256] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+};
+
+// ------------------------------------------------------------------------
+
+long FloydError1[61] =
+{
+ -7680, -7424, -7168, -6912, -6656, -6400, -6144,
+ -5888, -5632, -5376, -5120, -4864, -4608, -4352,
+ -4096, -3840, -3584, -3328, -3072, -2816, -2560,
+ -2304, -2048, -1792, -1536, -1280, -1024, -768,
+ -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
+ 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
+ 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
+ 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
+};
+
+// ------------------------------------------------------------------------
+
+long FloydError3[61] =
+{
+ -23040, -22272, -21504, -20736, -19968, -19200,
+ -18432, -17664, -16896, -16128, -15360, -14592,
+ -13824, -13056, -12288, -11520, -10752, -9984,
+ -9216, -8448, -7680, -6912, -6144, -5376, -4608,
+ -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
+ 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
+ 8448, 9216, 9984, 10752, 11520, 12288, 13056,
+ 13824, 14592, 15360, 16128, 16896, 17664, 18432,
+ 19200, 19968, 20736, 21504, 22272, 23040
+};
+
+// ------------------------------------------------------------------------
+
+long FloydError5[61] =
+{
+ -38400, -37120, -35840, -34560, -33280, -32000,
+ -30720, -29440, -28160, -26880, -25600, -24320,
+ -23040, -21760, -20480, -19200, -17920, -16640,
+ -15360, -14080, -12800, -11520, -10240, -8960,
+ -7680, -6400, -5120, -3840, -2560, -1280, 0,
+ 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
+ 11520, 12800, 14080, 15360, 16640, 17920, 19200,
+ 20480, 21760, 23040, 24320, 25600, 26880, 28160,
+ 29440, 30720, 32000, 33280, 34560, 35840, 37120,
+ 38400
+};
+
+// ------------------------------------------------------------------------
+
+long FloydError7[61] =
+{
+ -53760, -51968, -50176, -48384, -46592, -44800,
+ -43008, -41216, -39424, -37632, -35840, -34048,
+ -32256, -30464, -28672, -26880, -25088, -23296,
+ -21504, -19712, -17920, -16128, -14336, -12544,
+ -10752, -8960, -7168, -5376, -3584, -1792, 0,
+ 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
+ 16128, 17920, 19712, 21504, 23296, 25088, 26880,
+ 28672, 30464, 32256, 34048, 35840, 37632, 39424,
+ 41216, 43008, 44800, 46592, 48384, 50176, 51968,
+ 53760
+};
+
+// ------------------------------------------------------------------------
+
+long FloydIndexMap[6] =
+{
+ -30, 21, 72, 123, 174, 225
+};
+
+// --------------------------
+// - ImplCreateDitherMatrix -
+// --------------------------
+
+void ImplCreateDitherMatrix( BYTE (*pDitherMatrix)[16][16] )
+{
+ double fVal = 3.125;
+ const double fVal16 = fVal / 16.;
+ long i, j, k, l;
+ USHORT pMtx[ 16 ][ 16 ];
+ USHORT nMax = 0;
+ static BYTE pMagic[4][4] = { { 0, 14, 3, 13, },
+ {11, 5, 8, 6, },
+ {12, 2, 15, 1, },
+ {7, 9, 4, 10 } };
+
+ // MagicSquare aufbauen
+ for ( i = 0; i < 4; i++ )
+ for ( j = 0; j < 4; j++ )
+ for ( k = 0; k < 4; k++ )
+ for ( l = 0; l < 4; l++ )
+ nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] =
+ (USHORT) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax );
+
+ // auf Intervall [0;254] skalieren
+ for ( i = 0, fVal = 254. / nMax; i < 16; i++ )
+ for( j = 0; j < 16; j++ )
+ (*pDitherMatrix)[i][j] = (BYTE) ( fVal * pMtx[i][j] );
+}
+
+// ----------
+// - Bitmap -
+// ----------
+
+BOOL Bitmap::Convert( BmpConversion eConversion )
+{
+ const USHORT nBitCount = GetBitCount();
+ BOOL bRet = FALSE;
+
+ switch( eConversion )
+ {
+ case( BMP_CONVERSION_1BIT_THRESHOLD ):
+ bRet = ImplMakeMono( 128 );
+ break;
+
+ case( BMP_CONVERSION_1BIT_MATRIX ):
+ bRet = ImplMakeMonoDither();
+ break;
+
+ case( BMP_CONVERSION_4BIT_GREYS ):
+ bRet = ImplMakeGreyscales( 16 );
+ break;
+
+ case( BMP_CONVERSION_4BIT_COLORS ):
+ {
+ if( nBitCount < 4 )
+ bRet = ImplConvertUp( 4, NULL );
+ else if( nBitCount > 4 )
+ bRet = ImplConvertDown( 4, NULL );
+ else
+ bRet = TRUE;
+ }
+ break;
+
+ case( BMP_CONVERSION_4BIT_TRANS ):
+ {
+ Color aTrans( BMP_COL_TRANS );
+
+ if( nBitCount < 4 )
+ bRet = ImplConvertUp( 4, &aTrans );
+ else
+ bRet = ImplConvertDown( 4, &aTrans );
+ }
+ break;
+
+ case( BMP_CONVERSION_8BIT_GREYS ):
+ bRet = ImplMakeGreyscales( 256 );
+ break;
+
+ case( BMP_CONVERSION_8BIT_COLORS ):
+ {
+ if( nBitCount < 8 )
+ bRet = ImplConvertUp( 8 );
+ else if( nBitCount > 8 )
+ bRet = ImplConvertDown( 8 );
+ else
+ bRet = TRUE;
+ }
+ break;
+
+ case( BMP_CONVERSION_8BIT_TRANS ):
+ {
+ Color aTrans( BMP_COL_TRANS );
+
+ if( nBitCount < 8 )
+ bRet = ImplConvertUp( 8, &aTrans );
+ else
+ bRet = ImplConvertDown( 8, &aTrans );
+ }
+ break;
+
+ case( BMP_CONVERSION_24BIT ):
+ {
+ if( nBitCount < 24 )
+ bRet = ImplConvertUp( 24, FALSE );
+ else
+ bRet = TRUE;
+ }
+ break;
+
+ case( BMP_CONVERSION_GHOSTED ):
+ bRet = ImplConvertGhosted();
+ break;
+
+ default:
+ DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" );
+ break;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplMakeMono( BYTE cThreshold )
+{
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), 1 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >=
+ cThreshold )
+ {
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ }
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+ else
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
+ cThreshold )
+ {
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ }
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplMakeMonoDither()
+{
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), 1 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+ BYTE pDitherMatrix[ 16 ][ 16 ];
+
+ ImplCreateDitherMatrix( &pDitherMatrix );
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
+ {
+ if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >
+ pDitherMatrix[ nModY ][ nX % 16 ] )
+ {
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ }
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+ else
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
+ {
+ if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
+ pDitherMatrix[ nModY ][ nX % 16 ] )
+ {
+ pWriteAcc->SetPixel( nY, nX, aWhite );
+ }
+ else
+ pWriteAcc->SetPixel( nY, nX, aBlack );
+ }
+ }
+ }
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplMakeGreyscales( USHORT nGreys )
+{
+ DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
+
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ const BitmapPalette& rPal = GetGreyPalette( nGreys );
+ ULONG nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
+ BOOL bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
+
+ if( !bPalDiffers )
+ bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
+
+ if( bPalDiffers )
+ {
+ Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ pWriteAcc->SetPixel( nY, nX,
+ (BYTE) ( pReadAcc->GetPaletteColor(
+ pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ) );
+ }
+ }
+ }
+ else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
+ pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ nShift += 8;
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ Scanline pReadScan = pReadAcc->GetScanline( nY );
+ Scanline pWriteScan = pWriteAcc->GetScanline( nY );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ const ULONG nB = *pReadScan++;
+ const ULONG nG = *pReadScan++;
+ const ULONG nR = *pReadScan++;
+
+ *pWriteScan++ = (BYTE) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
+ }
+ }
+ }
+ else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
+ pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ nShift += 8;
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ Scanline pReadScan = pReadAcc->GetScanline( nY );
+ Scanline pWriteScan = pWriteAcc->GetScanline( nY );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ const ULONG nR = *pReadScan++;
+ const ULONG nG = *pReadScan++;
+ const ULONG nB = *pReadScan++;
+
+ *pWriteScan++ = (BYTE) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
+ }
+ }
+ }
+ else
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, sal::static_int_cast<BYTE>(( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift) );
+ }
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+ else
+ {
+ ReleaseAccess( pReadAcc );
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplConvertUp( USHORT nBitCount, Color* pExtColor )
+{
+ DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
+
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ BitmapPalette aPal;
+ Bitmap aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+
+ if( pWriteAcc->HasPalette() )
+ {
+ const USHORT nOldCount = 1 << GetBitCount();
+ const BitmapPalette& rOldPal = pReadAcc->GetPalette();
+
+ aPal.SetEntryCount( 1 << nBitCount );
+
+ for( USHORT i = 0; i < nOldCount; i++ )
+ aPal[ i ] = rOldPal[ i ];
+
+ if( pExtColor )
+ aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
+
+ pWriteAcc->SetPalette( aPal );
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
+ }
+ else
+ {
+ if( pReadAcc->HasPalette() )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
+ }
+ else
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
+ }
+ }
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplConvertDown( USHORT nBitCount, Color* pExtColor )
+{
+ DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
+
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ BitmapPalette aPal;
+ Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const USHORT nCount = 1 << nBitCount;
+ const long nWidth = pWriteAcc->Width();
+ const long nWidth1 = nWidth - 1L;
+ const long nHeight = pWriteAcc->Height();
+ Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
+ InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
+ BitmapColor aColor;
+ ImpErrorQuad aErrQuad;
+ ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ];
+ ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ];
+ ImpErrorQuad* pQLine1 = pErrQuad1;
+ ImpErrorQuad* pQLine2 = 0;
+ long nX, nY;
+ long nYTmp = 0L;
+ BYTE cIndex;
+ BOOL bQ1 = TRUE;
+
+ if( pExtColor )
+ {
+ aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
+ aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
+ }
+
+ // set Black/White always, if we have enough space
+ if( aPal.GetEntryCount() < ( nCount - 1 ) )
+ {
+ aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
+ aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
+ aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
+ }
+
+ pWriteAcc->SetPalette( aPal );
+
+ for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
+ {
+ for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
+ {
+ if( pReadAcc->HasPalette() )
+ pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
+ else
+ pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
+ }
+ }
+
+ for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
+ {
+ // erstes ZeilenPixel
+ cIndex = (BYTE) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
+ pWriteAcc->SetPixel( nY, 0, cIndex );
+
+ for( nX = 1L; nX < nWidth1; nX++ )
+ {
+ cIndex = (BYTE) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
+ aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
+ pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
+ pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
+ pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
+ pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
+ pWriteAcc->SetPixel( nY, nX, cIndex );
+ }
+
+ // letztes ZeilenPixel
+ if( nX < nWidth )
+ {
+ cIndex = (BYTE) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
+ pWriteAcc->SetPixel( nY, nX, cIndex );
+ }
+
+ // Zeilenpuffer neu fuellen/kopieren
+ pQLine1 = pQLine2;
+ pQLine2 = ( bQ1 = !bQ1 ) != FALSE ? pErrQuad2 : pErrQuad1;
+
+ if( nYTmp < nHeight )
+ {
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ if( pReadAcc->HasPalette() )
+ pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
+ else
+ pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
+ }
+ }
+ }
+
+ // Zeilenpuffer zerstoeren
+ delete[] pErrQuad1;
+ delete[] pErrQuad2;
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplConvertGhosted()
+{
+ Bitmap aNewBmp;
+ BitmapReadAccess* pR = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pR )
+ {
+ if( pR->HasPalette() )
+ {
+ BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
+
+ for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
+ {
+ const BitmapColor& rOld = pR->GetPaletteColor( (USHORT) i );
+ aNewPal[ (USHORT) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
+ ( rOld.GetGreen() >> 1 ) | 0x80,
+ ( rOld.GetBlue() >> 1 ) | 0x80 );
+ }
+
+ aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
+ BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
+
+ if( pW )
+ {
+ pW->CopyBuffer( *pR );
+ aNewBmp.ReleaseAccess( pW );
+ bRet = TRUE;
+ }
+ }
+ else
+ {
+ aNewBmp = Bitmap( GetSizePixel(), 24 );
+
+ BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
+
+ if( pW )
+ {
+ const long nWidth = pR->Width(), nHeight = pR->Height();
+
+ for( long nY = 0; nY < nHeight; nY++ )
+ {
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ const BitmapColor aOld( pR->GetPixel( nY, nX ) );
+ pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
+ ( aOld.GetGreen() >> 1 ) | 0x80,
+ ( aOld.GetBlue() >> 1 ) | 0x80 ) );
+
+ }
+ }
+
+ aNewBmp.ReleaseAccess( pW );
+ bRet = TRUE;
+ }
+ }
+
+ ReleaseAccess( pR );
+ }
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag )
+{
+ BOOL bRet;
+
+ if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
+ {
+ if( BMP_SCALE_FAST == nScaleFlag )
+ bRet = ImplScaleFast( rScaleX, rScaleY );
+ else if( BMP_SCALE_INTERPOLATE == nScaleFlag )
+ bRet = ImplScaleInterpolate( rScaleX, rScaleY );
+ else
+ bRet = FALSE;
+ }
+ else
+ bRet = TRUE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::Scale( const Size& rNewSize, ULONG nScaleFlag )
+{
+ const Size aSize( GetSizePixel() );
+ BOOL bRet;
+
+ if( aSize.Width() && aSize.Height() )
+ {
+ bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
+ (double) rNewSize.Height() / aSize.Height(),
+ nScaleFlag );
+ }
+ else
+ bRet = TRUE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
+{
+ const Size aSizePix( GetSizePixel() );
+ const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
+ const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
+ BOOL bRet = FALSE;
+
+ if( nNewWidth && nNewHeight )
+ {
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pReadAcc && pWriteAcc )
+ {
+ const long nScanlineSize = pWriteAcc->GetScanlineSize();
+ const long nNewWidth1 = nNewWidth - 1L;
+ const long nNewHeight1 = nNewHeight - 1L;
+ const long nWidth1 = pReadAcc->Width() - 1L;
+ const long nHeight1 = pReadAcc->Height() - 1L;
+ long* pLutX = new long[ nNewWidth ];
+ long* pLutY = new long[ nNewHeight ];
+ long nX, nY, nMapY, nActY = 0L;
+
+ if( nNewWidth1 && nNewHeight1 )
+ {
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ pLutX[ nX ] = nX * nWidth1 / nNewWidth1;
+
+ for( nY = 0L; nY < nNewHeight; nY++ )
+ pLutY[ nY ] = nY * nHeight1 / nNewHeight1;
+
+ while( nActY < nNewHeight )
+ {
+ nMapY = pLutY[ nActY ];
+
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
+
+ while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
+ {
+ memcpy( pWriteAcc->GetScanline( nActY + 1L ),
+ pWriteAcc->GetScanline( nActY ), nScanlineSize );
+ nActY++;
+ }
+
+ nActY++;
+ }
+
+ bRet = TRUE;
+ }
+
+ delete[] pLutX;
+ delete[] pLutY;
+ }
+
+ ReleaseAccess( pReadAcc );
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ if( bRet )
+ ImplAssignWithSize( aNewBmp );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
+{
+ const Size aSizePix( GetSizePixel() );
+ const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
+ const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
+ BOOL bRet = FALSE;
+
+ if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
+ {
+ BitmapColor aCol0;
+ BitmapColor aCol1;
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ long nWidth = pReadAcc->Width();
+ long nHeight = pReadAcc->Height();
+ Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+ long* pLutInt;
+ long* pLutFrac;
+ long nX, nY;
+ long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
+ double fTemp;
+ long nTemp;
+
+ if( pReadAcc && pWriteAcc )
+ {
+ const long nNewWidth1 = nNewWidth - 1L;
+ const long nWidth1 = pReadAcc->Width() - 1L;
+ const double fRevScaleX = (double) nWidth1 / nNewWidth1;
+
+ pLutInt = new long[ nNewWidth ];
+ pLutFrac = new long[ nNewWidth ];
+
+ for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
+ {
+ fTemp = nX * fRevScaleX;
+ pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
+ fTemp -= pLutInt[ nX ];
+ pLutFrac[ nX ] = (long) ( fTemp * 1024. );
+ }
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ if( 1 == nWidth )
+ {
+ aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) );
+
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ else
+ {
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ {
+ nTemp = pLutInt[ nX ];
+
+ aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) );
+ aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) );
+
+ nTemp = pLutFrac[ nX ];
+
+ lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
+ lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
+ lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
+
+ aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
+ aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
+ aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
+
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ if( 1 == nWidth )
+ {
+ aCol0 = pReadAcc->GetPixel( nY, 0 );
+
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ else
+ {
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ {
+ nTemp = pLutInt[ nX ];
+
+ aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
+ aCol1 = pReadAcc->GetPixel( nY, nTemp );
+
+ nTemp = pLutFrac[ nX ];
+
+ lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
+ lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
+ lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
+
+ aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
+ aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
+ aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
+
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ }
+ }
+ }
+
+ delete[] pLutInt;
+ delete[] pLutFrac;
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ if( bRet )
+ {
+ bRet = FALSE;
+ ImplAssignWithSize( aNewBmp );
+ pReadAcc = AcquireReadAccess();
+ aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
+ pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pReadAcc && pWriteAcc )
+ {
+ const long nNewHeight1 = nNewHeight - 1L;
+ const long nHeight1 = pReadAcc->Height() - 1L;
+ const double fRevScaleY = (double) nHeight1 / nNewHeight1;
+
+ pLutInt = new long[ nNewHeight ];
+ pLutFrac = new long[ nNewHeight ];
+
+ for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
+ {
+ fTemp = nY * fRevScaleY;
+ pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
+ fTemp -= pLutInt[ nY ];
+ pLutFrac[ nY ] = (long) ( fTemp * 1024. );
+ }
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ {
+ if( 1 == nHeight )
+ {
+ aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) );
+
+ for( nY = 0L; nY < nNewHeight; nY++ )
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ else
+ {
+ for( nY = 0L; nY < nNewHeight; nY++ )
+ {
+ nTemp = pLutInt[ nY ];
+
+ aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) );
+ aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) );
+
+ nTemp = pLutFrac[ nY ];
+
+ lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
+ lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
+ lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
+
+ aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
+ aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
+ aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
+
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ }
+ }
+ }
+ else
+ {
+ for( nX = 0L; nX < nNewWidth; nX++ )
+ {
+ if( 1 == nHeight )
+ {
+ aCol0 = pReadAcc->GetPixel( 0, nX );
+
+ for( nY = 0L; nY < nNewHeight; nY++ )
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ else
+ {
+ for( nY = 0L; nY < nNewHeight; nY++ )
+ {
+ nTemp = pLutInt[ nY ];
+
+ aCol0 = pReadAcc->GetPixel( nTemp++, nX );
+ aCol1 = pReadAcc->GetPixel( nTemp, nX );
+
+ nTemp = pLutFrac[ nY ];
+
+ lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
+ lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
+ lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
+
+ aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
+ aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
+ aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
+
+ pWriteAcc->SetPixel( nY, nX, aCol0 );
+ }
+ }
+ }
+ }
+
+ delete[] pLutInt;
+ delete[] pLutFrac;
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ if( bRet )
+ ImplAssignWithSize( aNewBmp );
+ }
+ }
+
+ if( !bRet )
+ bRet = ImplScaleFast( rScaleX, rScaleY );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::Dither( ULONG nDitherFlags )
+{
+ BOOL bRet = FALSE;
+
+ const Size aSizePix( GetSizePixel() );
+
+ if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
+ bRet = TRUE;
+ else if( nDitherFlags & BMP_DITHER_MATRIX )
+ bRet = ImplDitherMatrix();
+ else if( nDitherFlags & BMP_DITHER_FLOYD )
+ bRet = ImplDitherFloyd();
+ else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
+ bRet = ImplDitherFloyd16();
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplDitherMatrix()
+{
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ Bitmap aNewBmp( GetSizePixel(), 8 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc && pWriteAcc )
+ {
+ const ULONG nWidth = pReadAcc->Width();
+ const ULONG nHeight = pReadAcc->Height();
+ BitmapColor aIndex( (BYTE) 0 );
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( ULONG nY = 0UL; nY < nHeight; nY++ )
+ {
+ for( ULONG nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
+ {
+ const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
+ const ULONG nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
+ const ULONG nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
+ const ULONG nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
+ const ULONG nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
+
+ aIndex.SetIndex( (BYTE) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
+ pWriteAcc->SetPixel( nY, nX, aIndex );
+ }
+ }
+ }
+ else
+ {
+ for( ULONG nY = 0UL; nY < nHeight; nY++ )
+ {
+ for( ULONG nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
+ {
+ const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) );
+ const ULONG nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
+ const ULONG nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
+ const ULONG nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
+ const ULONG nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
+
+ aIndex.SetIndex( (BYTE) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
+ pWriteAcc->SetPixel( nY, nX, aIndex );
+ }
+ }
+ }
+
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplDitherFloyd()
+{
+ const Size aSize( GetSizePixel() );
+ BOOL bRet = FALSE;
+
+ if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
+ {
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ Bitmap aNewBmp( GetSizePixel(), 8 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pReadAcc && pWriteAcc )
+ {
+ BitmapColor aColor;
+ long nWidth = pReadAcc->Width();
+ long nWidth1 = nWidth - 1L;
+ long nHeight = pReadAcc->Height();
+ long nX;
+ long nW = nWidth * 3L;
+ long nW2 = nW - 3L;
+ long nRErr, nGErr, nBErr;
+ long nRC, nGC, nBC;
+ long nTemp;
+ long nZ;
+ long* p1 = new long[ nW ];
+ long* p2 = new long[ nW ];
+ long* p1T = p1;
+ long* p2T = p2;
+ long* pTmp;
+ BOOL bPal = pReadAcc->HasPalette();
+
+ pTmp = p2T;
+
+ if( bPal )
+ {
+ for( nZ = 0; nZ < nWidth; nZ++ )
+ {
+ aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) );
+
+ *pTmp++ = (long) aColor.GetBlue() << 12;
+ *pTmp++ = (long) aColor.GetGreen() << 12;
+ *pTmp++ = (long) aColor.GetRed() << 12;
+ }
+ }
+ else
+ {
+ for( nZ = 0; nZ < nWidth; nZ++ )
+ {
+ aColor = pReadAcc->GetPixel( 0, nZ );
+
+ *pTmp++ = (long) aColor.GetBlue() << 12;
+ *pTmp++ = (long) aColor.GetGreen() << 12;
+ *pTmp++ = (long) aColor.GetRed() << 12;
+ }
+ }
+
+ for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
+ {
+ pTmp = p1T;
+ p1T = p2T;
+ p2T = pTmp;
+
+ if( nY < nHeight )
+ {
+ if( bPal )
+ {
+ for( nZ = 0; nZ < nWidth; nZ++ )
+ {
+ aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) );
+
+ *pTmp++ = (long) aColor.GetBlue() << 12;
+ *pTmp++ = (long) aColor.GetGreen() << 12;
+ *pTmp++ = (long) aColor.GetRed() << 12;
+ }
+ }
+ else
+ {
+ for( nZ = 0; nZ < nWidth; nZ++ )
+ {
+ aColor = pReadAcc->GetPixel( nY, nZ );
+
+ *pTmp++ = (long) aColor.GetBlue() << 12;
+ *pTmp++ = (long) aColor.GetGreen() << 12;
+ *pTmp++ = (long) aColor.GetRed() << 12;
+ }
+ }
+ }
+
+ // erstes Pixel gesondert betrachten
+ nX = 0;
+ CALC_ERRORS;
+ CALC_TABLES7;
+ nX -= 5;
+ CALC_TABLES5;
+ pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
+
+ // mittlere Pixel ueber Schleife
+ long nXAcc;
+ for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
+ {
+ CALC_ERRORS;
+ CALC_TABLES7;
+ nX -= 8;
+ CALC_TABLES3;
+ CALC_TABLES5;
+ pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
+ }
+
+ // letztes Pixel gesondert betrachten
+ CALC_ERRORS;
+ nX -= 5;
+ CALC_TABLES3;
+ CALC_TABLES5;
+ pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
+ }
+
+ delete[] p1;
+ delete[] p2;
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aPrefSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aPrefSize;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplDitherFloyd16()
+{
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ Bitmap aNewBmp( GetSizePixel(), 24 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc && pWriteAcc )
+ {
+ const long nWidth = pWriteAcc->Width();
+ const long nWidth1 = nWidth - 1L;
+ const long nHeight = pWriteAcc->Height();
+ BitmapColor aColor;
+ BitmapColor aBestCol;
+ ImpErrorQuad aErrQuad;
+ ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ];
+ ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ];
+ ImpErrorQuad* pQLine1 = pErrQuad1;
+ ImpErrorQuad* pQLine2 = 0;
+ long nX, nY;
+ long nYTmp = 0L;
+ BOOL bQ1 = TRUE;
+
+ for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
+ for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
+ pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
+
+ for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
+ {
+ // erstes ZeilenPixel
+ aBestCol = pQLine1[ 0 ].ImplGetColor();
+ aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
+ aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
+ aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
+ pWriteAcc->SetPixel( nY, 0, aBestCol );
+
+ for( nX = 1L; nX < nWidth1; nX++ )
+ {
+ aColor = pQLine1[ nX ].ImplGetColor();
+ aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
+ aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
+ aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
+ aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
+ pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
+ pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
+ pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
+ pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
+ pWriteAcc->SetPixel( nY, nX, aBestCol );
+ }
+
+ // letztes ZeilenPixel
+ aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
+ aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
+ aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
+ aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
+ pWriteAcc->SetPixel( nY, nX, aBestCol );
+
+ // Zeilenpuffer neu fuellen/kopieren
+ pQLine1 = pQLine2;
+ pQLine2 = ( bQ1 = !bQ1 ) != FALSE ? pErrQuad2 : pErrQuad1;
+
+ if( nYTmp < nHeight )
+ for( nX = 0L; nX < nWidth; nX++ )
+ pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
+ }
+
+ // Zeilenpuffer zerstoeren
+ delete[] pErrQuad1;
+ delete[] pErrQuad2;
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ReduceColors( USHORT nColorCount, BmpReduce eReduce )
+{
+ BOOL bRet;
+
+ if( GetColorCount() <= (ULONG) nColorCount )
+ bRet = TRUE;
+ else if( nColorCount )
+ {
+ if( BMP_REDUCE_SIMPLE == eReduce )
+ bRet = ImplReduceSimple( nColorCount );
+ else if( BMP_REDUCE_POPULAR == eReduce )
+ bRet = ImplReducePopular( nColorCount );
+ else
+ bRet = ImplReduceMedian( nColorCount );
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplReduceSimple( USHORT nColorCount )
+{
+ Bitmap aNewBmp;
+ BitmapReadAccess* pRAcc = AcquireReadAccess();
+ const USHORT nColCount = Min( nColorCount, (USHORT) 256 );
+ USHORT nBitCount;
+ BOOL bRet = FALSE;
+
+ if( nColCount <= 2 )
+ nBitCount = 1;
+ else if( nColCount <= 16 )
+ nBitCount = 4;
+ else
+ nBitCount = 8;
+
+ if( pRAcc )
+ {
+ Octree aOct( *pRAcc, nColCount );
+ const BitmapPalette& rPal = aOct.GetPalette();
+ BitmapWriteAccess* pWAcc;
+
+ aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
+ pWAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ const long nWidth = pRAcc->Width();
+ const long nHeight = pRAcc->Height();
+
+ if( pRAcc->HasPalette() )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX =0L; nX < nWidth; nX++ )
+ pWAcc->SetPixel( nY, nX, (BYTE) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) );
+ }
+ else
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX =0L; nX < nWidth; nX++ )
+ pWAcc->SetPixel( nY, nX, (BYTE) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) );
+ }
+
+ aNewBmp.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pRAcc );
+ }
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+struct PopularColorCount
+{
+ sal_uInt32 mnIndex;
+ sal_uInt32 mnCount;
+};
+
+// ------------------------------------------------------------------------
+
+extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
+{
+ int nRet;
+
+ if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
+ nRet = 1;
+ else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
+ nRet = 0;
+ else
+ nRet = -1;
+
+ return nRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplReducePopular( USHORT nColCount )
+{
+ BitmapReadAccess* pRAcc = AcquireReadAccess();
+ USHORT nBitCount;
+ BOOL bRet = FALSE;
+
+ if( nColCount > 256 )
+ nColCount = 256;
+
+ if( nColCount < 17 )
+ nBitCount = 4;
+ else
+ nBitCount = 8;
+
+ if( pRAcc )
+ {
+ const sal_uInt32 nValidBits = 4;
+ const sal_uInt32 nRightShiftBits = 8 - nValidBits;
+ const sal_uInt32 nLeftShiftBits1 = nValidBits;
+ const sal_uInt32 nLeftShiftBits2 = nValidBits << 1;
+ const sal_uInt32 nColorsPerComponent = 1 << nValidBits;
+ const sal_uInt32 nColorOffset = 256 / nColorsPerComponent;
+ const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
+ const long nWidth = pRAcc->Width();
+ const long nHeight = pRAcc->Height();
+ PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ];
+ long nX, nY, nR, nG, nB, nIndex;
+
+ rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
+
+ for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
+ {
+ for( nG = 0; nG < 256; nG += nColorOffset )
+ {
+ for( nB = 0; nB < 256; nB += nColorOffset )
+ {
+ pCountTable[ nIndex ].mnIndex = nIndex;
+ nIndex++;
+ }
+ }
+ }
+
+ if( pRAcc->HasPalette() )
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
+ pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
+ ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
+ ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
+ pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
+ ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
+ ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
+ }
+ }
+ }
+
+ BitmapPalette aNewPal( nColCount );
+
+ qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
+
+ for( USHORT n = 0; n < nColCount; n++ )
+ {
+ const PopularColorCount& rPop = pCountTable[ n ];
+ aNewPal[ n ] = BitmapColor( (BYTE) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
+ (BYTE) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
+ (BYTE) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
+ }
+
+ Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
+ BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ BitmapColor aDstCol( (BYTE) 0 );
+ BYTE* pIndexMap = new BYTE[ nTotalColors ];
+
+ for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
+ for( nG = 0; nG < 256; nG += nColorOffset )
+ for( nB = 0; nB < 256; nB += nColorOffset )
+ pIndexMap[ nIndex++ ] = (BYTE) aNewPal.GetBestIndex( BitmapColor( (BYTE) nR, (BYTE) nG, (BYTE) nB ) );
+
+ if( pRAcc->HasPalette() )
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
+ aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
+ ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
+ ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
+ pWAcc->SetPixel( nY, nX, aDstCol );
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nHeight; nY++ )
+ {
+ for( nX = 0L; nX < nWidth; nX++ )
+ {
+ const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
+ aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
+ ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
+ ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
+ pWAcc->SetPixel( nY, nX, aDstCol );
+ }
+ }
+ }
+
+ delete[] pIndexMap;
+ aNewBmp.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ delete[] pCountTable;
+ ReleaseAccess( pRAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplReduceMedian( USHORT nColCount )
+{
+ BitmapReadAccess* pRAcc = AcquireReadAccess();
+ USHORT nBitCount;
+ BOOL bRet = FALSE;
+
+ if( nColCount < 17 )
+ nBitCount = 4;
+ else if( nColCount < 257 )
+ nBitCount = 8;
+ else
+ {
+ DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
+ nBitCount = 8;
+ nColCount = 256;
+ }
+
+ if( pRAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), nBitCount );
+ BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ const ULONG nSize = 32768UL * sizeof( ULONG );
+ ULONG* pColBuf = (ULONG*) rtl_allocateMemory( nSize );
+ const long nWidth = pWAcc->Width();
+ const long nHeight = pWAcc->Height();
+ long nIndex = 0L;
+
+ memset( (HPBYTE) pColBuf, 0, nSize );
+
+ // create Buffer
+ if( pRAcc->HasPalette() )
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
+ pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
+ }
+ }
+ }
+ else
+ {
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
+ pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
+ }
+ }
+ }
+
+ // create palette via median cut
+ BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
+ ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
+ nColCount, nWidth * nHeight, nIndex );
+
+ // do mapping of colors to palette
+ InverseColorMap aMap( aPal );
+ pWAcc->SetPalette( aPal );
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pWAcc->SetPixel( nY, nX, (BYTE) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) );
+
+ rtl_freeMemory( pColBuf );
+ aNewBmp.ReleaseAccess( pWAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pRAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void Bitmap::ImplMedianCut( ULONG* pColBuf, BitmapPalette& rPal,
+ long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
+ long nColors, long nPixels, long& rIndex )
+{
+ if( !nPixels )
+ return;
+
+ BitmapColor aCol;
+ const long nRLen = nR2 - nR1;
+ const long nGLen = nG2 - nG1;
+ const long nBLen = nB2 - nB1;
+ long nR, nG, nB;
+ ULONG* pBuf = pColBuf;
+
+ if( !nRLen && !nGLen && !nBLen )
+ {
+ if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
+ {
+ aCol.SetRed( (BYTE) ( nR1 << 3 ) );
+ aCol.SetGreen( (BYTE) ( nG1 << 3 ) );
+ aCol.SetBlue( (BYTE) ( nB1 << 3 ) );
+ rPal[ (USHORT) rIndex++ ] = aCol;
+ }
+ }
+ else
+ {
+ if( 1 == nColors || 1 == nPixels )
+ {
+ long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
+
+ for( nR = nR1; nR <= nR2; nR++ )
+ {
+ for( nG = nG1; nG <= nG2; nG++ )
+ {
+ for( nB = nB1; nB <= nB2; nB++ )
+ {
+ nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
+
+ if( nPixSum )
+ {
+ nRSum += nR * nPixSum;
+ nGSum += nG * nPixSum;
+ nBSum += nB * nPixSum;
+ }
+ }
+ }
+ }
+
+ aCol.SetRed( (BYTE) ( ( nRSum / nPixels ) << 3 ) );
+ aCol.SetGreen( (BYTE) ( ( nGSum / nPixels ) << 3 ) );
+ aCol.SetBlue( (BYTE) ( ( nBSum / nPixels ) << 3 ) );
+ rPal[ (USHORT) rIndex++ ] = aCol;
+ }
+ else
+ {
+ const long nTest = ( nPixels >> 1 );
+ long nPixOld = 0;
+ long nPixNew = 0;
+
+ if( nBLen > nGLen && nBLen > nRLen )
+ {
+ nB = nB1 - 1;
+
+ while( nPixNew < nTest )
+ {
+ nB++, nPixOld = nPixNew;
+ for( nR = nR1; nR <= nR2; nR++ )
+ for( nG = nG1; nG <= nG2; nG++ )
+ nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
+ }
+
+ if( nB < nB2 )
+ {
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
+ }
+ else
+ {
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
+ }
+ }
+ else if( nGLen > nRLen )
+ {
+ nG = nG1 - 1;
+
+ while( nPixNew < nTest )
+ {
+ nG++, nPixOld = nPixNew;
+ for( nR = nR1; nR <= nR2; nR++ )
+ for( nB = nB1; nB <= nB2; nB++ )
+ nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
+ }
+
+ if( nG < nG2 )
+ {
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
+ }
+ else
+ {
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
+ ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
+ }
+ }
+ else
+ {
+ nR = nR1 - 1;
+
+ while( nPixNew < nTest )
+ {
+ nR++, nPixOld = nPixNew;
+ for( nG = nG1; nG <= nG2; nG++ )
+ for( nB = nB1; nB <= nB2; nB++ )
+ nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
+ }
+
+ if( nR < nR2 )
+ {
+ ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
+ ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
+ }
+ else
+ {
+ ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
+ ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::Vectorize( PolyPolygon& rPolyPoly, ULONG nFlags, const Link* pProgress )
+{
+ return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::Vectorize( GDIMetaFile& rMtf, BYTE cReduce, ULONG nFlags, const Link* pProgress )
+{
+ return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
+ short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
+ double fGamma, BOOL bInvert )
+{
+ BOOL bRet = FALSE;
+
+ // nothing to do => return quickly
+ if( !nLuminancePercent && !nContrastPercent &&
+ !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
+ ( fGamma == 1.0 ) && !bInvert )
+ {
+ bRet = TRUE;
+ }
+ else
+ {
+ BitmapWriteAccess* pAcc = AcquireWriteAccess();
+
+ if( pAcc )
+ {
+ BitmapColor aCol;
+ const long nW = pAcc->Width();
+ const long nH = pAcc->Height();
+ BYTE* cMapR = new BYTE[ 256 ];
+ BYTE* cMapG = new BYTE[ 256 ];
+ BYTE* cMapB = new BYTE[ 256 ];
+ long nX, nY;
+ double fM, fROff, fGOff, fBOff, fOff;
+
+ // calculate slope
+ if( nContrastPercent >= 0 )
+ fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
+ else
+ fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
+
+ // total offset = luminance offset + contrast offset
+ fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
+
+ // channel offset = channel offset + total offset
+ fROff = nChannelRPercent * 2.55 + fOff;
+ fGOff = nChannelGPercent * 2.55 + fOff;
+ fBOff = nChannelBPercent * 2.55 + fOff;
+
+ // calculate gamma value
+ fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
+ const BOOL bGamma = ( fGamma != 1.0 );
+
+ // create mapping table
+ for( nX = 0L; nX < 256L; nX++ )
+ {
+ cMapR[ nX ] = (BYTE) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
+ cMapG[ nX ] = (BYTE) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
+ cMapB[ nX ] = (BYTE) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
+
+ if( bGamma )
+ {
+ cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
+ cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
+ cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
+ }
+
+ if( bInvert )
+ {
+ cMapR[ nX ] = ~cMapR[ nX ];
+ cMapG[ nX ] = ~cMapG[ nX ];
+ cMapB[ nX ] = ~cMapB[ nX ];
+ }
+ }
+
+ // do modifying
+ if( pAcc->HasPalette() )
+ {
+ BitmapColor aNewCol;
+
+ for( USHORT i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
+ {
+ const BitmapColor& rCol = pAcc->GetPaletteColor( i );
+ aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
+ aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
+ aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
+ pAcc->SetPaletteColor( i, aNewCol );
+ }
+ }
+ else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
+ {
+ for( nY = 0L; nY < nH; nY++ )
+ {
+ Scanline pScan = pAcc->GetScanline( nY );
+
+ for( nX = 0L; nX < nW; nX++ )
+ {
+ *pScan = cMapB[ *pScan ]; pScan++;
+ *pScan = cMapG[ *pScan ]; pScan++;
+ *pScan = cMapR[ *pScan ]; pScan++;
+ }
+ }
+ }
+ else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
+ {
+ for( nY = 0L; nY < nH; nY++ )
+ {
+ Scanline pScan = pAcc->GetScanline( nY );
+
+ for( nX = 0L; nX < nW; nX++ )
+ {
+ *pScan = cMapR[ *pScan ]; pScan++;
+ *pScan = cMapG[ *pScan ]; pScan++;
+ *pScan = cMapB[ *pScan ]; pScan++;
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nH; nY++ )
+ {
+ for( nX = 0L; nX < nW; nX++ )
+ {
+ aCol = pAcc->GetPixel( nY, nX );
+ aCol.SetRed( cMapR[ aCol.GetRed() ] );
+ aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
+ aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
+ pAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+ }
+
+ delete[] cMapR;
+ delete[] cMapG;
+ delete[] cMapB;
+ ReleaseAccess( pAcc );
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
diff --git a/vcl/source/gdi/bitmap4.cxx b/vcl/source/gdi/bitmap4.cxx
new file mode 100644
index 000000000000..b64bcd8fe540
--- /dev/null
+++ b/vcl/source/gdi/bitmap4.cxx
@@ -0,0 +1,1009 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdlib.h>
+#include <vos/macros.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/bitmap.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define S2(a,b) { register long t; if( ( t = b - a ) < 0 ) { a += t; b -= t; } }
+#define MN3(a,b,c) S2(a,b); S2(a,c);
+#define MX3(a,b,c) S2(b,c); S2(a,c);
+#define MNMX3(a,b,c) MX3(a,b,c); S2(a,b);
+#define MNMX4(a,b,c,d) S2(a,b); S2(c,d); S2(a,c); S2(b,d);
+#define MNMX5(a,b,c,d,e) S2(a,b); S2(c,d); MN3(a,c,e); MX3(b,d,e);
+#define MNMX6(a,b,c,d,e,f) S2(a,d); S2(b,e); S2(c,f); MN3(a,b,c); MX3(d,e,f);
+
+// ----------
+// - Bitmap -
+// ----------
+
+BOOL Bitmap::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
+{
+ BOOL bRet = FALSE;
+
+ switch( eFilter )
+ {
+ case( BMP_FILTER_SMOOTH ):
+ {
+ const long pSmoothMatrix[] = { 1, 2, 1, 2, 5, 2, 1, 2, 1 };
+ bRet = ImplConvolute3( &pSmoothMatrix[ 0 ], 17, pFilterParam, pProgress );
+ }
+ break;
+
+ case( BMP_FILTER_SHARPEN ):
+ {
+ const long pSharpenMatrix[] = { -1, -1, -1, -1, 16, -1, -1, -1, -1 };
+ bRet = ImplConvolute3( &pSharpenMatrix[ 0 ], 8, pFilterParam, pProgress );
+ }
+ break;
+
+ case( BMP_FILTER_REMOVENOISE ):
+ bRet = ImplMedianFilter( pFilterParam, pProgress );
+ break;
+
+ case( BMP_FILTER_SOBEL_GREY ):
+ bRet = ImplSobelGrey( pFilterParam, pProgress );
+ break;
+
+ case( BMP_FILTER_SOLARIZE ):
+ bRet = ImplSolarize( pFilterParam, pProgress );
+ break;
+
+ case( BMP_FILTER_SEPIA ):
+ bRet = ImplSepia( pFilterParam, pProgress );
+ break;
+
+ case( BMP_FILTER_MOSAIC ):
+ bRet = ImplMosaic( pFilterParam, pProgress );
+ break;
+
+ case( BMP_FILTER_EMBOSS_GREY ):
+ bRet = ImplEmbossGrey( pFilterParam, pProgress );
+ break;
+
+ case( BMP_FILTER_POPART ):
+ bRet = ImplPopArt( pFilterParam, pProgress );
+ break;
+
+ default:
+ DBG_ERROR( "Bitmap::Convert(): Unsupported filter" );
+ break;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL Bitmap::ImplConvolute3( const long* pMatrix, long nDivisor,
+ const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
+{
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), 24 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
+ const long nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
+ long* pColm = new long[ nWidth2 ];
+ long* pRows = new long[ nHeight2 ];
+ BitmapColor* pColRow1 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ];
+ BitmapColor* pColRow2 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ];
+ BitmapColor* pColRow3 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ];
+ BitmapColor* pRowTmp1 = pColRow1;
+ BitmapColor* pRowTmp2 = pColRow2;
+ BitmapColor* pRowTmp3 = pColRow3;
+ BitmapColor* pColor;
+ long nY, nX, i, nSumR, nSumG, nSumB, nMatrixVal, nTmp;
+ long (*pKoeff)[ 256 ] = new long[ 9 ][ 256 ];
+ long* pTmp;
+
+ // create LUT of products of matrix value and possible color component values
+ for( nY = 0; nY < 9; nY++ )
+ for( nX = nTmp = 0, nMatrixVal = pMatrix[ nY ]; nX < 256; nX++, nTmp += nMatrixVal )
+ pKoeff[ nY ][ nX ] = nTmp;
+
+ // create column LUT
+ for( i = 0; i < nWidth2; i++ )
+ pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
+
+ pColm[ nWidth + 1 ] = pColm[ nWidth ];
+
+ // create row LUT
+ for( i = 0; i < nHeight2; i++ )
+ pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
+
+ pRows[ nHeight + 1 ] = pRows[ nHeight ];
+
+ // read first three rows of bitmap color
+ for( i = 0; i < nWidth2; i++ )
+ {
+ pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
+ pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
+ pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
+ }
+
+ // do convolution
+ for( nY = 0; nY < nHeight; )
+ {
+ for( nX = 0; nX < nWidth; nX++ )
+ {
+ // first row
+ nSumR = ( pTmp = pKoeff[ 0 ] )[ ( pColor = pRowTmp1 + nX )->GetRed() ];
+ nSumG = pTmp[ pColor->GetGreen() ];
+ nSumB = pTmp[ pColor->GetBlue() ];
+
+ nSumR += ( pTmp = pKoeff[ 1 ] )[ ( ++pColor )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ nSumR += ( pTmp = pKoeff[ 2 ] )[ ( ++pColor )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ // second row
+ nSumR += ( pTmp = pKoeff[ 3 ] )[ ( pColor = pRowTmp2 + nX )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ nSumR += ( pTmp = pKoeff[ 4 ] )[ ( ++pColor )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ nSumR += ( pTmp = pKoeff[ 5 ] )[ ( ++pColor )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ // third row
+ nSumR += ( pTmp = pKoeff[ 6 ] )[ ( pColor = pRowTmp3 + nX )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ nSumR += ( pTmp = pKoeff[ 7 ] )[ ( ++pColor )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ nSumR += ( pTmp = pKoeff[ 8 ] )[ ( ++pColor )->GetRed() ];
+ nSumG += pTmp[ pColor->GetGreen() ];
+ nSumB += pTmp[ pColor->GetBlue() ];
+
+ // calculate destination color
+ pWriteAcc->SetPixel( nY, nX, BitmapColor( (BYTE) MinMax( nSumR / nDivisor, 0, 255 ),
+ (BYTE) MinMax( nSumG / nDivisor, 0, 255 ),
+ (BYTE) MinMax( nSumB / nDivisor, 0, 255 ) ) );
+ }
+
+ if( ++nY < nHeight )
+ {
+ if( pRowTmp1 == pColRow1 )
+ pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
+ else if( pRowTmp1 == pColRow2 )
+ pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
+ else
+ pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
+
+ for( i = 0; i < nWidth2; i++ )
+ pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
+ }
+ }
+
+ delete[] pKoeff;
+ delete[] (BYTE*) pColRow1;
+ delete[] (BYTE*) pColRow2;
+ delete[] (BYTE*) pColRow3;
+ delete[] pColm;
+ delete[] pRows;
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL Bitmap::ImplMedianFilter( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
+{
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), 24 );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
+ const long nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
+ long* pColm = new long[ nWidth2 ];
+ long* pRows = new long[ nHeight2 ];
+ BitmapColor* pColRow1 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ];
+ BitmapColor* pColRow2 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ];
+ BitmapColor* pColRow3 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ];
+ BitmapColor* pRowTmp1 = pColRow1;
+ BitmapColor* pRowTmp2 = pColRow2;
+ BitmapColor* pRowTmp3 = pColRow3;
+ BitmapColor* pColor;
+ long nY, nX, i;
+ long nR1, nR2, nR3, nR4, nR5, nR6, nR7, nR8, nR9;
+ long nG1, nG2, nG3, nG4, nG5, nG6, nG7, nG8, nG9;
+ long nB1, nB2, nB3, nB4, nB5, nB6, nB7, nB8, nB9;
+
+ // create column LUT
+ for( i = 0; i < nWidth2; i++ )
+ pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
+
+ pColm[ nWidth + 1 ] = pColm[ nWidth ];
+
+ // create row LUT
+ for( i = 0; i < nHeight2; i++ )
+ pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
+
+ pRows[ nHeight + 1 ] = pRows[ nHeight ];
+
+ // read first three rows of bitmap color
+ if (nHeight2 > 2)
+ {
+ for( i = 0; i < nWidth2; i++ )
+ {
+ pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
+ pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
+ pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
+ }
+ }
+
+ // do median filtering
+ for( nY = 0; nY < nHeight; )
+ {
+ for( nX = 0; nX < nWidth; nX++ )
+ {
+ nR1 = ( pColor = pRowTmp1 + nX )->GetRed(), nG1 = pColor->GetGreen(), nB1 = pColor->GetBlue();
+ nR2 = ( ++pColor )->GetRed(), nG2 = pColor->GetGreen(), nB2 = pColor->GetBlue();
+ nR3 = ( ++pColor )->GetRed(), nG3 = pColor->GetGreen(), nB3 = pColor->GetBlue();
+
+ nR4 = ( pColor = pRowTmp2 + nX )->GetRed(), nG4 = pColor->GetGreen(), nB4 = pColor->GetBlue();
+ nR5 = ( ++pColor )->GetRed(), nG5 = pColor->GetGreen(), nB5 = pColor->GetBlue();
+ nR6 = ( ++pColor )->GetRed(), nG6 = pColor->GetGreen(), nB6 = pColor->GetBlue();
+
+ nR7 = ( pColor = pRowTmp3 + nX )->GetRed(), nG7 = pColor->GetGreen(), nB7 = pColor->GetBlue();
+ nR8 = ( ++pColor )->GetRed(), nG8 = pColor->GetGreen(), nB8 = pColor->GetBlue();
+ nR9 = ( ++pColor )->GetRed(), nG9 = pColor->GetGreen(), nB9 = pColor->GetBlue();
+
+ MNMX6( nR1, nR2, nR3, nR4, nR5, nR6 );
+ MNMX5( nR7, nR2, nR3, nR4, nR5 );
+ MNMX4( nR8, nR2, nR3, nR4 );
+ MNMX3( nR9, nR2, nR3 );
+
+ MNMX6( nG1, nG2, nG3, nG4, nG5, nG6 );
+ MNMX5( nG7, nG2, nG3, nG4, nG5 );
+ MNMX4( nG8, nG2, nG3, nG4 );
+ MNMX3( nG9, nG2, nG3 );
+
+ MNMX6( nB1, nB2, nB3, nB4, nB5, nB6 );
+ MNMX5( nB7, nB2, nB3, nB4, nB5 );
+ MNMX4( nB8, nB2, nB3, nB4 );
+ MNMX3( nB9, nB2, nB3 );
+
+ // set destination color
+ pWriteAcc->SetPixel( nY, nX, BitmapColor( (BYTE) nR2, (BYTE) nG2, (BYTE) nB2 ) );
+ }
+
+ if( ++nY < nHeight )
+ {
+ if( pRowTmp1 == pColRow1 )
+ pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
+ else if( pRowTmp1 == pColRow2 )
+ pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
+ else
+ pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
+
+ for( i = 0; i < nWidth2; i++ )
+ pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
+ }
+ }
+
+ delete[] (BYTE*) pColRow1;
+ delete[] (BYTE*) pColRow2;
+ delete[] (BYTE*) pColRow3;
+ delete[] pColm;
+ delete[] pRows;
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL Bitmap::ImplSobelGrey( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
+{
+ BOOL bRet = ImplMakeGreyscales( 256 );
+
+ if( bRet )
+ {
+ bRet = FALSE;
+
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+
+ if( pReadAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ BitmapColor aGrey( (BYTE) 0 );
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+ const long nMask111 = -1, nMask121 = 0, nMask131 = 1;
+ const long nMask211 = -2, nMask221 = 0, nMask231 = 2;
+ const long nMask311 = -1, nMask321 = 0, nMask331 = 1;
+ const long nMask112 = 1, nMask122 = 2, nMask132 = 1;
+ const long nMask212 = 0, nMask222 = 0, nMask232 = 0;
+ const long nMask312 = -1, nMask322 = -2, nMask332 = -1;
+ long nGrey11, nGrey12, nGrey13;
+ long nGrey21, nGrey22, nGrey23;
+ long nGrey31, nGrey32, nGrey33;
+ long* pHMap = new long[ nWidth + 2 ];
+ long* pVMap = new long[ nHeight + 2 ];
+ long nX, nY, nSum1, nSum2;
+
+ // fill mapping tables
+ pHMap[ 0 ] = 0;
+ for( nX = 1; nX <= nWidth; nX++ )
+ pHMap[ nX ] = nX - 1;
+ pHMap[ nWidth + 1 ] = nWidth - 1;
+
+ pVMap[ 0 ] = 0;
+ for( nY = 1; nY <= nHeight; nY++ )
+ pVMap[ nY ] = nY - 1;
+ pVMap[ nHeight + 1 ] = nHeight - 1;
+
+ for( nY = 0; nY < nHeight ; nY++ )
+ {
+ nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
+ nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
+ nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
+ nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
+ nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
+ nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
+ nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
+ nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
+ nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
+
+ for( nX = 0; nX < nWidth; nX++ )
+ {
+ nSum1 = nSum2 = 0;
+
+ nSum1 += nMask111 * nGrey11;
+ nSum2 += nMask112 * nGrey11;
+
+ nSum1 += nMask121 * nGrey12;
+ nSum2 += nMask122 * nGrey12;
+
+ nSum1 += nMask131 * nGrey13;
+ nSum2 += nMask132 * nGrey13;
+
+ nSum1 += nMask211 * nGrey21;
+ nSum2 += nMask212 * nGrey21;
+
+ nSum1 += nMask221 * nGrey22;
+ nSum2 += nMask222 * nGrey22;
+
+ nSum1 += nMask231 * nGrey23;
+ nSum2 += nMask232 * nGrey23;
+
+ nSum1 += nMask311 * nGrey31;
+ nSum2 += nMask312 * nGrey31;
+
+ nSum1 += nMask321 * nGrey32;
+ nSum2 += nMask322 * nGrey32;
+
+ nSum1 += nMask331 * nGrey33;
+ nSum2 += nMask332 * nGrey33;
+
+ nSum1 = (long) sqrt( (double)( nSum1 * nSum1 + nSum2 * nSum2 ) );
+ aGrey.SetIndex( ~(BYTE) VOS_BOUND( nSum1, 0, 255 ) );
+ pWriteAcc->SetPixel( nY, nX, aGrey );
+
+ if( nX < ( nWidth - 1 ) )
+ {
+ const long nNextX = pHMap[ nX + 3 ];
+
+ nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
+ nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
+ nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
+ }
+ }
+ }
+
+ delete[] pHMap;
+ delete[] pVMap;
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL Bitmap::ImplEmbossGrey( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
+{
+ BOOL bRet = ImplMakeGreyscales( 256 );
+
+ if( bRet )
+ {
+ bRet = FALSE;
+
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+
+ if( pReadAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ BitmapColor aGrey( (BYTE) 0 );
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+ long nGrey11, nGrey12, nGrey13;
+ long nGrey21, nGrey22, nGrey23;
+ long nGrey31, nGrey32, nGrey33;
+ double fAzim = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
+ ( pFilterParam->maEmbossAngles.mnAzimuthAngle100 * 0.01 ) : 0.0 ) * F_PI180;
+ double fElev = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
+ ( pFilterParam->maEmbossAngles.mnElevationAngle100 * 0.01 ) : 90.0 ) * F_PI180;
+ long* pHMap = new long[ nWidth + 2 ];
+ long* pVMap = new long[ nHeight + 2 ];
+ long nX, nY, nNx, nNy, nDotL;
+ const long nLx = FRound( cos( fAzim ) * cos( fElev ) * 255.0 );
+ const long nLy = FRound( sin( fAzim ) * cos( fElev ) * 255.0 );
+ const long nLz = FRound( sin( fElev ) * 255.0 );
+ const long nZ2 = ( ( 6 * 255 ) / 4 ) * ( ( 6 * 255 ) / 4 );
+ const long nNzLz = ( ( 6 * 255 ) / 4 ) * nLz;
+ const BYTE cLz = (BYTE) VOS_BOUND( nLz, 0, 255 );
+
+ // fill mapping tables
+ pHMap[ 0 ] = 0;
+ for( nX = 1; nX <= nWidth; nX++ )
+ pHMap[ nX ] = nX - 1;
+ pHMap[ nWidth + 1 ] = nWidth - 1;
+
+ pVMap[ 0 ] = 0;
+ for( nY = 1; nY <= nHeight; nY++ )
+ pVMap[ nY ] = nY - 1;
+ pVMap[ nHeight + 1 ] = nHeight - 1;
+
+ for( nY = 0; nY < nHeight ; nY++ )
+ {
+ nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
+ nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
+ nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
+ nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
+ nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
+ nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
+ nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
+ nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
+ nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
+
+ for( nX = 0; nX < nWidth; nX++ )
+ {
+ nNx = nGrey11 + nGrey21 + nGrey31 - nGrey13 - nGrey23 - nGrey33;
+ nNy = nGrey31 + nGrey32 + nGrey33 - nGrey11 - nGrey12 - nGrey13;
+
+ if( !nNx && !nNy )
+ aGrey.SetIndex( cLz );
+ else if( ( nDotL = nNx * nLx + nNy * nLy +nNzLz ) < 0 )
+ aGrey.SetIndex( 0 );
+ else
+ {
+ const double fGrey = nDotL / sqrt( (double)(nNx * nNx + nNy * nNy + nZ2) );
+ aGrey.SetIndex( (BYTE) VOS_BOUND( fGrey, 0, 255 ) );
+ }
+
+ pWriteAcc->SetPixel( nY, nX, aGrey );
+
+ if( nX < ( nWidth - 1 ) )
+ {
+ const long nNextX = pHMap[ nX + 3 ];
+
+ nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
+ nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
+ nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
+ }
+ }
+ }
+
+ delete[] pHMap;
+ delete[] pVMap;
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL Bitmap::ImplSolarize( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
+{
+ BOOL bRet = FALSE;
+ BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const BYTE cThreshold = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SOLARIZE ) ?
+ pFilterParam->mcSolarGreyThreshold : 128;
+
+ if( pWriteAcc->HasPalette() )
+ {
+ const BitmapPalette& rPal = pWriteAcc->GetPalette();
+
+ for( USHORT i = 0, nCount = rPal.GetEntryCount(); i < nCount; i++ )
+ {
+ if( rPal[ i ].GetLuminance() >= cThreshold )
+ {
+ BitmapColor aCol( rPal[ i ] );
+ pWriteAcc->SetPaletteColor( i, aCol.Invert() );
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol;
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+
+ for( long nY = 0; nY < nHeight ; nY++ )
+ {
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ aCol = pWriteAcc->GetPixel( nY, nX );
+
+ if( aCol.GetLuminance() >= cThreshold )
+ pWriteAcc->SetPixel( nY, nX, aCol.Invert() );
+ }
+ }
+ }
+
+ ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL Bitmap::ImplSepia( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
+{
+ BitmapReadAccess* pReadAcc = AcquireReadAccess();
+ BOOL bRet = FALSE;
+
+ if( pReadAcc )
+ {
+ long nSepiaPercent = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SEPIA ) ?
+ pFilterParam->mcSolarGreyThreshold : 10;
+ const long nSepia = 10000 - 100 * VOS_BOUND( nSepiaPercent, 0, 100 );
+ BitmapPalette aSepiaPal( 256 );
+
+ DBG_ASSERT( nSepiaPercent <= 100, "Bitmap::ImplSepia(): sepia value out of range; defaulting to 100%" );
+
+ for( USHORT i = 0; i < 256; i++ )
+ {
+ BitmapColor& rCol = aSepiaPal[ i ];
+ const BYTE cSepiaValue = (BYTE) ( ( nSepia * i ) / 10000 );
+
+ rCol.SetRed( (BYTE) i );
+ rCol.SetGreen( cSepiaValue );
+ rCol.SetBlue( cSepiaValue );
+ }
+
+ Bitmap aNewBmp( GetSizePixel(), 8, &aSepiaPal );
+ BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ BitmapColor aCol( (BYTE) 0 );
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+
+ if( pReadAcc->HasPalette() )
+ {
+ for( long nY = 0; nY < nHeight ; nY++ )
+ {
+ const USHORT nPalCount = pReadAcc->GetPaletteEntryCount();
+ BYTE* pIndexMap = new BYTE[ nPalCount ];
+
+ for( USHORT i = 0; i < nPalCount; i++ )
+ pIndexMap[ i ] = pReadAcc->GetPaletteColor( i ).GetLuminance();
+
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ aCol.SetIndex( pIndexMap[ pReadAcc->GetPixel( nY, nX ).GetIndex() ] );
+ pWriteAcc->SetPixel( nY, nX, aCol );
+ }
+
+ delete[] pIndexMap;
+ }
+ }
+ else
+ {
+ for( long nY = 0; nY < nHeight ; nY++ )
+ {
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ aCol.SetIndex( pReadAcc->GetPixel( nY, nX ).GetLuminance() );
+ pWriteAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+ }
+
+ aNewBmp.ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL Bitmap::ImplMosaic( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
+{
+ ULONG nTileWidth = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
+ pFilterParam->maMosaicTileSize.mnTileWidth : 4;
+ ULONG nTileHeight = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
+ pFilterParam->maMosaicTileSize.mnTileHeight : 4;
+ BOOL bRet = FALSE;
+
+ if( !nTileWidth )
+ nTileWidth = 1;
+
+ if( !nTileHeight )
+ nTileHeight = 1;
+
+ if( nTileWidth > 1 || nTileHeight > 1 )
+ {
+ Bitmap* pNewBmp;
+ BitmapReadAccess* pReadAcc;
+ BitmapWriteAccess* pWriteAcc;
+
+ if( GetBitCount() > 8 )
+ {
+ pNewBmp = NULL;
+ pReadAcc = pWriteAcc = AcquireWriteAccess();
+ }
+ else
+ {
+ pNewBmp = new Bitmap( GetSizePixel(), 24 );
+ pReadAcc = AcquireReadAccess();
+ pWriteAcc = pNewBmp->AcquireWriteAccess();
+ }
+
+ if( pReadAcc && pWriteAcc )
+ {
+ BitmapColor aCol;
+ long nWidth = pReadAcc->Width();
+ long nHeight = pReadAcc->Height();
+ long nX, nY, nX1, nX2, nY1, nY2, nSumR, nSumG, nSumB;
+ double fArea_1;
+
+ nY1 = 0; nY2 = nTileHeight - 1;
+
+ if( nY2 >= nHeight )
+ nY2 = nHeight - 1;
+
+ do
+ {
+ nX1 = 0; nX2 = nTileWidth - 1;
+
+ if( nX2 >= nWidth )
+ nX2 = nWidth - 1;
+
+ fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
+
+ if( !pNewBmp )
+ {
+ do
+ {
+ for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
+ {
+ for( nX = nX1; nX <= nX2; nX++ )
+ {
+ aCol = pReadAcc->GetPixel( nY, nX );
+ nSumR += aCol.GetRed();
+ nSumG += aCol.GetGreen();
+ nSumB += aCol.GetBlue();
+ }
+ }
+
+ aCol.SetRed( (BYTE) ( nSumR * fArea_1 ) );
+ aCol.SetGreen( (BYTE) ( nSumG * fArea_1 ) );
+ aCol.SetBlue( (BYTE) ( nSumB * fArea_1 ) );
+
+ for( nY = nY1; nY <= nY2; nY++ )
+ for( nX = nX1; nX <= nX2; nX++ )
+ pWriteAcc->SetPixel( nY, nX, aCol );
+
+ nX1 += nTileWidth; nX2 += nTileWidth;
+
+ if( nX2 >= nWidth )
+ {
+ nX2 = nWidth - 1;
+ fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
+ }
+ }
+ while( nX1 < nWidth );
+ }
+ else
+ {
+ do
+ {
+ for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
+ {
+ for( nX = nX1; nX <= nX2; nX++ )
+ {
+ const BitmapColor& rCol = pReadAcc->GetPaletteColor( (BYTE) pReadAcc->GetPixel( nY, nX ) );
+ nSumR += rCol.GetRed();
+ nSumG += rCol.GetGreen();
+ nSumB += rCol.GetBlue();
+ }
+ }
+
+ aCol.SetRed( (BYTE) ( nSumR * fArea_1 ) );
+ aCol.SetGreen( (BYTE) ( nSumG * fArea_1 ) );
+ aCol.SetBlue( (BYTE) ( nSumB * fArea_1 ) );
+
+ for( nY = nY1; nY <= nY2; nY++ )
+ for( nX = nX1; nX <= nX2; nX++ )
+ pWriteAcc->SetPixel( nY, nX, aCol );
+
+ nX1 += nTileWidth; nX2 += nTileWidth;
+
+ if( nX2 >= nWidth )
+ {
+ nX2 = nWidth - 1;
+ fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
+ }
+ }
+ while( nX1 < nWidth );
+ }
+
+ nY1 += nTileHeight; nY2 += nTileHeight;
+
+ if( nY2 >= nHeight )
+ nY2 = nHeight - 1;
+ }
+ while( nY1 < nHeight );
+
+ bRet = TRUE;
+ }
+
+ ReleaseAccess( pReadAcc );
+
+ if( pNewBmp )
+ {
+ pNewBmp->ReleaseAccess( pWriteAcc );
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = *pNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+
+ delete pNewBmp;
+ }
+ }
+ else
+ bRet = TRUE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+struct PopArtEntry
+{
+ sal_uInt32 mnIndex;
+ sal_uInt32 mnCount;
+};
+
+// ------------------------------------------------------------------------
+
+extern "C" int __LOADONCALLAPI ImplPopArtCmpFnc( const void* p1, const void* p2 )
+{
+ int nRet;
+
+ if( ( (PopArtEntry*) p1 )->mnCount < ( (PopArtEntry*) p2 )->mnCount )
+ nRet = 1;
+ else if( ( (PopArtEntry*) p1 )->mnCount == ( (PopArtEntry*) p2 )->mnCount )
+ nRet = 0;
+ else
+ nRet = -1;
+
+ return nRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Bitmap::ImplPopArt( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
+{
+ BOOL bRet = ( GetBitCount() > 8 ) ? Convert( BMP_CONVERSION_8BIT_COLORS ) : TRUE;
+
+ if( bRet )
+ {
+ bRet = FALSE;
+
+ BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
+
+ if( pWriteAcc )
+ {
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+ const ULONG nEntryCount = 1 << pWriteAcc->GetBitCount();
+ ULONG n;
+ PopArtEntry* pPopArtTable = new PopArtEntry[ nEntryCount ];
+
+ for( n = 0; n < nEntryCount; n++ )
+ {
+ PopArtEntry& rEntry = pPopArtTable[ n ];
+ rEntry.mnIndex = (sal_uInt16) n;
+ rEntry.mnCount = 0;
+ }
+
+ // get pixel count for each palette entry
+ for( long nY = 0; nY < nHeight ; nY++ )
+ for( long nX = 0; nX < nWidth; nX++ )
+ pPopArtTable[ pWriteAcc->GetPixel( nY, nX ).GetIndex() ].mnCount++;
+
+ // sort table
+ qsort( pPopArtTable, nEntryCount, sizeof( PopArtEntry ), ImplPopArtCmpFnc );
+
+ // get last used entry
+ ULONG nFirstEntry;
+ ULONG nLastEntry = 0;
+
+ for( n = 0; n < nEntryCount; n++ )
+ if( pPopArtTable[ n ].mnCount )
+ nLastEntry = n;
+
+ // rotate palette (one entry)
+ const BitmapColor aFirstCol( pWriteAcc->GetPaletteColor( sal::static_int_cast<USHORT>(pPopArtTable[ 0 ].mnIndex) ) );
+ for( nFirstEntry = 0; nFirstEntry < nLastEntry; nFirstEntry++ )
+ {
+ pWriteAcc->SetPaletteColor( sal::static_int_cast<USHORT>(pPopArtTable[ nFirstEntry ].mnIndex),
+ pWriteAcc->GetPaletteColor( sal::static_int_cast<USHORT>(pPopArtTable[ nFirstEntry + 1 ].mnIndex) ) );
+ }
+ pWriteAcc->SetPaletteColor( sal::static_int_cast<USHORT>(pPopArtTable[ nLastEntry ].mnIndex), aFirstCol );
+
+ // cleanup
+ delete[] pPopArtTable;
+ ReleaseAccess( pWriteAcc );
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx
new file mode 100644
index 000000000000..38402af626c2
--- /dev/null
+++ b/vcl/source/gdi/bitmapex.cxx
@@ -0,0 +1,914 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <ctype.h>
+#include <rtl/crc.h>
+#include <vcl/salbtype.hxx>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/alpha.hxx>
+#include <vcl/image.h>
+#include <vcl/bitmapex.hxx>
+#include <vcl/pngread.hxx>
+#ifndef _SV_IMPIMAGETREE_H
+#include <vcl/impimagetree.hxx>
+#endif
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svapp.hxx>
+#include <vcl/bmpacc.hxx>
+
+// ------------
+// - BitmapEx -
+// ------------
+
+BitmapEx::BitmapEx() :
+ eTransparent( TRANSPARENT_NONE ),
+ bAlpha ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx::BitmapEx( const BitmapEx& rBitmapEx ) :
+ aBitmap ( rBitmapEx.aBitmap ),
+ aMask ( rBitmapEx.aMask ),
+ aBitmapSize ( rBitmapEx.aBitmapSize ),
+ aTransparentColor ( rBitmapEx.aTransparentColor ),
+ eTransparent ( rBitmapEx.eTransparent ),
+ bAlpha ( rBitmapEx.bAlpha )
+{
+}
+
+BitmapEx::BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize ) :
+ eTransparent( TRANSPARENT_NONE ),
+ bAlpha ( FALSE )
+{
+ if( rBitmapEx.IsEmpty() )
+ return;
+
+ aBitmap = Bitmap( aSize, rBitmapEx.aBitmap.GetBitCount() );
+ aBitmapSize = aSize;
+ if( rBitmapEx.IsAlpha() )
+ {
+ bAlpha = TRUE;
+ aMask = AlphaMask( aSize ).ImplGetBitmap();
+ }
+ else if( rBitmapEx.IsTransparent() )
+ aMask = Bitmap( aSize, rBitmapEx.aMask.GetBitCount() );
+
+ Rectangle aDestRect( Point( 0, 0 ), aSize );
+ Rectangle aSrcRect( aSrc, aSize );
+ CopyPixel( aDestRect, aSrcRect, &rBitmapEx );
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx::BitmapEx( const ResId& rResId ) :
+ eTransparent( TRANSPARENT_NONE ),
+ bAlpha ( FALSE )
+{
+ static ImplImageTreeSingletonRef aImageTree;
+ ResMgr* pResMgr = NULL;
+
+ ResMgr::GetResourceSkipHeader( rResId.SetRT( RSC_BITMAP ), &pResMgr );
+ pResMgr->ReadLong();
+ pResMgr->ReadLong();
+
+ const String aFileName( pResMgr->ReadString() );
+ ::rtl::OUString aCurrentSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
+
+ if( !aImageTree->loadImage( aFileName, aCurrentSymbolsStyle, *this ) )
+ {
+#ifdef DBG_UTIL
+ ByteString aErrorStr( "BitmapEx::BitmapEx( const ResId& rResId ): could not load image <" );
+ DBG_ERROR( ( ( aErrorStr += ByteString( aFileName, RTL_TEXTENCODING_ASCII_US ) ) += '>' ).GetBuffer() );
+#endif
+ }
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx::BitmapEx( const Bitmap& rBmp ) :
+ aBitmap ( rBmp ),
+ aBitmapSize ( aBitmap.GetSizePixel() ),
+ eTransparent( TRANSPARENT_NONE ),
+ bAlpha ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) :
+ aBitmap ( rBmp ),
+ aMask ( rMask ),
+ aBitmapSize ( aBitmap.GetSizePixel() ),
+ eTransparent ( !rMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
+ bAlpha ( FALSE )
+{
+ DBG_ASSERT( !rMask || rBmp.GetSizePixel() == rMask.GetSizePixel(),
+ "BitmapEx::BitmapEx(): size mismatch for bitmap and mask." );
+
+ // #105489# Ensure a mask is exactly one bit deep
+ if( !!aMask && aMask.GetBitCount() != 1 )
+ {
+ OSL_TRACE("BitmapEx: forced mask to monochrome");
+ aMask.ImplMakeMono( 255 );
+ }
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) :
+ aBitmap ( rBmp ),
+ aMask ( rAlphaMask.ImplGetBitmap() ),
+ aBitmapSize ( aBitmap.GetSizePixel() ),
+ eTransparent ( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
+ bAlpha ( !rAlphaMask ? FALSE : TRUE )
+{
+ DBG_ASSERT( !rAlphaMask || rBmp.GetSizePixel() == rAlphaMask.GetSizePixel(),
+ "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
+
+ // #i75531# the workaround below can go when
+ // X11SalGraphics::drawAlphaBitmap()'s render acceleration
+ // can handle the bitmap depth mismatch directly
+ if( aBitmap.GetBitCount() < aMask.GetBitCount() )
+ aBitmap.Convert( BMP_CONVERSION_24BIT );
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) :
+ aBitmap ( rBmp ),
+ aBitmapSize ( aBitmap.GetSizePixel() ),
+ aTransparentColor ( rTransparentColor ),
+ eTransparent ( TRANSPARENT_BITMAP ),
+ bAlpha ( FALSE )
+{
+ aMask = aBitmap.CreateMask( aTransparentColor );
+
+ DBG_ASSERT( rBmp.GetSizePixel() == aMask.GetSizePixel(),
+ "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx::~BitmapEx()
+{
+}
+
+// ------------------------------------------------------------------
+
+// ------------------------------------------------------------------
+
+BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx )
+{
+ if( &rBitmapEx != this )
+ {
+ aBitmap = rBitmapEx.aBitmap;
+ aMask = rBitmapEx.aMask;
+ aBitmapSize = rBitmapEx.aBitmapSize;
+ aTransparentColor = rBitmapEx.aTransparentColor;
+ eTransparent = rBitmapEx.eTransparent;
+ bAlpha = rBitmapEx.bAlpha;
+ }
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::operator==( const BitmapEx& rBitmapEx ) const
+{
+ if( eTransparent != rBitmapEx.eTransparent )
+ return FALSE;
+
+ if( aBitmap != rBitmapEx.aBitmap )
+ return FALSE;
+
+ if( aBitmapSize != rBitmapEx.aBitmapSize )
+ return FALSE;
+
+ if( eTransparent == TRANSPARENT_NONE )
+ return TRUE;
+
+ if( eTransparent == TRANSPARENT_COLOR )
+ return aTransparentColor == rBitmapEx.aTransparentColor;
+
+ return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const
+{
+ return( rBmpEx.eTransparent == eTransparent &&
+ rBmpEx.bAlpha == bAlpha &&
+ rBmpEx.aBitmap.IsEqual( aBitmap ) &&
+ rBmpEx.aMask.IsEqual( aMask ) );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::IsEmpty() const
+{
+ return( aBitmap.IsEmpty() && aMask.IsEmpty() );
+}
+
+// ------------------------------------------------------------------
+
+void BitmapEx::SetEmpty()
+{
+ aBitmap.SetEmpty();
+ aMask.SetEmpty();
+ eTransparent = TRANSPARENT_NONE;
+ bAlpha = FALSE;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapEx::Clear()
+{
+ SetEmpty();
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::IsTransparent() const
+{
+ return( eTransparent != TRANSPARENT_NONE );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::IsAlpha() const
+{
+ return( IsTransparent() && bAlpha );
+}
+
+// ------------------------------------------------------------------
+
+Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const
+{
+ Bitmap aRetBmp( aBitmap );
+
+ if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) )
+ {
+ Bitmap aTempMask;
+
+ if( eTransparent == TRANSPARENT_COLOR )
+ aTempMask = aBitmap.CreateMask( aTransparentColor );
+ else
+ aTempMask = aMask;
+
+ if( !IsAlpha() )
+ aRetBmp.Replace( aTempMask, *pTransReplaceColor );
+ else
+ aRetBmp.Replace( GetAlpha(), *pTransReplaceColor );
+ }
+
+ return aRetBmp;
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx BitmapEx::GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const
+{
+ BitmapEx aRet;
+
+ if( BMP_COLOR_HIGHCONTRAST == eColorMode )
+ {
+ aRet = *this;
+ aRet.aBitmap = aBitmap.GetColorTransformedBitmap( eColorMode );
+ }
+ else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
+ BMP_COLOR_MONOCHROME_WHITE == eColorMode )
+ {
+ aRet = *this;
+ aRet.aBitmap = aRet.aBitmap.GetColorTransformedBitmap( eColorMode );
+
+ if( !aRet.aMask.IsEmpty() )
+ {
+ aRet.aMask.CombineSimple( aRet.aBitmap, BMP_COMBINE_OR );
+ aRet.aBitmap.Erase( ( BMP_COLOR_MONOCHROME_BLACK == eColorMode ) ? COL_BLACK : COL_WHITE );
+
+ DBG_ASSERT( aRet.aBitmap.GetSizePixel() == aRet.aMask.GetSizePixel(),
+ "BitmapEx::GetColorTransformedBitmapEx(): size mismatch for bitmap and alpha mask." );
+ }
+ }
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------
+
+Bitmap BitmapEx::GetMask() const
+{
+ Bitmap aRet( aMask );
+
+ if( IsAlpha() )
+ aRet.ImplMakeMono( 255 );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------
+
+AlphaMask BitmapEx::GetAlpha() const
+{
+ AlphaMask aAlpha;
+
+ if( IsAlpha() )
+ aAlpha.ImplSetBitmap( aMask );
+ else
+ aAlpha = aMask;
+
+ return aAlpha;
+}
+
+// ------------------------------------------------------------------
+
+ULONG BitmapEx::GetSizeBytes() const
+{
+ ULONG nSizeBytes = aBitmap.GetSizeBytes();
+
+ if( eTransparent == TRANSPARENT_BITMAP )
+ nSizeBytes += aMask.GetSizeBytes();
+
+ return nSizeBytes;
+}
+
+// ------------------------------------------------------------------
+
+ULONG BitmapEx::GetChecksum() const
+{
+ sal_uInt32 nCrc = aBitmap.GetChecksum();
+ SVBT32 aBT32;
+
+ UInt32ToSVBT32( (long) eTransparent, aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( (long) bAlpha, aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() )
+ {
+ UInt32ToSVBT32( aMask.GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+
+ return nCrc;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapEx::SetSizePixel( const Size& rNewSize )
+{
+ Scale( rNewSize );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Invert()
+{
+ BOOL bRet = FALSE;
+
+ if( !!aBitmap )
+ {
+ bRet = aBitmap.Invert();
+
+ if( bRet && ( eTransparent == TRANSPARENT_COLOR ) )
+ aTransparentColor = BitmapColor( aTransparentColor ).Invert();
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Mirror( ULONG nMirrorFlags )
+{
+ BOOL bRet = FALSE;
+
+ if( !!aBitmap )
+ {
+ bRet = aBitmap.Mirror( nMirrorFlags );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ aMask.Mirror( nMirrorFlags );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag )
+{
+ BOOL bRet = FALSE;
+
+ if( !!aBitmap )
+ {
+ bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ aMask.Scale( rScaleX, rScaleY, BMP_SCALE_FAST );
+
+ aBitmapSize = aBitmap.GetSizePixel();
+
+ DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
+ "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL BitmapEx::Scale( const Size& rNewSize, ULONG nScaleFlag )
+{
+ BOOL bRet;
+
+ if( aBitmapSize.Width() && aBitmapSize.Height() )
+ {
+ bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(),
+ (double) rNewSize.Height() / aBitmapSize.Height(),
+ nScaleFlag );
+ }
+ else
+ bRet = TRUE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
+{
+ BOOL bRet = FALSE;
+
+ if( !!aBitmap )
+ {
+ const BOOL bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
+
+ if( bTransRotate )
+ {
+ if( eTransparent == TRANSPARENT_COLOR )
+ bRet = aBitmap.Rotate( nAngle10, aTransparentColor );
+ else
+ {
+ bRet = aBitmap.Rotate( nAngle10, COL_BLACK );
+
+ if( eTransparent == TRANSPARENT_NONE )
+ {
+ aMask = Bitmap( aBitmapSize, 1 );
+ aMask.Erase( COL_BLACK );
+ eTransparent = TRANSPARENT_BITMAP;
+ }
+
+ if( bRet && !!aMask )
+ aMask.Rotate( nAngle10, COL_WHITE );
+ }
+ }
+ else
+ {
+ bRet = aBitmap.Rotate( nAngle10, rFillColor );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ aMask.Rotate( nAngle10, COL_WHITE );
+ }
+
+ aBitmapSize = aBitmap.GetSizePixel();
+
+ DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
+ "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Crop( const Rectangle& rRectPixel )
+{
+ BOOL bRet = FALSE;
+
+ if( !!aBitmap )
+ {
+ bRet = aBitmap.Crop( rRectPixel );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ aMask.Crop( rRectPixel );
+
+ aBitmapSize = aBitmap.GetSizePixel();
+
+ DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
+ "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Convert( BmpConversion eConversion )
+{
+ return( !!aBitmap ? aBitmap.Convert( eConversion ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::ReduceColors( USHORT nNewColorCount, BmpReduce eReduce )
+{
+ return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Expand( ULONG nDX, ULONG nDY, const Color* pInitColor, BOOL bExpandTransparent )
+{
+ BOOL bRet = FALSE;
+
+ if( !!aBitmap )
+ {
+ bRet = aBitmap.Expand( nDX, nDY, pInitColor );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ {
+ Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
+ aMask.Expand( nDX, nDY, &aColor );
+ }
+
+ aBitmapSize = aBitmap.GetSizePixel();
+
+ DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
+ "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
+ const BitmapEx* pBmpExSrc )
+{
+ BOOL bRet = FALSE;
+
+ if( !pBmpExSrc || pBmpExSrc->IsEmpty() )
+ {
+ if( !aBitmap.IsEmpty() )
+ {
+ bRet = aBitmap.CopyPixel( rRectDst, rRectSrc );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ aMask.CopyPixel( rRectDst, rRectSrc );
+ }
+ }
+ else
+ {
+ if( !aBitmap.IsEmpty() )
+ {
+ bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap );
+
+ if( bRet )
+ {
+ if( pBmpExSrc->IsAlpha() )
+ {
+ if( IsAlpha() )
+ // cast to use the optimized AlphaMask::CopyPixel
+ ((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask );
+ else if( IsTransparent() )
+ {
+ AlphaMask* pAlpha = new AlphaMask( aMask );
+
+ aMask = pAlpha->ImplGetBitmap();
+ delete pAlpha;
+ bAlpha = TRUE;
+ aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
+ }
+ else
+ {
+ sal_uInt8 cBlack = 0;
+ AlphaMask* pAlpha = new AlphaMask( GetSizePixel(), &cBlack );
+
+ aMask = pAlpha->ImplGetBitmap();
+ delete pAlpha;
+ eTransparent = TRANSPARENT_BITMAP;
+ bAlpha = TRUE;
+ aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
+ }
+ }
+ else if( pBmpExSrc->IsTransparent() )
+ {
+ if( IsAlpha() )
+ {
+ AlphaMask aAlpha( pBmpExSrc->aMask );
+ aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() );
+ }
+ else if( IsTransparent() )
+ aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
+ else
+ {
+ aMask = Bitmap( GetSizePixel(), 1 );
+ aMask.Erase( Color( COL_BLACK ) );
+ eTransparent = TRANSPARENT_BITMAP;
+ aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
+ }
+ }
+ else if( IsAlpha() )
+ {
+ sal_uInt8 cBlack = 0;
+ const AlphaMask aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack );
+
+ aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
+ }
+ else if( IsTransparent() )
+ {
+ Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 );
+
+ aMaskSrc.Erase( Color( COL_BLACK ) );
+ aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc );
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Erase( const Color& rFillColor )
+{
+ BOOL bRet = FALSE;
+
+ if( !!aBitmap )
+ {
+ bRet = aBitmap.Erase( rFillColor );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ {
+ // #104416# Respect transparency on fill color
+ if( rFillColor.GetTransparency() )
+ {
+ const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() );
+ aMask.Erase( aFill );
+ }
+ else
+ {
+ const Color aBlack( COL_BLACK );
+ aMask.Erase( aBlack );
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Dither( ULONG nDitherFlags )
+{
+ return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol )
+{
+ return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, ULONG nColorCount, const ULONG* pTols )
+{
+ return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (ULONG*) pTols ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent,
+ short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
+ double fGamma, BOOL bInvert )
+{
+ return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent,
+ nChannelRPercent, nChannelGPercent, nChannelBPercent,
+ fGamma, bInvert ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
+{
+ return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
+{
+ pOutDev->DrawBitmapEx( rDestPt, *this );
+}
+
+// ------------------------------------------------------------------
+
+void BitmapEx::Draw( OutputDevice* pOutDev,
+ const Point& rDestPt, const Size& rDestSize ) const
+{
+ pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this );
+}
+
+// ------------------------------------------------------------------
+
+void BitmapEx::Draw( OutputDevice* pOutDev,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const
+{
+ pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this );
+}
+
+// ------------------------------------------------------------------
+
+sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
+{
+ sal_uInt8 nTransparency(0xff);
+
+ if(!aBitmap.IsEmpty())
+ {
+ if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height())
+ {
+ switch(eTransparent)
+ {
+ case TRANSPARENT_NONE:
+ {
+ // not transparent, ergo all covered
+ nTransparency = 0x00;
+ break;
+ }
+ case TRANSPARENT_COLOR:
+ {
+ Bitmap aTestBitmap(aBitmap);
+ BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
+
+ if(pRead)
+ {
+ const Color aColor = pRead->GetColor(nY, nX);
+
+ // if color is not equal to TransparentColor, we are not transparent
+ if(aColor != aTransparentColor)
+ {
+ nTransparency = 0x00;
+ }
+
+ aTestBitmap.ReleaseAccess(pRead);
+ }
+ break;
+ }
+ case TRANSPARENT_BITMAP:
+ {
+ if(!aMask.IsEmpty())
+ {
+ Bitmap aTestBitmap(aMask);
+ BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
+
+ if(pRead)
+ {
+ const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
+
+ if(bAlpha)
+ {
+ nTransparency = aBitmapColor.GetIndex();
+ }
+ else
+ {
+ if(0x00 == aBitmapColor.GetIndex())
+ {
+ nTransparency = 0x00;
+ }
+ }
+
+ aTestBitmap.ReleaseAccess(pRead);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return nTransparency;
+}
+
+// ------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx )
+{
+ rBitmapEx.aBitmap.Write( rOStm );
+
+ rOStm << (UINT32) 0x25091962;
+ rOStm << (UINT32) 0xACB20201;
+ rOStm << (BYTE) rBitmapEx.eTransparent;
+
+ if( rBitmapEx.eTransparent == TRANSPARENT_BITMAP )
+ rBitmapEx.aMask.Write( rOStm );
+ else if( rBitmapEx.eTransparent == TRANSPARENT_COLOR )
+ rOStm << rBitmapEx.aTransparentColor;
+
+ return rOStm;
+}
+
+// ------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx )
+{
+ Bitmap aBmp;
+
+ rIStm >> aBmp;
+
+ if( !rIStm.GetError() )
+ {
+ const ULONG nStmPos = rIStm.Tell();
+ UINT32 nMagic1 = 0;
+ UINT32 nMagic2 = 0;
+
+ rIStm >> nMagic1 >> nMagic2;
+
+ if( ( nMagic1 != 0x25091962 ) || ( nMagic2 != 0xACB20201 ) || rIStm.GetError() )
+ {
+ rIStm.ResetError();
+ rIStm.Seek( nStmPos );
+ rBitmapEx = aBmp;
+ }
+ else
+ {
+ BYTE bTransparent = false;
+
+ rIStm >> bTransparent;
+
+ if( bTransparent == (BYTE) TRANSPARENT_BITMAP )
+ {
+ Bitmap aMask;
+
+ rIStm >> aMask;
+
+ if( !!aMask)
+ {
+ // do we have an alpha mask?
+ if( ( 8 == aMask.GetBitCount() ) && aMask.HasGreyPalette() )
+ {
+ AlphaMask aAlpha;
+
+ // create alpha mask quickly (without greyscale conversion)
+ aAlpha.ImplSetBitmap( aMask );
+ rBitmapEx = BitmapEx( aBmp, aAlpha );
+ }
+ else
+ rBitmapEx = BitmapEx( aBmp, aMask );
+ }
+ else
+ rBitmapEx = aBmp;
+ }
+ else if( bTransparent == (BYTE) TRANSPARENT_COLOR )
+ {
+ Color aTransparentColor;
+
+ rIStm >> aTransparentColor;
+ rBitmapEx = BitmapEx( aBmp, aTransparentColor );
+ }
+ else
+ rBitmapEx = aBmp;
+ }
+ }
+
+ return rIStm;
+}
diff --git a/vcl/source/gdi/bmpacc.cxx b/vcl/source/gdi/bmpacc.cxx
new file mode 100644
index 000000000000..c963ea32542e
--- /dev/null
+++ b/vcl/source/gdi/bmpacc.cxx
@@ -0,0 +1,447 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/salbtype.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bmpacc.hxx>
+#include <string.h>
+
+// --------------------
+// - BitmapReadAccess -
+// --------------------
+
+BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, BOOL bModify ) :
+ mpBuffer ( NULL ),
+ mpScanBuf ( NULL ),
+ mFncGetPixel ( NULL ),
+ mFncSetPixel ( NULL ),
+ mbModify ( bModify )
+{
+ ImplCreate( rBitmap );
+}
+
+// ------------------------------------------------------------------
+
+BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) :
+ mpBuffer ( NULL ),
+ mpScanBuf ( NULL ),
+ mFncGetPixel ( NULL ),
+ mFncSetPixel ( NULL ),
+ mbModify ( FALSE )
+{
+ ImplCreate( rBitmap );
+}
+
+// ------------------------------------------------------------------
+
+BitmapReadAccess::~BitmapReadAccess()
+{
+ ImplDestroy();
+}
+
+// ------------------------------------------------------------------
+
+void BitmapReadAccess::ImplCreate( Bitmap& rBitmap )
+{
+ ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
+
+ DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" );
+
+ if( pImpBmp )
+ {
+ if( mbModify && !maBitmap.ImplGetImpBitmap() )
+ {
+ rBitmap.ImplMakeUnique();
+ pImpBmp = rBitmap.ImplGetImpBitmap();
+ }
+ else
+ {
+ DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2,
+ "Unpredictable results: bitmap is referenced more than once!" );
+ }
+
+ mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
+
+ if( !mpBuffer )
+ {
+ ImpBitmap* pNewImpBmp = new ImpBitmap;
+
+ if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount() ) )
+ {
+ pImpBmp = pNewImpBmp;
+ rBitmap.ImplSetImpBitmap( pImpBmp );
+ mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
+ }
+ else
+ delete pNewImpBmp;
+ }
+
+ if( mpBuffer )
+ {
+ const long nHeight = mpBuffer->mnHeight;
+ Scanline pTmpLine = mpBuffer->mpBits;
+
+ mpScanBuf = new Scanline[ nHeight ];
+ maColorMask = mpBuffer->maColorMask;
+
+ if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ {
+ for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize )
+ mpScanBuf[ nY ] = pTmpLine;
+ }
+ else
+ {
+ for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize )
+ mpScanBuf[ nY ] = pTmpLine;
+ }
+
+ if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) )
+ {
+ delete[] mpScanBuf;
+ mpScanBuf = NULL;
+
+ pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
+ mpBuffer = NULL;
+ }
+ else
+ maBitmap = rBitmap;
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapReadAccess::ImplDestroy()
+{
+ ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
+
+ delete[] mpScanBuf;
+ mpScanBuf = NULL;
+
+ if( mpBuffer && pImpBmp )
+ {
+ pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
+ mpBuffer = NULL;
+ }
+}
+
+// ------------------------------------------------------------------
+
+BOOL BitmapReadAccess::ImplSetAccessPointers( ULONG nFormat )
+{
+ BOOL bRet = TRUE;
+
+ switch( nFormat )
+ {
+ CASE_FORMAT( _1BIT_MSB_PAL )
+ CASE_FORMAT( _1BIT_LSB_PAL )
+ CASE_FORMAT( _4BIT_MSN_PAL )
+ CASE_FORMAT( _4BIT_LSN_PAL )
+ CASE_FORMAT( _8BIT_PAL )
+ CASE_FORMAT( _8BIT_TC_MASK )
+ CASE_FORMAT( _16BIT_TC_MSB_MASK )
+ CASE_FORMAT( _16BIT_TC_LSB_MASK )
+ CASE_FORMAT( _24BIT_TC_BGR )
+ CASE_FORMAT( _24BIT_TC_RGB )
+ CASE_FORMAT( _24BIT_TC_MASK )
+ CASE_FORMAT( _32BIT_TC_ABGR )
+ CASE_FORMAT( _32BIT_TC_ARGB )
+ CASE_FORMAT( _32BIT_TC_BGRA )
+ CASE_FORMAT( _32BIT_TC_RGBA )
+ CASE_FORMAT( _32BIT_TC_MASK )
+
+ default:
+ bRet = FALSE;
+ break;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapReadAccess::ImplZeroInitUnusedBits()
+{
+ const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize();
+
+ if( nWidth && nHeight && nScanSize && GetBuffer() )
+ {
+ sal_uInt32 nBits;
+ bool bMsb;
+
+ const ULONG nScanlineFormat = GetScanlineFormat();
+ switch( nScanlineFormat )
+ {
+ case( BMP_FORMAT_1BIT_MSB_PAL ):
+ nBits = 1;
+ bMsb = true;
+ break;
+
+ case( BMP_FORMAT_1BIT_LSB_PAL ):
+ nBits = 1;
+ bMsb = false;
+ break;
+
+ case( BMP_FORMAT_4BIT_MSN_PAL ):
+ nBits = 4;
+ bMsb = true;
+ break;
+
+ case( BMP_FORMAT_4BIT_LSN_PAL ):
+ nBits = 4;
+ bMsb = false;
+ break;
+
+ case( BMP_FORMAT_8BIT_PAL ):
+ case( BMP_FORMAT_8BIT_TC_MASK ):
+ bMsb = true;
+ nBits = 8;
+ break;
+
+ case( BMP_FORMAT_16BIT_TC_MSB_MASK ):
+ case( BMP_FORMAT_16BIT_TC_LSB_MASK ):
+ bMsb = true;
+ nBits = 16;
+ break;
+
+ case( BMP_FORMAT_24BIT_TC_BGR ):
+ case( BMP_FORMAT_24BIT_TC_RGB ):
+ case( BMP_FORMAT_24BIT_TC_MASK ):
+ bMsb = true;
+ nBits = 24;
+ break;
+
+ case( BMP_FORMAT_32BIT_TC_ABGR ):
+ case( BMP_FORMAT_32BIT_TC_ARGB ):
+ case( BMP_FORMAT_32BIT_TC_BGRA ):
+ case( BMP_FORMAT_32BIT_TC_RGBA ):
+ case( BMP_FORMAT_32BIT_TC_MASK ):
+ bMsb = true;
+ nBits = 32;
+ break;
+
+ default:
+ {
+ DBG_ERROR( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format");
+ nBits = 0;
+ bMsb = true;
+ }
+ break;
+ }
+
+ nBits *= nWidth;
+ if( nScanSize % 4 || !bMsb )
+ {
+ DBG_ASSERT( 8*nScanSize >= nBits,
+ "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!");
+ const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits;
+ if( nLeftOverBits != 0 ) // else there is really nothing to do
+ {
+ const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U;
+ sal_uInt8 nMask;
+
+ if( bMsb )
+ nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL));
+ else
+ nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL));
+
+ BYTE* pLastBytes = (BYTE*)GetBuffer() + ( nScanSize - nBytes );
+ for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize )
+ {
+ *pLastBytes &= nMask;
+ for( sal_uInt32 j = 1; j < nBytes; j++ )
+ pLastBytes[j] = 0;
+ }
+ }
+ }
+ else if( nBits & 0x1f )
+ {
+ sal_uInt32 nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits );
+ BYTE* pLast4Bytes = (BYTE*) GetBuffer() + ( nScanSize - 4 );
+
+#ifdef OSL_LITENDIAN
+ nMask = SWAPLONG( nMask );
+#endif
+ for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize )
+ ( *(sal_uInt32*) pLast4Bytes ) &= nMask;
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapReadAccess::Flush()
+{
+ ImplDestroy();
+}
+
+// ------------------------------------------------------------------
+
+void BitmapReadAccess::ReAccess( BOOL bModify )
+{
+ const ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
+
+ DBG_ASSERT( !mpBuffer, "No ReAccess possible while bitmap is being accessed!" );
+ DBG_ASSERT( pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ), "Accessed bitmap does not exist anymore!" );
+
+ if( !mpBuffer && pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ) )
+ {
+ mbModify = bModify;
+ ImplCreate( maBitmap );
+ }
+}
+
+// ------------------------------------------------------------------
+
+USHORT BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const
+{
+ return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
+}
+
+// ---------------------
+// - BitmapWriteAccess -
+// ---------------------
+
+BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) :
+ BitmapReadAccess( rBitmap, TRUE ),
+ mpLineColor ( NULL ),
+ mpFillColor ( NULL )
+{
+}
+
+// ------------------------------------------------------------------
+
+BitmapWriteAccess::~BitmapWriteAccess()
+{
+ delete mpLineColor;
+ delete mpFillColor;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc )
+{
+ DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
+ DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" );
+ DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
+
+ if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
+ ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) )
+ {
+ memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() );
+ }
+ else
+ // TODO: use fastbmp infrastructure
+ for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ )
+ SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) );
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline,
+ ULONG nSrcScanlineFormat, ULONG nSrcScanlineSize )
+{
+ const ULONG nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat );
+
+ DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
+ DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) ||
+ ( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ),
+ "No copying possible between palette and non palette scanlines!" );
+
+ const ULONG nCount = Min( GetScanlineSize(), nSrcScanlineSize );
+
+ if( nCount )
+ {
+ if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) )
+ memcpy( mpScanBuf[ nY ], aSrcScanline, nCount );
+ else
+ {
+ DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK &&
+ nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK &&
+ nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK,
+ "No support for pixel formats with color masks yet!" );
+
+ // TODO: use fastbmp infrastructure
+ FncGetPixel pFncGetPixel;
+
+ switch( nFormat )
+ {
+ case( BMP_FORMAT_1BIT_MSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break;
+ case( BMP_FORMAT_1BIT_LSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break;
+ case( BMP_FORMAT_4BIT_MSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break;
+ case( BMP_FORMAT_4BIT_LSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break;
+ case( BMP_FORMAT_8BIT_PAL ): pFncGetPixel = GetPixelFor_8BIT_PAL; break;
+ case( BMP_FORMAT_8BIT_TC_MASK ): pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break;
+ case( BMP_FORMAT_16BIT_TC_MSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break;
+ case( BMP_FORMAT_16BIT_TC_LSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break;
+ case( BMP_FORMAT_24BIT_TC_BGR ): pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break;
+ case( BMP_FORMAT_24BIT_TC_RGB ): pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break;
+ case( BMP_FORMAT_24BIT_TC_MASK ): pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break;
+ case( BMP_FORMAT_32BIT_TC_ABGR ): pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break;
+ case( BMP_FORMAT_32BIT_TC_ARGB ): pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break;
+ case( BMP_FORMAT_32BIT_TC_BGRA ): pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break;
+ case( BMP_FORMAT_32BIT_TC_RGBA ): pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break;
+ case( BMP_FORMAT_32BIT_TC_MASK ): pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break;
+
+ default:
+ pFncGetPixel = NULL;
+ break;
+ }
+
+ if( pFncGetPixel )
+ {
+ const ColorMask aDummyMask;
+
+ for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ )
+ SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) );
+ }
+ }
+ }
+}
+
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc )
+{
+ DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
+
+ if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
+ ( GetScanlineSize() == rReadAcc.GetScanlineSize() ) )
+ {
+ const long nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() );
+ const ULONG nCount = nHeight * mpBuffer->mnScanlineSize;
+
+ memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount );
+ }
+ else
+ for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ )
+ CopyScanline( nY, rReadAcc );
+}
diff --git a/vcl/source/gdi/bmpacc2.cxx b/vcl/source/gdi/bmpacc2.cxx
new file mode 100644
index 000000000000..436c165d3bb5
--- /dev/null
+++ b/vcl/source/gdi/bmpacc2.cxx
@@ -0,0 +1,331 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/salbtype.hxx>
+#include <vcl/bmpacc.hxx>
+
+// ----------------
+// - BitmapAccess -
+// ----------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _1BIT_MSB_PAL )
+{
+ return( pScanline[ nX >> 3 ] & ( 1 << ( 7 - ( nX & 7 ) ) ) ? 1 : 0 );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _1BIT_MSB_PAL )
+{
+ BYTE& rByte = pScanline[ nX >> 3 ];
+
+ ( rBitmapColor.GetIndex() & 1 ) ? ( rByte |= 1 << ( 7 - ( nX & 7 ) ) ) :
+ ( rByte &= ~( 1 << ( 7 - ( nX & 7 ) ) ) );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _1BIT_LSB_PAL )
+{
+ return( pScanline[ nX >> 3 ] & ( 1 << ( nX & 7 ) ) ? 1 : 0 );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _1BIT_LSB_PAL )
+{
+ BYTE& rByte = pScanline[ nX >> 3 ];
+
+ ( rBitmapColor.GetIndex() & 1 ) ? ( rByte |= 1 << ( nX & 7 ) ) :
+ ( rByte &= ~( 1 << ( nX & 7 ) ) );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _4BIT_MSN_PAL )
+{
+ return( ( pScanline[ nX >> 1 ] >> ( nX & 1 ? 0 : 4 ) ) & 0x0f );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _4BIT_MSN_PAL )
+{
+ BYTE& rByte = pScanline[ nX >> 1 ];
+
+ ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( rBitmapColor.GetIndex() & 0x0f ) ) :
+ ( rByte &= 0x0f, rByte |= ( rBitmapColor.GetIndex() << 4 ) );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _4BIT_LSN_PAL )
+{
+ return( ( pScanline[ nX >> 1 ] >> ( nX & 1 ? 4 : 0 ) ) & 0x0f );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _4BIT_LSN_PAL )
+{
+ BYTE& rByte = pScanline[ nX >> 1 ];
+
+ ( nX & 1 ) ? ( rByte &= 0x0f, rByte |= ( rBitmapColor.GetIndex() << 4 ) ) :
+ ( rByte &= 0xf0, rByte |= ( rBitmapColor.GetIndex() & 0x0f ) );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _8BIT_PAL )
+{
+ return pScanline[ nX ];
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _8BIT_PAL )
+{
+ pScanline[ nX ] = rBitmapColor.GetIndex();
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL( _8BIT_TC_MASK )
+{
+ BitmapColor aColor;
+ rMask.GetColorFor8Bit( aColor, pScanline + nX );
+ return aColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL( _8BIT_TC_MASK )
+{
+ rMask.SetColorFor8Bit( rBitmapColor, pScanline + nX );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL( _16BIT_TC_MSB_MASK )
+{
+ BitmapColor aColor;
+ rMask.GetColorFor16BitMSB( aColor, pScanline + ( nX << 1UL ) );
+ return aColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL( _16BIT_TC_MSB_MASK )
+{
+ rMask.SetColorFor16BitMSB( rBitmapColor, pScanline + ( nX << 1UL ) );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL( _16BIT_TC_LSB_MASK )
+{
+ BitmapColor aColor;
+ rMask.GetColorFor16BitLSB( aColor, pScanline + ( nX << 1UL ) );
+ return aColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL( _16BIT_TC_LSB_MASK )
+{
+ rMask.SetColorFor16BitLSB( rBitmapColor, pScanline + ( nX << 1UL ) );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _24BIT_TC_BGR )
+{
+ BitmapColor aBitmapColor;
+
+ aBitmapColor.SetBlue( *( pScanline = pScanline + nX * 3 )++ );
+ aBitmapColor.SetGreen( *pScanline++ );
+ aBitmapColor.SetRed( *pScanline );
+
+ return aBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _24BIT_TC_BGR )
+{
+ *( pScanline = pScanline + nX * 3 )++ = rBitmapColor.GetBlue();
+ *pScanline++ = rBitmapColor.GetGreen();
+ *pScanline = rBitmapColor.GetRed();
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _24BIT_TC_RGB )
+{
+ BitmapColor aBitmapColor;
+
+ aBitmapColor.SetRed( *( pScanline = pScanline + nX * 3 )++ );
+ aBitmapColor.SetGreen( *pScanline++ );
+ aBitmapColor.SetBlue( *pScanline );
+
+ return aBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _24BIT_TC_RGB )
+{
+ *( pScanline = pScanline + nX * 3 )++ = rBitmapColor.GetRed();
+ *pScanline++ = rBitmapColor.GetGreen();
+ *pScanline = rBitmapColor.GetBlue();
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL( _24BIT_TC_MASK )
+{
+ BitmapColor aColor;
+ rMask.GetColorFor24Bit( aColor, pScanline + nX * 3L );
+ return aColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL( _24BIT_TC_MASK )
+{
+ rMask.SetColorFor24Bit( rBitmapColor, pScanline + nX * 3L );
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _32BIT_TC_ABGR )
+{
+ BitmapColor aBitmapColor;
+
+ aBitmapColor.SetBlue( *( pScanline = pScanline + ( nX << 2 ) + 1 )++ );
+ aBitmapColor.SetGreen( *pScanline++ );
+ aBitmapColor.SetRed( *pScanline );
+
+ return aBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _32BIT_TC_ABGR )
+{
+ *( pScanline = pScanline + ( nX << 2 ) )++ = 0;
+ *pScanline++ = rBitmapColor.GetBlue();
+ *pScanline++ = rBitmapColor.GetGreen();
+ *pScanline = rBitmapColor.GetRed();
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _32BIT_TC_ARGB )
+{
+ BitmapColor aBitmapColor;
+
+ aBitmapColor.SetRed( *( pScanline = pScanline + ( nX << 2 ) + 1 )++ );
+ aBitmapColor.SetGreen( *pScanline++ );
+ aBitmapColor.SetBlue( *pScanline );
+
+ return aBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _32BIT_TC_ARGB )
+{
+ *( pScanline = pScanline + ( nX << 2 ) )++ = 0;
+ *pScanline++ = rBitmapColor.GetRed();
+ *pScanline++ = rBitmapColor.GetGreen();
+ *pScanline = rBitmapColor.GetBlue();
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _32BIT_TC_BGRA )
+{
+ BitmapColor aBitmapColor;
+
+ aBitmapColor.SetBlue( *( pScanline = pScanline + ( nX << 2 ) )++ );
+ aBitmapColor.SetGreen( *pScanline++ );
+ aBitmapColor.SetRed( *pScanline );
+
+ return aBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _32BIT_TC_BGRA )
+{
+ *( pScanline = pScanline + ( nX << 2 ) )++ = rBitmapColor.GetBlue();
+ *pScanline++ = rBitmapColor.GetGreen();
+ *pScanline++ = rBitmapColor.GetRed();
+ *pScanline = 0;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL_NOMASK( _32BIT_TC_RGBA )
+{
+ BitmapColor aBitmapColor;
+
+ aBitmapColor.SetRed( *( pScanline = pScanline + ( nX << 2 ) )++ );
+ aBitmapColor.SetGreen( *pScanline++ );
+ aBitmapColor.SetBlue( *pScanline );
+
+ return aBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL_NOMASK( _32BIT_TC_RGBA )
+{
+ *( pScanline = pScanline + ( nX << 2 ) )++ = rBitmapColor.GetRed();
+ *pScanline++ = rBitmapColor.GetGreen();
+ *pScanline++ = rBitmapColor.GetBlue();
+ *pScanline = 0;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_GETPIXEL( _32BIT_TC_MASK )
+{
+ BitmapColor aColor;
+ rMask.GetColorFor32Bit( aColor, pScanline + ( nX << 2UL ) );
+ return aColor;
+}
+
+// ------------------------------------------------------------------
+
+IMPL_FORMAT_SETPIXEL( _32BIT_TC_MASK )
+{
+ rMask.SetColorFor32Bit( rBitmapColor, pScanline + ( nX << 2UL ) );
+}
diff --git a/vcl/source/gdi/bmpacc3.cxx b/vcl/source/gdi/bmpacc3.cxx
new file mode 100644
index 000000000000..a89015d12351
--- /dev/null
+++ b/vcl/source/gdi/bmpacc3.cxx
@@ -0,0 +1,410 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/salbtype.hxx>
+#include <vcl/bitmap.hxx>
+#include <tools/poly.hxx>
+#include <vcl/region.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/bmpfast.hxx>
+
+// ---------------------
+// - BitmapWriteAccess -
+// ---------------------
+
+void BitmapWriteAccess::SetLineColor()
+{
+ delete mpLineColor;
+ mpLineColor = NULL;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::SetLineColor( const Color& rColor )
+{
+ delete mpLineColor;
+
+ if( rColor.GetTransparency() == 255 )
+ mpLineColor = NULL;
+ else
+ mpLineColor = ( HasPalette() ? new BitmapColor( (BYTE) GetBestPaletteIndex( rColor ) ) : new BitmapColor( rColor ) );
+}
+
+// ------------------------------------------------------------------
+
+Color BitmapWriteAccess::GetLineColor() const
+{
+ Color aRet;
+
+ if( mpLineColor )
+ aRet = (const Color&) *mpLineColor;
+ else
+ aRet.SetTransparency( 255 );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::SetFillColor()
+{
+ delete mpFillColor;
+ mpFillColor = NULL;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::SetFillColor( const Color& rColor )
+{
+ delete mpFillColor;
+
+ if( rColor.GetTransparency() == 255 )
+ mpFillColor = NULL;
+ else
+ mpFillColor = ( HasPalette() ? new BitmapColor( (BYTE) GetBestPaletteIndex( rColor ) ) : new BitmapColor( rColor ) );
+}
+
+// ------------------------------------------------------------------
+
+Color BitmapWriteAccess::GetFillColor() const
+{
+ Color aRet;
+
+ if( mpFillColor )
+ aRet = (const Color&) *mpFillColor;
+ else
+ aRet.SetTransparency( 255 );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::Erase( const Color& rColor )
+{
+ // convert the color format from RGB to palette index if needed
+ // TODO: provide and use Erase( BitmapColor& method)
+ BitmapColor aColor = rColor;
+ if( HasPalette() )
+ aColor = BitmapColor( (BYTE)GetBestPaletteIndex( rColor) );
+ // try fast bitmap method first
+ if( ImplFastEraseBitmap( *mpBuffer, aColor ) )
+ return;
+
+ // use the canonical method to clear the bitmap
+ BitmapColor* pOldFillColor = mpFillColor ? new BitmapColor( *mpFillColor ) : NULL;
+ const Point aPoint;
+ const Rectangle aRect( aPoint, maBitmap.GetSizePixel() );
+
+ SetFillColor( rColor );
+ FillRect( aRect );
+ delete mpFillColor;
+ mpFillColor = pOldFillColor;
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::DrawLine( const Point& rStart, const Point& rEnd )
+{
+ if( mpLineColor )
+ {
+ const BitmapColor& rLineColor = *mpLineColor;
+ long nX, nY;
+
+ if ( rStart.X() == rEnd.X() )
+ {
+ // vertikale Line
+ const long nEndY = rEnd.Y();
+
+ nX = rStart.X();
+ nY = rStart.Y();
+
+ if ( nEndY > nY )
+ {
+ for (; nY <= nEndY; nY++ )
+ SetPixel( nY, nX, rLineColor );
+ }
+ else
+ {
+ for (; nY >= nEndY; nY-- )
+ SetPixel( nY, nX, rLineColor );
+ }
+ }
+ else if ( rStart.Y() == rEnd.Y() )
+ {
+ // horizontale Line
+ const long nEndX = rEnd.X();
+
+ nX = rStart.X();
+ nY = rStart.Y();
+
+ if ( nEndX > nX )
+ {
+ for (; nX <= nEndX; nX++ )
+ SetPixel( nY, nX, rLineColor );
+ }
+ else
+ {
+ for (; nX >= nEndX; nX-- )
+ SetPixel( nY, nX, rLineColor );
+ }
+ }
+ else
+ {
+ const long nDX = labs( rEnd.X() - rStart.X() );
+ const long nDY = labs( rEnd.Y() - rStart.Y() );
+ long nX1;
+ long nY1;
+ long nX2;
+ long nY2;
+
+ if ( nDX >= nDY )
+ {
+ if ( rStart.X() < rEnd.X() )
+ {
+ nX1 = rStart.X();
+ nY1 = rStart.Y();
+ nX2 = rEnd.X();
+ nY2 = rEnd.Y();
+ }
+ else
+ {
+ nX1 = rEnd.X();
+ nY1 = rEnd.Y();
+ nX2 = rStart.X();
+ nY2 = rStart.Y();
+ }
+
+ const long nDYX = ( nDY - nDX ) << 1;
+ const long nDY2 = nDY << 1;
+ long nD = nDY2 - nDX;
+ BOOL bPos = nY1 < nY2;
+
+ for ( nX = nX1, nY = nY1; nX <= nX2; nX++ )
+ {
+ SetPixel( nY, nX, rLineColor );
+
+ if ( nD < 0 )
+ nD += nDY2;
+ else
+ {
+ nD += nDYX;
+
+ if ( bPos )
+ nY++;
+ else
+ nY--;
+ }
+ }
+ }
+ else
+ {
+ if ( rStart.Y() < rEnd.Y() )
+ {
+ nX1 = rStart.X();
+ nY1 = rStart.Y();
+ nX2 = rEnd.X();
+ nY2 = rEnd.Y();
+ }
+ else
+ {
+ nX1 = rEnd.X();
+ nY1 = rEnd.Y();
+ nX2 = rStart.X();
+ nY2 = rStart.Y();
+ }
+
+ const long nDYX = ( nDX - nDY ) << 1;
+ const long nDY2 = nDX << 1;
+ long nD = nDY2 - nDY;
+ BOOL bPos = nX1 < nX2;
+
+ for ( nX = nX1, nY = nY1; nY <= nY2; nY++ )
+ {
+ SetPixel( nY, nX, rLineColor );
+
+ if ( nD < 0 )
+ nD += nDY2;
+ else
+ {
+ nD += nDYX;
+
+ if ( bPos )
+ nX++;
+ else
+ nX--;
+ }
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::FillRect( const Rectangle& rRect )
+{
+ if( mpFillColor )
+ {
+ const BitmapColor& rFillColor = *mpFillColor;
+ Point aPoint;
+ Rectangle aRect( aPoint, maBitmap.GetSizePixel() );
+
+ aRect.Intersection( rRect );
+
+ if( !aRect.IsEmpty() )
+ {
+ const long nStartX = rRect.Left();
+ const long nStartY = rRect.Top();
+ const long nEndX = rRect.Right();
+ const long nEndY = rRect.Bottom();
+
+ for( long nY = nStartY; nY <= nEndY; nY++ )
+ for( long nX = nStartX; nX <= nEndX; nX++ )
+ SetPixel( nY, nX, rFillColor );
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::DrawRect( const Rectangle& rRect )
+{
+ if( mpFillColor )
+ FillRect( rRect );
+
+ if( mpLineColor && ( !mpFillColor || ( *mpFillColor != *mpLineColor ) ) )
+ {
+ DrawLine( rRect.TopLeft(), rRect.TopRight() );
+ DrawLine( rRect.TopRight(), rRect.BottomRight() );
+ DrawLine( rRect.BottomRight(), rRect.BottomLeft() );
+ DrawLine( rRect.BottomLeft(), rRect.TopLeft() );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::FillPolygon( const Polygon& rPoly )
+{
+ const USHORT nSize = rPoly.GetSize();
+
+ if( nSize && mpFillColor )
+ {
+ const BitmapColor& rFillColor = *mpFillColor;
+ Region aRegion( rPoly );
+ Rectangle aRect;
+
+ aRegion.Intersect( Rectangle( Point(), Size( Width(), Height() ) ) );
+
+ if( !aRegion.IsEmpty() )
+ {
+ RegionHandle aRegHandle( aRegion.BeginEnumRects() );
+
+ while( aRegion.GetNextEnumRect( aRegHandle, aRect ) )
+ for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ )
+ for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ )
+ SetPixel( nY, nX, rFillColor );
+
+ aRegion.EndEnumRects( aRegHandle );
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::DrawPolygon( const Polygon& rPoly )
+{
+ if( mpFillColor )
+ FillPolygon( rPoly );
+
+ if( mpLineColor && ( !mpFillColor || ( *mpFillColor != *mpLineColor ) ) )
+ {
+ const USHORT nSize = rPoly.GetSize();
+
+ for( USHORT i = 0, nSize1 = nSize - 1; i < nSize1; i++ )
+ DrawLine( rPoly[ i ], rPoly[ i + 1 ] );
+
+ if( rPoly[ nSize - 1 ] != rPoly[ 0 ] )
+ DrawLine( rPoly[ nSize - 1 ], rPoly[ 0 ] );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::FillPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ const USHORT nCount = rPolyPoly.Count();
+
+ if( nCount && mpFillColor )
+ {
+ const BitmapColor& rFillColor = *mpFillColor;
+ Region aRegion( rPolyPoly );
+ Rectangle aRect;
+
+ aRegion.Intersect( Rectangle( Point(), Size( Width(), Height() ) ) );
+
+ if( !aRegion.IsEmpty() )
+ {
+ RegionHandle aRegHandle( aRegion.BeginEnumRects() );
+
+ while( aRegion.GetNextEnumRect( aRegHandle, aRect ) )
+ for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ )
+ for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ )
+ SetPixel( nY, nX, rFillColor );
+
+ aRegion.EndEnumRects( aRegHandle );
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void BitmapWriteAccess::DrawPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ if( mpFillColor )
+ FillPolyPolygon( rPolyPoly );
+
+ if( mpLineColor && ( !mpFillColor || ( *mpFillColor != *mpLineColor ) ) )
+ {
+ for( USHORT n = 0, nCount = rPolyPoly.Count(); n < nCount; )
+ {
+ const Polygon& rPoly = rPolyPoly[ n++ ];
+ const USHORT nSize = rPoly.GetSize();
+
+ if( nSize )
+ {
+ for( USHORT i = 0, nSize1 = nSize - 1; i < nSize1; i++ )
+ DrawLine( rPoly[ i ], rPoly[ i + 1 ] );
+
+ if( rPoly[ nSize - 1 ] != rPoly[ 0 ] )
+ DrawLine( rPoly[ nSize - 1 ], rPoly[ 0 ] );
+ }
+ }
+ }
+}
diff --git a/vcl/source/gdi/bmpconv.cxx b/vcl/source/gdi/bmpconv.cxx
new file mode 100644
index 000000000000..d949f519d197
--- /dev/null
+++ b/vcl/source/gdi/bmpconv.cxx
@@ -0,0 +1,213 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/bitmap.hxx>
+#include <vcl/impbmpconv.hxx>
+#include <vcl/svapp.hxx>
+#include <vos/mutex.hxx>
+#include <tools/stream.hxx>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <cppuhelper/compbase1.hxx>
+
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::reflection;
+using namespace com::sun::star::awt;
+using namespace rtl;
+
+namespace vcl {
+
+class BmpTransporter :
+ public cppu::WeakImplHelper1< com::sun::star::awt::XBitmap >
+{
+ Sequence<sal_Int8> m_aBM;
+ com::sun::star::awt::Size m_aSize;
+public:
+ BmpTransporter( const Bitmap& rBM );
+ virtual ~BmpTransporter();
+
+ virtual com::sun::star::awt::Size SAL_CALL getSize() throw();
+ virtual Sequence< sal_Int8 > SAL_CALL getDIB() throw();
+ virtual Sequence< sal_Int8 > SAL_CALL getMaskDIB() throw();
+};
+
+class BmpConverter :
+ public cppu::WeakImplHelper1< com::sun::star::script::XInvocation >
+{
+public:
+ BmpConverter();
+ virtual ~BmpConverter();
+
+ virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() throw();
+ virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue )
+ throw( UnknownPropertyException );
+ virtual Any SAL_CALL getValue( const OUString& rProperty )
+ throw( UnknownPropertyException );
+ virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) throw();
+ virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) throw();
+
+ virtual Any SAL_CALL invoke( const OUString& rFunction,
+ const Sequence< Any >& rParams,
+ Sequence< sal_Int16 >& rOutParamIndex,
+ Sequence< Any >& rOutParam
+ )
+ throw( CannotConvertException, InvocationTargetException );
+};
+
+}
+
+using namespace vcl;
+
+Reference< XInvocation > vcl::createBmpConverter()
+{
+ return static_cast<XInvocation*>(new BmpConverter());
+}
+
+BmpConverter::BmpConverter()
+{
+}
+
+BmpConverter::~BmpConverter()
+{
+}
+
+Reference< XIntrospectionAccess > SAL_CALL BmpConverter::getIntrospection() throw()
+{
+ return Reference< XIntrospectionAccess >();
+}
+
+void SAL_CALL BmpConverter::setValue( const OUString&, const Any& ) throw( UnknownPropertyException )
+{
+ throw UnknownPropertyException();
+}
+
+Any SAL_CALL BmpConverter::getValue( const OUString& ) throw( UnknownPropertyException )
+{
+ throw UnknownPropertyException();
+}
+
+sal_Bool SAL_CALL BmpConverter::hasMethod( const OUString& rName ) throw()
+{
+ return rName.equalsIgnoreAsciiCase( OUString::createFromAscii( "convert-bitmap-depth" ) );
+}
+
+sal_Bool SAL_CALL BmpConverter::hasProperty( const OUString& ) throw()
+{
+ return sal_False;
+}
+
+Any SAL_CALL BmpConverter::invoke(
+ const OUString& rFunction,
+ const Sequence< Any >& rParams,
+ Sequence< sal_Int16 >&,
+ Sequence< Any >& )
+ throw( CannotConvertException, InvocationTargetException )
+{
+ Any aRet;
+
+ if( rFunction.equalsIgnoreAsciiCase( OUString::createFromAscii( "convert-bitmap-depth" ) ) )
+ {
+ Reference< XBitmap > xBM;
+ sal_uInt16 nTargetDepth = 0;
+ if( rParams.getLength() != 2 )
+ throw CannotConvertException();
+
+ if( ! (rParams.getConstArray()[0] >>= xBM ) ||
+ ! ( rParams.getConstArray()[1] >>= nTargetDepth ) )
+ throw CannotConvertException();
+
+ Sequence< sal_Int8 > aDIB = xBM->getDIB();
+
+ // call into vcl not thread safe
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ SvMemoryStream aStream( aDIB.getArray(), aDIB.getLength(), STREAM_READ | STREAM_WRITE );
+ Bitmap aBM;
+ aBM.Read( aStream, TRUE );
+ if( nTargetDepth < 4 )
+ nTargetDepth = 1;
+ else if( nTargetDepth < 8 )
+ nTargetDepth = 4;
+ else if( nTargetDepth >8 && nTargetDepth < 24 )
+ nTargetDepth = 24;
+
+ if( aBM.GetBitCount() == 24 && nTargetDepth <= 8 )
+ aBM.Dither( BMP_DITHER_FLOYD );
+
+ if( aBM.GetBitCount() != nTargetDepth )
+ {
+ switch( nTargetDepth )
+ {
+ case 1: aBM.Convert( BMP_CONVERSION_1BIT_THRESHOLD );break;
+ case 4: aBM.ReduceColors( BMP_CONVERSION_4BIT_COLORS );break;
+ case 8: aBM.ReduceColors( BMP_CONVERSION_8BIT_COLORS );break;
+ case 24: aBM.Convert( BMP_CONVERSION_24BIT );break;
+ }
+ }
+ xBM = new BmpTransporter( aBM );
+ aRet <<= xBM;
+ }
+ else
+ throw InvocationTargetException();
+
+ return aRet;
+}
+
+BmpTransporter::BmpTransporter( const Bitmap& rBM )
+{
+ m_aSize.Width = rBM.GetSizePixel().Width();
+ m_aSize.Height = rBM.GetSizePixel().Height();
+ SvMemoryStream aStream;
+ rBM.Write( aStream, FALSE, TRUE );
+ m_aBM = Sequence<sal_Int8>(static_cast<const sal_Int8*>(aStream.GetData()),
+ aStream.GetEndOfData());
+}
+
+BmpTransporter::~BmpTransporter()
+{
+}
+
+com::sun::star::awt::Size SAL_CALL BmpTransporter::getSize() throw()
+{
+ return m_aSize;
+}
+
+Sequence< sal_Int8 > SAL_CALL BmpTransporter::getDIB() throw()
+{
+ return m_aBM;
+}
+
+Sequence< sal_Int8 > SAL_CALL BmpTransporter::getMaskDIB() throw()
+{
+ return Sequence< sal_Int8 >();
+}
diff --git a/vcl/source/gdi/bmpfast.cxx b/vcl/source/gdi/bmpfast.cxx
new file mode 100644
index 000000000000..e6c94ba0475e
--- /dev/null
+++ b/vcl/source/gdi/bmpfast.cxx
@@ -0,0 +1,1040 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/bmpfast.hxx>
+
+#ifndef NO_OPTIMIZED_BITMAP_ACCESS
+
+#include <tools/debug.hxx>
+#include <vcl/bmpacc.hxx>
+
+#define FAST_ARGB_BGRA
+
+#include <stdlib.h>
+static bool bDisableFastBitops = (getenv( "SAL_DISABLE_BITMAPS_OPTS" ) != NULL);
+
+typedef unsigned char PIXBYTE;
+
+class BasePixelPtr
+{
+public:
+ BasePixelPtr( PIXBYTE* p = NULL ) : mpPixel( p ) {}
+ void SetRawPtr( PIXBYTE* pRawPtr ) { mpPixel = pRawPtr; }
+ PIXBYTE* GetRawPtr( void ) const { return mpPixel; }
+ void AddByteOffset( int nByteOffset ) { mpPixel += nByteOffset; }
+ bool operator<( const BasePixelPtr& rCmp ) const { return (mpPixel < rCmp.mpPixel); }
+
+protected:
+ PIXBYTE* mpPixel;
+};
+
+template <ULONG PIXFMT>
+class TrueColorPixelPtr : public BasePixelPtr
+{
+public:
+ PIXBYTE GetRed() const;
+ PIXBYTE GetGreen() const;
+ PIXBYTE GetBlue() const;
+ PIXBYTE GetAlpha() const;
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const;
+ void SetAlpha( PIXBYTE a ) const;
+ void operator++(int);
+};
+
+// =======================================================================
+// template specializations for truecolor pixel formats
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_24BIT_TC_RGB> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 3; }
+
+ PIXBYTE GetRed() const { return mpPixel[0]; }
+ PIXBYTE GetGreen() const { return mpPixel[1]; }
+ PIXBYTE GetBlue() const { return mpPixel[2]; }
+ PIXBYTE GetAlpha() const { return 0; }
+ void SetAlpha( PIXBYTE ) const {}
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[0] = r;
+ mpPixel[1] = g;
+ mpPixel[2] = b;
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_24BIT_TC_BGR> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 3; }
+
+ PIXBYTE GetRed() const { return mpPixel[2]; }
+ PIXBYTE GetGreen() const { return mpPixel[1]; }
+ PIXBYTE GetBlue() const { return mpPixel[0]; }
+ PIXBYTE GetAlpha() const { return 0; }
+ void SetAlpha( PIXBYTE ) const {}
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[0] = b;
+ mpPixel[1] = g;
+ mpPixel[2] = r;
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_ARGB> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 4; }
+
+ PIXBYTE GetRed() const { return mpPixel[1]; }
+ PIXBYTE GetGreen() const { return mpPixel[2]; }
+ PIXBYTE GetBlue() const { return mpPixel[3]; }
+ PIXBYTE GetAlpha() const { return mpPixel[0]; }
+ void SetAlpha( PIXBYTE a ) const { mpPixel[0] = a; }
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[1] = r;
+ mpPixel[2] = g;
+ mpPixel[3] = b;
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_ABGR> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 4; }
+
+ PIXBYTE GetRed() const { return mpPixel[3]; }
+ PIXBYTE GetGreen() const { return mpPixel[2]; }
+ PIXBYTE GetBlue() const { return mpPixel[1]; }
+ PIXBYTE GetAlpha() const { return mpPixel[0]; }
+ void SetAlpha( PIXBYTE a ) const { mpPixel[0] = a; }
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[1] = b;
+ mpPixel[2] = g;
+ mpPixel[3] = r;
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_RGBA> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 4; }
+
+ PIXBYTE GetRed() const { return mpPixel[0]; }
+ PIXBYTE GetGreen() const { return mpPixel[1]; }
+ PIXBYTE GetBlue() const { return mpPixel[2]; }
+ PIXBYTE GetAlpha() const { return mpPixel[3]; }
+ void SetAlpha( PIXBYTE a ) const{ mpPixel[3] = a; }
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[0] = r;
+ mpPixel[1] = g;
+ mpPixel[2] = b;
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_BGRA> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 4; }
+
+ PIXBYTE GetRed() const { return mpPixel[2]; }
+ PIXBYTE GetGreen() const { return mpPixel[1]; }
+ PIXBYTE GetBlue() const { return mpPixel[0]; }
+ PIXBYTE GetAlpha() const { return mpPixel[3]; }
+ void SetAlpha( PIXBYTE a ) const{ mpPixel[3] = a; }
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[0] = b;
+ mpPixel[1] = g;
+ mpPixel[2] = r;
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_16BIT_TC_MSB_MASK> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 2; }
+
+ // TODO: non565-RGB
+ PIXBYTE GetRed() const { return (mpPixel[0] & 0xF8U); }
+ PIXBYTE GetGreen() const { return (mpPixel[0]<<5U) | ((mpPixel[1]>>3U)&28U); }
+ PIXBYTE GetBlue() const { return (mpPixel[1]<<3U); }
+ PIXBYTE GetAlpha() const { return 0; }
+ void SetAlpha( PIXBYTE ) const {}
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[0] = ((g >> 5U) & 7U) | (r & 0xF8U);
+ mpPixel[1] = ((g & 28U)<< 3U) | (b >> 3U);
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_16BIT_TC_LSB_MASK> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 2; }
+
+ // TODO: non565-RGB
+ PIXBYTE GetRed() const { return (mpPixel[1] & 0xF8U); }
+ PIXBYTE GetGreen() const { return (mpPixel[1]<<5U) | ((mpPixel[0]>>3U)&28U); }
+ PIXBYTE GetBlue() const { return (mpPixel[0]<<3U); }
+ PIXBYTE GetAlpha() const { return 0; }
+ void SetAlpha( PIXBYTE ) const {}
+
+ void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
+ {
+ mpPixel[0] = ((g & 28U)<< 3U) | (b >> 3U);
+ mpPixel[1] = ((g >> 5U) & 7U) | (r & 0xF8U);
+ }
+};
+
+// -----------------------------------------------------------------------
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_8BIT_TC_MASK> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 1; }
+ PIXBYTE GetAlpha() const { return mpPixel[0]; }
+ void SetAlpha( PIXBYTE a ) const { mpPixel[0] = a; }
+ void SetColor( PIXBYTE, PIXBYTE, PIXBYTE ) const {}
+};
+
+// TODO: for some reason many Alpha maps are BMP_FORMAT_8BIT_PAL
+// they should be BMP_FORMAT_8BIT_TC_MASK
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_8BIT_PAL>
+: public TrueColorPixelPtr<BMP_FORMAT_8BIT_TC_MASK>
+{};
+
+#if 0
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_24BIT_TC_MASK> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 3; }
+
+ unsigned GetAlpha() const
+ {
+ unsigned nAlpha = mpPixel[0];
+ nAlpha |= mpPixel[1] << 8U;
+ nAlpha |= mpPixel[2] << 16U;
+ return nAlpha;
+ }
+
+ void SetAlpha( unsigned nAlpha ) const
+ {
+ mpPixel[0] = nAlpha;
+ mpPixel[1] = nAlpha >> 8U;
+ mpPixel[2] = nAlpha >> 16U;
+ }
+};
+
+template <>
+class TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_MASK> : public BasePixelPtr
+{
+public:
+ void operator++() { mpPixel += 4; }
+
+ unsigned GetAlpha() const
+ {
+#ifdef OSL_BIGENDIAN
+ unsigned nAlpha = *reinterpret_cast<unsigned*>( mpPixel );
+#else
+ unsigned nAlpha = mpPixel[0];
+ nAlpha |= mpPixel[1] << 8U;
+ nAlpha |= mpPixel[2] << 16U;
+ nAlpha |= mpPixel[3] << 24U;
+#endif
+ return nAlpha;
+ }
+
+ void SetAlpha( unsigned nAlpha ) const
+ {
+#ifdef OSL_BIGENDIAN
+ *reinterpret_cast<unsigned*>( mpPixel ) = nAlpha;
+#else
+ mpPixel[0] = nAlpha;
+ mpPixel[1] = nAlpha >> 8U;
+ mpPixel[2] = nAlpha >> 16U;
+ mpPixel[3] = nAlpha >> 24U;
+#endif
+ }
+};
+
+#endif
+
+// =======================================================================
+// converting truecolor formats
+
+template <ULONG SRCFMT, ULONG DSTFMT>
+inline void ImplConvertPixel( const TrueColorPixelPtr<DSTFMT>& rDst,
+ const TrueColorPixelPtr<SRCFMT>& rSrc )
+{
+ rDst.SetColor( rSrc.GetRed(), rSrc.GetGreen(), rSrc.GetBlue() );
+ rDst.SetAlpha( rSrc.GetAlpha() );
+}
+
+// -----------------------------------------------------------------------
+
+template <>
+inline void ImplConvertPixel<BMP_FORMAT_16BIT_TC_LSB_MASK, BMP_FORMAT_16BIT_TC_MSB_MASK> (
+ const TrueColorPixelPtr<BMP_FORMAT_16BIT_TC_MSB_MASK>& rDst,
+ const TrueColorPixelPtr<BMP_FORMAT_16BIT_TC_LSB_MASK>& rSrc )
+{
+ // byte swapping
+ const PIXBYTE* pSrc = rSrc.GetRawPtr();
+ PIXBYTE* pDst = rDst.GetRawPtr();
+ pDst[1] = pSrc[0];
+ pDst[0] = pSrc[1];
+}
+
+// -----------------------------------------------------------------------
+
+template <ULONG SRCFMT, ULONG DSTFMT>
+inline void ImplConvertLine( const TrueColorPixelPtr<DSTFMT>& rDst,
+ const TrueColorPixelPtr<SRCFMT>& rSrc, int nPixelCount )
+{
+ TrueColorPixelPtr<DSTFMT> aDst( rDst );
+ TrueColorPixelPtr<SRCFMT> aSrc( rSrc );
+ while( --nPixelCount >= 0 )
+ {
+ ImplConvertPixel( aDst, aSrc );
+ ++aSrc;
+ ++aDst;
+ }
+}
+
+// =======================================================================
+// alpha blending truecolor pixels
+
+template <unsigned ALPHABITS, ULONG SRCFMT, ULONG DSTFMT>
+inline void ImplBlendPixels( const TrueColorPixelPtr<DSTFMT>& rDst,
+ const TrueColorPixelPtr<SRCFMT>& rSrc, unsigned nAlphaVal )
+{
+ if( !nAlphaVal )
+ ImplConvertPixel( rDst, rSrc );
+ else if( nAlphaVal != ~(~0 << ALPHABITS) )
+ {
+ static const unsigned nAlphaShift = (ALPHABITS > 8) ? 8 : ALPHABITS;
+ if( ALPHABITS > nAlphaShift )
+ nAlphaVal >>= ALPHABITS - nAlphaShift;
+
+ int nR = rDst.GetRed();
+ int nS = rSrc.GetRed();
+ nR = nS + (((nR - nS) * nAlphaVal) >> nAlphaShift);
+
+ int nG = rDst.GetGreen();
+ nS = rSrc.GetGreen();
+ nG = nS + (((nG - nS) * nAlphaVal) >> nAlphaShift);
+
+ int nB = rDst.GetBlue();
+ nS = rSrc.GetBlue();
+ nB = nS + (((nB - nS) * nAlphaVal) >> nAlphaShift);
+
+ rDst.SetColor( sal::static_int_cast<PIXBYTE>(nR),
+ sal::static_int_cast<PIXBYTE>(nG),
+ sal::static_int_cast<PIXBYTE>(nB) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+template <unsigned ALPHABITS, ULONG MASKFMT, ULONG SRCFMT, ULONG DSTFMT>
+inline void ImplBlendLines( const TrueColorPixelPtr<DSTFMT>& rDst,
+ const TrueColorPixelPtr<SRCFMT>& rSrc, const TrueColorPixelPtr<MASKFMT>& rMsk,
+ int nPixelCount )
+{
+ TrueColorPixelPtr<MASKFMT> aMsk( rMsk );
+ TrueColorPixelPtr<DSTFMT> aDst( rDst );
+ TrueColorPixelPtr<SRCFMT> aSrc( rSrc );
+ while( --nPixelCount >= 0 )
+ {
+ ImplBlendPixels<ALPHABITS>( aDst, aSrc, aMsk.GetAlpha() );
+ ++aDst;
+ ++aSrc;
+ ++aMsk;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+template <unsigned ALPHABITS, ULONG SRCFMT, ULONG DSTFMT>
+inline void ImplBlendLines( const TrueColorPixelPtr<DSTFMT>& rDst,
+ const TrueColorPixelPtr<SRCFMT>& rSrc, unsigned nAlphaVal,
+ int nPixelCount )
+{
+ if( nAlphaVal == ~(~0 << ALPHABITS) )
+ ImplConvertLine( rDst, rSrc, nPixelCount );
+ else if( nAlphaVal )
+ {
+ TrueColorPixelPtr<SRCFMT> aSrc( rSrc );
+ TrueColorPixelPtr<DSTFMT> aDst( rDst );
+ while( --nPixelCount >= 0 )
+ {
+ ImplBlendPixels<ALPHABITS>( aDst, aSrc, nAlphaVal );
+ ++aDst;
+ ++aSrc;
+ }
+ }
+}
+
+// =======================================================================
+
+static bool ImplCopyImage( BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer )
+{
+ const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
+ int nDstLinestep = rDstBuffer.mnScanlineSize;
+
+ const PIXBYTE* pRawSrc = rSrcBuffer.mpBits;
+ PIXBYTE* pRawDst = rDstBuffer.mpBits;
+
+ // source and destination don't match upside down
+ if( BMP_FORMAT_TOP_DOWN & (rSrcBuffer.mnFormat ^ rDstBuffer.mnFormat) )
+ {
+ pRawDst += (rSrcBuffer.mnHeight - 1) * nDstLinestep;
+ nDstLinestep = -rDstBuffer.mnScanlineSize;
+ }
+ else if( nSrcLinestep == nDstLinestep )
+ {
+ memcpy( pRawDst, pRawSrc, rSrcBuffer.mnHeight * nDstLinestep );
+ return true;
+ }
+
+ int nByteWidth = nSrcLinestep;
+ if( nByteWidth > rDstBuffer.mnScanlineSize )
+ nByteWidth = rDstBuffer.mnScanlineSize;
+
+ for( int y = rSrcBuffer.mnHeight; --y >= 0; )
+ {
+ memcpy( pRawDst, pRawSrc, nByteWidth );
+ pRawSrc += nSrcLinestep;
+ pRawDst += nDstLinestep;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+template <ULONG DSTFMT,ULONG SRCFMT>
+bool ImplConvertToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
+ BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer )
+{
+ // help the compiler to avoid instantiations of unneeded conversions
+ DBG_ASSERT( SRCFMT != DSTFMT, "ImplConvertToBitmap into same format");
+ if( SRCFMT == DSTFMT )
+ return false;
+
+ const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
+ int nDstLinestep = rDstBuffer.mnScanlineSize;
+
+ TrueColorPixelPtr<DSTFMT> aDstLine; aDstLine.SetRawPtr( rDstBuffer.mpBits );
+
+ // source and destination don't match upside down
+ if( BMP_FORMAT_TOP_DOWN & (rSrcBuffer.mnFormat ^ rDstBuffer.mnFormat) )
+ {
+ aDstLine.AddByteOffset( (rSrcBuffer.mnHeight - 1) * nDstLinestep );
+ nDstLinestep = -nDstLinestep;
+ }
+
+ for( int y = rSrcBuffer.mnHeight; --y >= 0; )
+ {
+ ImplConvertLine( aDstLine, rSrcLine, rSrcBuffer.mnWidth );
+ rSrcLine.AddByteOffset( nSrcLinestep );
+ aDstLine.AddByteOffset( nDstLinestep );
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+template <ULONG SRCFMT>
+inline bool ImplConvertFromBitmap( BitmapBuffer& rDst, const BitmapBuffer& rSrc )
+{
+ TrueColorPixelPtr<SRCFMT> aSrcType; aSrcType.SetRawPtr( rSrc.mpBits );
+
+ // select the matching instantiation for the destination's bitmap format
+ switch( rDst.mnFormat & ~BMP_FORMAT_TOP_DOWN )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ case BMP_FORMAT_8BIT_PAL:
+ break;
+
+ case BMP_FORMAT_8BIT_TC_MASK:
+// return ImplConvertToBitmap<BMP_FORMAT_8BIT_TC_MASK>( aSrcType, rDst, rSrc );
+ case BMP_FORMAT_24BIT_TC_MASK:
+// return ImplConvertToBitmap<BMP_FORMAT_24BIT_TC_MASK>( aSrcType, rDst, rSrc );
+ case BMP_FORMAT_32BIT_TC_MASK:
+// return ImplConvertToBitmap<BMP_FORMAT_32BIT_TC_MASK>( aSrcType, rDst, rSrc );
+ break;
+
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ return ImplConvertToBitmap<BMP_FORMAT_16BIT_TC_MSB_MASK>( aSrcType, rDst, rSrc );
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ return ImplConvertToBitmap<BMP_FORMAT_16BIT_TC_LSB_MASK>( aSrcType, rDst, rSrc );
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ return ImplConvertToBitmap<BMP_FORMAT_24BIT_TC_BGR>( aSrcType, rDst, rSrc );
+ case BMP_FORMAT_24BIT_TC_RGB:
+ return ImplConvertToBitmap<BMP_FORMAT_24BIT_TC_RGB>( aSrcType, rDst, rSrc );
+
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ return ImplConvertToBitmap<BMP_FORMAT_32BIT_TC_ABGR>( aSrcType, rDst, rSrc );
+#ifdef FAST_ARGB_BGRA
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ return ImplConvertToBitmap<BMP_FORMAT_32BIT_TC_ARGB>( aSrcType, rDst, rSrc );
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ return ImplConvertToBitmap<BMP_FORMAT_32BIT_TC_BGRA>( aSrcType, rDst, rSrc );
+#endif
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ return ImplConvertToBitmap<BMP_FORMAT_32BIT_TC_RGBA>( aSrcType, rDst, rSrc );
+ }
+
+#ifdef DEBUG
+ static int nNotAccelerated = 0;
+ if( rSrc.mnWidth * rSrc.mnHeight >= 4000 )
+ if( ++nNotAccelerated == 100 )
+ {
+ int foo = 0; (void)foo; // so no warning is created when building on pro with debug
+ DBG_WARNING2( "ImplConvertFromBitmap for not accelerated case (0x%04X->0x%04X)",
+ rSrc.mnFormat, rDst.mnFormat );
+ }
+#endif
+
+ return false;
+}
+
+// =======================================================================
+
+// an universal stretching conversion is overkill in most common situations
+// => performance benefits for speeding up the non-stretching cases
+bool ImplFastBitmapConversion( BitmapBuffer& rDst, const BitmapBuffer& rSrc,
+ const SalTwoRect& rTR )
+{
+ if( bDisableFastBitops )
+ return false;
+
+ // horizontal mirroring not implemented yet
+ if( rTR.mnDestWidth < 0 )
+ return false;
+ // vertical mirroring
+ if( rTR.mnDestHeight < 0 )
+ // TODO: rDst.mnFormat ^= BMP_FORMAT_TOP_DOWN;
+ return false;
+
+ // offseted conversion is not implemented yet
+ if( rTR.mnSrcX || rTR.mnSrcY )
+ return false;
+ if( rTR.mnDestX || rTR.mnDestY )
+ return false;
+
+ // stretched conversion is not implemented yet
+ if( rTR.mnDestWidth != rTR.mnSrcWidth )
+ return false;
+ if( rTR.mnDestHeight!= rTR.mnSrcHeight )
+ return false;
+
+ // check source image size
+ if( rSrc.mnWidth < rTR.mnSrcX + rTR.mnSrcWidth )
+ return false;
+ if( rSrc.mnHeight < rTR.mnSrcY + rTR.mnSrcHeight )
+ return false;
+
+ // check dest image size
+ if( rDst.mnWidth < rTR.mnDestX + rTR.mnDestWidth )
+ return false;
+ if( rDst.mnHeight < rTR.mnDestY + rTR.mnDestHeight )
+ return false;
+
+ const ULONG nSrcFormat = rSrc.mnFormat & ~BMP_FORMAT_TOP_DOWN;
+ const ULONG nDstFormat = rDst.mnFormat & ~BMP_FORMAT_TOP_DOWN;
+
+ // TODO: also implement conversions for 16bit colormasks with non-565 format
+ if( nSrcFormat & (BMP_FORMAT_16BIT_TC_LSB_MASK | BMP_FORMAT_16BIT_TC_MSB_MASK) )
+ if( rSrc.maColorMask.GetRedMask() != 0xF800
+ || rSrc.maColorMask.GetGreenMask()!= 0x07E0
+ || rSrc.maColorMask.GetBlueMask() != 0x001F )
+ return false;
+ if( nDstFormat & (BMP_FORMAT_16BIT_TC_LSB_MASK | BMP_FORMAT_16BIT_TC_MSB_MASK) )
+ if( rDst.maColorMask.GetRedMask() != 0xF800
+ || rDst.maColorMask.GetGreenMask()!= 0x07E0
+ || rDst.maColorMask.GetBlueMask() != 0x001F )
+ return false;
+
+ // special handling of trivial cases
+ if( nSrcFormat == nDstFormat )
+ {
+ // accelerated palette conversions not yet implemented
+ if( rSrc.maPalette != rDst.maPalette )
+ return false;
+ return ImplCopyImage( rDst, rSrc );
+ }
+
+ // select the matching instantiation for the source's bitmap format
+ switch( nSrcFormat )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ case BMP_FORMAT_8BIT_PAL:
+ break;
+
+ case BMP_FORMAT_8BIT_TC_MASK:
+// return ImplConvertFromBitmap<BMP_FORMAT_8BIT_TC_MASK>( rDst, rSrc );
+ case BMP_FORMAT_24BIT_TC_MASK:
+// return ImplConvertFromBitmap<BMP_FORMAT_24BIT_TC_MASK>( rDst, rSrc );
+ case BMP_FORMAT_32BIT_TC_MASK:
+// return ImplConvertFromBitmap<BMP_FORMAT_32BIT_TC_MASK>( rDst, rSrc );
+ break;
+
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ return ImplConvertFromBitmap<BMP_FORMAT_16BIT_TC_MSB_MASK>( rDst, rSrc );
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ return ImplConvertFromBitmap<BMP_FORMAT_16BIT_TC_LSB_MASK>( rDst, rSrc );
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ return ImplConvertFromBitmap<BMP_FORMAT_24BIT_TC_BGR>( rDst, rSrc );
+ case BMP_FORMAT_24BIT_TC_RGB:
+ return ImplConvertFromBitmap<BMP_FORMAT_24BIT_TC_RGB>( rDst, rSrc );
+
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ return ImplConvertFromBitmap<BMP_FORMAT_32BIT_TC_ABGR>( rDst, rSrc );
+#ifdef FAST_ARGB_BGRA
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ return ImplConvertFromBitmap<BMP_FORMAT_32BIT_TC_ARGB>( rDst, rSrc );
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ return ImplConvertFromBitmap<BMP_FORMAT_32BIT_TC_BGRA>( rDst, rSrc );
+#endif
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ return ImplConvertFromBitmap<BMP_FORMAT_32BIT_TC_RGBA>( rDst, rSrc );
+ }
+
+#ifdef DEBUG
+ static int nNotAccelerated = 0;
+ if( rSrc.mnWidth * rSrc.mnHeight >= 4000 )
+ {
+ if( ++nNotAccelerated == 100 )
+ {
+ int foo = 0; (void)foo; // so no warning is created when building on pro with debug
+ DBG_WARNING2( "ImplFastBitmapConversion for not accelerated case (0x%04X->0x%04X)", rSrc.mnFormat, rDst.mnFormat );
+ }
+ }
+#endif
+
+ return false;
+}
+
+// =======================================================================
+
+template <ULONG DSTFMT,ULONG SRCFMT> //,ULONG MSKFMT>
+bool ImplBlendToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
+ BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
+ const BitmapBuffer& rMskBuffer )
+{
+ //DBG_ASSERT( rMskBuffer.mnFormat == MSKFMT, "FastBmp BlendImage: wrong MSKFMT" );
+ DBG_ASSERT( rMskBuffer.mnFormat == BMP_FORMAT_8BIT_PAL, "FastBmp BlendImage: unusual MSKFMT" );
+
+ const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
+ int nMskLinestep = rMskBuffer.mnScanlineSize;
+ int nDstLinestep = rDstBuffer.mnScanlineSize;
+
+ TrueColorPixelPtr<BMP_FORMAT_8BIT_PAL> aMskLine; aMskLine.SetRawPtr( rMskBuffer.mpBits );
+ TrueColorPixelPtr<DSTFMT> aDstLine; aDstLine.SetRawPtr( rDstBuffer.mpBits );
+
+ // special case for single line masks
+ if( rMskBuffer.mnHeight == 1 )
+ nMskLinestep = 0;
+
+ // source and mask don't match: upside down
+ if( (rSrcBuffer.mnFormat ^ rMskBuffer.mnFormat) & BMP_FORMAT_TOP_DOWN )
+ {
+ aMskLine.AddByteOffset( (rSrcBuffer.mnHeight - 1) * nMskLinestep );
+ nMskLinestep = -nMskLinestep;
+ }
+
+ // source and destination don't match: upside down
+ if( (rSrcBuffer.mnFormat ^ rDstBuffer.mnFormat) & BMP_FORMAT_TOP_DOWN )
+ {
+ aDstLine.AddByteOffset( (rSrcBuffer.mnHeight - 1) * nDstLinestep );
+ nDstLinestep = -nDstLinestep;
+ }
+
+ for( int y = rSrcBuffer.mnHeight; --y >= 0; )
+ {
+ ImplBlendLines<8>( aDstLine, rSrcLine, aMskLine, rDstBuffer.mnWidth );
+ aDstLine.AddByteOffset( nDstLinestep );
+ rSrcLine.AddByteOffset( nSrcLinestep );
+ aMskLine.AddByteOffset( nMskLinestep );
+ }
+
+ return true;
+}
+
+// some specializations to reduce the code size
+template <>
+inline bool ImplBlendToBitmap<BMP_FORMAT_24BIT_TC_BGR,BMP_FORMAT_24BIT_TC_BGR>(
+ TrueColorPixelPtr<BMP_FORMAT_24BIT_TC_BGR>&,
+ BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
+ const BitmapBuffer& rMskBuffer )
+ {
+ TrueColorPixelPtr<BMP_FORMAT_24BIT_TC_RGB> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
+ return ImplBlendToBitmap<BMP_FORMAT_24BIT_TC_RGB>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
+ }
+
+template <>
+inline bool ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_ABGR,BMP_FORMAT_32BIT_TC_ABGR>(
+ TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_ABGR>&,
+ BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
+ const BitmapBuffer& rMskBuffer )
+ {
+ TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_ARGB> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
+ return ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_ARGB>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
+ }
+
+template <>
+inline bool ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_BGRA,BMP_FORMAT_32BIT_TC_BGRA>(
+ TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_BGRA>&,
+ BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
+ const BitmapBuffer& rMskBuffer )
+ {
+ TrueColorPixelPtr<BMP_FORMAT_32BIT_TC_RGBA> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
+ return ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_RGBA>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
+ }
+
+// -----------------------------------------------------------------------
+
+template <ULONG SRCFMT>
+bool ImplBlendFromBitmap( BitmapBuffer& rDst, const BitmapBuffer& rSrc, const BitmapBuffer& rMsk )
+{
+ TrueColorPixelPtr<SRCFMT> aSrcType; aSrcType.SetRawPtr( rSrc.mpBits );
+
+ // select the matching instantiation for the destination's bitmap format
+ switch( rDst.mnFormat & ~BMP_FORMAT_TOP_DOWN )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ case BMP_FORMAT_8BIT_PAL:
+ break;
+
+ case BMP_FORMAT_8BIT_TC_MASK:
+// return ImplBlendToBitmap<BMP_FORMAT_8BIT_TC_MASK>( aSrcType, rDst, rSrc, rMsk );
+ case BMP_FORMAT_24BIT_TC_MASK:
+// return ImplBlendToBitmap<BMP_FORMAT_24BIT_TC_MASK>( aSrcType, rDst, rSrc, rMsk );
+ case BMP_FORMAT_32BIT_TC_MASK:
+// return ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_MASK>( aSrcType, rDst, rSrc, rMsk );
+ break;
+
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ return ImplBlendToBitmap<BMP_FORMAT_16BIT_TC_MSB_MASK>( aSrcType, rDst, rSrc, rMsk );
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ return ImplBlendToBitmap<BMP_FORMAT_16BIT_TC_LSB_MASK>( aSrcType, rDst, rSrc, rMsk );
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ return ImplBlendToBitmap<BMP_FORMAT_24BIT_TC_BGR>( aSrcType, rDst, rSrc, rMsk );
+ case BMP_FORMAT_24BIT_TC_RGB:
+ return ImplBlendToBitmap<BMP_FORMAT_24BIT_TC_RGB>( aSrcType, rDst, rSrc, rMsk );
+
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ return ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_ABGR>( aSrcType, rDst, rSrc, rMsk );
+#ifdef FAST_ARGB_BGRA
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ return ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_ARGB>( aSrcType, rDst, rSrc, rMsk );
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ return ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_BGRA>( aSrcType, rDst, rSrc, rMsk );
+#endif
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ return ImplBlendToBitmap<BMP_FORMAT_32BIT_TC_RGBA>( aSrcType, rDst, rSrc, rMsk );
+ }
+
+#ifdef DEBUG
+ static int nNotAccelerated = 0;
+ if( rSrc.mnWidth * rSrc.mnHeight >= 4000 )
+ if( ++nNotAccelerated == 100 )
+ {
+ int foo = 0; (void)foo; // so no warning is created when building on pro with debug
+ DBG_WARNING3( "ImplBlendFromBitmap for not accelerated case (0x%04X*0x%04X->0x%04X)",
+ rSrc.mnFormat, rMsk.mnFormat, rDst.mnFormat );
+ }
+#endif
+
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplFastBitmapBlending( BitmapWriteAccess& rDstWA,
+ const BitmapReadAccess& rSrcRA, const BitmapReadAccess& rMskRA,
+ const SalTwoRect& rTR )
+{
+ if( bDisableFastBitops )
+ return false;
+
+ // accelerated blending of paletted bitmaps not implemented yet
+ if( rSrcRA.HasPalette() )
+ return false;
+ if( rDstWA.HasPalette() )
+ return false;
+ // TODO: either get rid of mask's use of 8BIT_PAL or check the palette
+
+ // horizontal mirroring not implemented yet
+ if( rTR.mnDestWidth < 0 )
+ return false;
+ // vertical mirroring
+ if( rTR.mnDestHeight < 0 )
+ // TODO: rDst.mnFormat ^= BMP_FORMAT_TOP_DOWN;
+ return false;
+
+ // offseted blending is not implemented yet
+ if( rTR.mnSrcX || rTR.mnSrcY )
+ return false;
+ if( rTR.mnDestX || rTR.mnDestY )
+ return false;
+
+ // stretched blending is not implemented yet
+ if( rTR.mnDestWidth != rTR.mnSrcWidth )
+ return false;
+ if( rTR.mnDestHeight!= rTR.mnSrcHeight )
+ return false;
+
+ // check source image size
+ if( rSrcRA.Width() < rTR.mnSrcX + rTR.mnSrcWidth )
+ return false;
+ if( rSrcRA.Height() < rTR.mnSrcY + rTR.mnSrcHeight )
+ return false;
+
+ // check mask image size
+ if( rMskRA.Width() < rTR.mnSrcX + rTR.mnSrcWidth )
+ return false;
+ if( rMskRA.Height() < rTR.mnSrcY + rTR.mnSrcHeight )
+ if( rMskRA.Height() != 1 )
+ return false;
+
+ // check dest image size
+ if( rDstWA.Width() < rTR.mnDestX + rTR.mnDestWidth )
+ return false;
+ if( rDstWA.Height() < rTR.mnDestY + rTR.mnDestHeight )
+ return false;
+
+ BitmapBuffer& rDst = *rDstWA.ImplGetBitmapBuffer();
+ const BitmapBuffer& rSrc = *rSrcRA.ImplGetBitmapBuffer();
+ const BitmapBuffer& rMsk = *rMskRA.ImplGetBitmapBuffer();
+
+ const ULONG nSrcFormat = rSrc.mnFormat & ~BMP_FORMAT_TOP_DOWN;
+ const ULONG nDstFormat = rDst.mnFormat & ~BMP_FORMAT_TOP_DOWN;
+
+ // accelerated conversions for 16bit colormasks with non-565 format are not yet implemented
+ if( nSrcFormat & (BMP_FORMAT_16BIT_TC_LSB_MASK | BMP_FORMAT_16BIT_TC_MSB_MASK) )
+ if( rSrc.maColorMask.GetRedMask() != 0xF800
+ || rSrc.maColorMask.GetGreenMask()!= 0x07E0
+ || rSrc.maColorMask.GetBlueMask() != 0x001F)
+ return false;
+ if( nDstFormat & (BMP_FORMAT_16BIT_TC_LSB_MASK | BMP_FORMAT_16BIT_TC_MSB_MASK) )
+ if( rDst.maColorMask.GetRedMask() != 0xF800
+ || rDst.maColorMask.GetGreenMask()!= 0x07E0
+ || rDst.maColorMask.GetBlueMask() != 0x001F)
+ return false;
+
+ // select the matching instantiation for the source's bitmap format
+ switch( nSrcFormat )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ case BMP_FORMAT_8BIT_PAL:
+ break;
+
+ case BMP_FORMAT_8BIT_TC_MASK:
+// return ImplBlendFromBitmap<BMP_FORMAT_8BIT_TC_MASK>( rDst, rSrc );
+ case BMP_FORMAT_24BIT_TC_MASK:
+// return ImplBlendFromBitmap<BMP_FORMAT_24BIT_TC_MASK>( rDst, rSrc );
+ case BMP_FORMAT_32BIT_TC_MASK:
+// return ImplBlendFromBitmap<BMP_FORMAT_32BIT_TC_MASK>( rDst, rSrc );
+ break;
+
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ return ImplBlendFromBitmap<BMP_FORMAT_16BIT_TC_MSB_MASK>( rDst, rSrc, rMsk );
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ return ImplBlendFromBitmap<BMP_FORMAT_16BIT_TC_LSB_MASK>( rDst, rSrc, rMsk );
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ return ImplBlendFromBitmap<BMP_FORMAT_24BIT_TC_BGR>( rDst, rSrc, rMsk );
+ case BMP_FORMAT_24BIT_TC_RGB:
+ return ImplBlendFromBitmap<BMP_FORMAT_24BIT_TC_RGB>( rDst, rSrc, rMsk );
+
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ return ImplBlendFromBitmap<BMP_FORMAT_32BIT_TC_ABGR>( rDst, rSrc, rMsk );
+#ifdef FAST_ARGB_BGRA
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ return ImplBlendFromBitmap<BMP_FORMAT_32BIT_TC_ARGB>( rDst, rSrc, rMsk );
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ return ImplBlendFromBitmap<BMP_FORMAT_32BIT_TC_BGRA>( rDst, rSrc, rMsk );
+#endif
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ return ImplBlendFromBitmap<BMP_FORMAT_32BIT_TC_RGBA>( rDst, rSrc, rMsk );
+ }
+
+#ifdef DEBUG
+ static int nNotAccelerated = 0;
+ if( rSrc.mnWidth * rSrc.mnHeight >= 4000 )
+ if( ++nNotAccelerated == 100 )
+ {
+ int foo = 0; (void)foo; // so no warning is created when building on pro with debug
+ DBG_WARNING3( "ImplFastBlend for not accelerated case (0x%04X*0x%04X->0x%04X)",
+ rSrc.mnFormat, rMsk.mnFormat, rDst.mnFormat );
+ }
+#endif
+
+ return false;
+}
+
+bool ImplFastEraseBitmap( BitmapBuffer& rDst, const BitmapColor& rColor )
+{
+ if( bDisableFastBitops )
+ return false;
+
+ const ULONG nDstFormat = rDst.mnFormat & ~BMP_FORMAT_TOP_DOWN;
+
+ // erasing a bitmap is often just a byte-wise memory fill
+ bool bByteFill = true;
+ BYTE nFillByte;
+
+ switch( nDstFormat )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ nFillByte = rColor.GetIndex();
+ nFillByte = static_cast<BYTE>( -(nFillByte & 1) ); // 0x00 or 0xFF
+ break;
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ nFillByte = rColor.GetIndex();
+ nFillByte &= 0x0F;
+ nFillByte |= (nFillByte << 4);
+ break;
+ case BMP_FORMAT_8BIT_PAL:
+ case BMP_FORMAT_8BIT_TC_MASK:
+ nFillByte = rColor.GetIndex();
+ break;
+
+ case BMP_FORMAT_24BIT_TC_MASK:
+ case BMP_FORMAT_24BIT_TC_BGR:
+ case BMP_FORMAT_24BIT_TC_RGB:
+ nFillByte = rColor.GetRed();
+ if( (nFillByte != rColor.GetGreen())
+ || (nFillByte != rColor.GetBlue()) )
+ bByteFill = false;
+ break;
+
+ default:
+ bByteFill = false;
+ nFillByte = 0x00;
+ break;
+ }
+
+ if( bByteFill )
+ {
+ long nByteCount = rDst.mnHeight * rDst.mnScanlineSize;
+ rtl_fillMemory( rDst.mpBits, nByteCount, nFillByte );
+ return true;
+ }
+
+ // TODO: handle other bitmap formats
+ switch( nDstFormat )
+ {
+ case BMP_FORMAT_32BIT_TC_MASK:
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ case BMP_FORMAT_24BIT_TC_RGB:
+
+ case BMP_FORMAT_32BIT_TC_ABGR:
+#ifdef FAST_ARGB_BGRA
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ case BMP_FORMAT_32BIT_TC_BGRA:
+#endif
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+// =======================================================================
+
+#else // NO_OPTIMIZED_BITMAP_ACCESS
+
+bool ImplFastBitmapConversion( BitmapBuffer&, const BitmapBuffer& )
+{
+ return false;
+}
+
+bool ImplFastBitmapBlending( BitmapWriteAccess&,
+ const BitmapReadAccess&, const BitmapReadAccess&,
+ const Size&, const Point& )
+{
+ return false;
+}
+
+bool ImplFastEraseBitmap( BitmapBuffer&, const BitmapColor& )
+{
+ return false;
+}
+
+#endif
diff --git a/vcl/source/gdi/configsettings.cxx b/vcl/source/gdi/configsettings.cxx
new file mode 100644
index 000000000000..b11b9ab822f4
--- /dev/null
+++ b/vcl/source/gdi/configsettings.cxx
@@ -0,0 +1,205 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/configsettings.hxx>
+#include <vcl/svdata.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+using namespace rtl;
+using namespace utl;
+using namespace vcl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+#define SETTINGS_CONFIGNODE "VCL/Settings"
+
+/*
+ * SettingsConfigItem::get
+ */
+
+SettingsConfigItem* SettingsConfigItem::get()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->mpSettingsConfigItem )
+ pSVData->mpSettingsConfigItem = new SettingsConfigItem();
+ return pSVData->mpSettingsConfigItem;
+}
+
+/*
+ * SettignsConfigItem constructor
+ */
+
+SettingsConfigItem::SettingsConfigItem()
+ :
+ ConfigItem( OUString( RTL_CONSTASCII_USTRINGPARAM( SETTINGS_CONFIGNODE ) ),
+ CONFIG_MODE_DELAYED_UPDATE ),
+ m_aSettings( 0 )
+{
+ getValues();
+}
+
+/*
+ * SettingsConfigItem destructor
+ */
+
+SettingsConfigItem::~SettingsConfigItem()
+{
+ if( IsModified() )
+ Commit();
+}
+
+/*
+ * SettingsConfigItem::Commit
+ */
+
+void SettingsConfigItem::Commit()
+{
+ if( ! IsValidConfigMgr() )
+ return;
+
+ std::hash_map< OUString, SmallOUStrMap, rtl::OUStringHash >::const_iterator group;
+
+ for( group = m_aSettings.begin(); group != m_aSettings.end(); ++group )
+ {
+ String aKeyName( group->first );
+ /*sal_Bool bAdded =*/ AddNode( OUString(), aKeyName );
+ Sequence< PropertyValue > aValues( group->second.size() );
+ PropertyValue* pValues = aValues.getArray();
+ int nIndex = 0;
+ SmallOUStrMap::const_iterator it;
+ for( it = group->second.begin(); it != group->second.end(); ++it )
+ {
+ String aName( aKeyName );
+ aName.Append( '/' );
+ aName.Append( String( it->first ) );
+ pValues[nIndex].Name = aName;
+ pValues[nIndex].Handle = 0;
+ pValues[nIndex].Value <<= it->second;
+ pValues[nIndex].State = PropertyState_DIRECT_VALUE;
+ nIndex++;
+ }
+ ReplaceSetProperties( aKeyName, aValues );
+ }
+}
+
+/*
+ * SettingsConfigItem::Notify
+ */
+
+void SettingsConfigItem::Notify( const Sequence< OUString >& )
+{
+ getValues();
+}
+
+/*
+ * SettingsConfigItem::getValues
+ */
+void SettingsConfigItem::getValues()
+{
+ if( ! IsValidConfigMgr() )
+ return;
+
+ m_aSettings.clear();
+
+ Sequence< OUString > aNames( GetNodeNames( OUString() ) );
+ m_aSettings.resize( aNames.getLength() );
+
+ for( int j = 0; j < aNames.getLength(); j++ )
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "found settings data for \"%s\"\n",
+ OUStringToOString( aNames.getConstArray()[j], RTL_TEXTENCODING_ASCII_US ).getStr()
+ );
+#endif
+ String aKeyName( aNames.getConstArray()[j] );
+ Sequence< OUString > aKeys( GetNodeNames( aKeyName ) );
+ Sequence< OUString > aSettingsKeys( aKeys.getLength() );
+ const OUString* pFrom = aKeys.getConstArray();
+ OUString* pTo = aSettingsKeys.getArray();
+ for( int m = 0; m < aKeys.getLength(); m++ )
+ {
+ String aName( aKeyName );
+ aName.Append( '/' );
+ aName.Append( String( pFrom[m] ) );
+ pTo[m] = aName;
+ }
+ Sequence< Any > aValues( GetProperties( aSettingsKeys ) );
+ const Any* pValue = aValues.getConstArray();
+ for( int i = 0; i < aValues.getLength(); i++, pValue++ )
+ {
+ if( pValue->getValueTypeClass() == TypeClass_STRING )
+ {
+ const OUString* pLine = (const OUString*)pValue->getValue();
+ if( pLine->getLength() )
+ m_aSettings[ aKeyName ][ pFrom[i] ] = *pLine;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, " \"%s\"=\"%.30s\"\n",
+ OUStringToOString( aKeys.getConstArray()[i], RTL_TEXTENCODING_ASCII_US ).getStr(),
+ OUStringToOString( *pLine, RTL_TEXTENCODING_ASCII_US ).getStr()
+ );
+#endif
+ }
+ }
+ }
+}
+
+/*
+ * SettingsConfigItem::getDefaultFont
+ */
+
+const OUString& SettingsConfigItem::getValue( const OUString& rGroup, const OUString& rKey ) const
+{
+ ::std::hash_map< OUString, SmallOUStrMap, rtl::OUStringHash >::const_iterator group = m_aSettings.find( rGroup );
+ if( group == m_aSettings.end() || group->second.find( rKey ) == group->second.end() )
+ {
+ static OUString aEmpty;
+ return aEmpty;
+ }
+ return group->second.find(rKey)->second;
+}
+
+/*
+ * SettingsConfigItem::setDefaultFont
+ */
+
+void SettingsConfigItem::setValue( const OUString& rGroup, const OUString& rKey, const OUString& rValue )
+{
+ bool bModified = m_aSettings[ rGroup ][ rKey ] != rValue;
+ if( bModified )
+ {
+ m_aSettings[ rGroup ][ rKey ] = rValue;
+ SetModified();
+ }
+}
+
diff --git a/vcl/source/gdi/cvtgrf.cxx b/vcl/source/gdi/cvtgrf.cxx
new file mode 100644
index 000000000000..8ba963bc4718
--- /dev/null
+++ b/vcl/source/gdi/cvtgrf.cxx
@@ -0,0 +1,175 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/metaact.hxx>
+#include <vcl/salinst.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/cvtgrf.hxx>
+
+// --------------
+// - Callback -
+// --------------
+
+// --------------------
+// - GraphicConverter -
+// --------------------
+
+GraphicConverter::GraphicConverter() :
+ mpConvertData( NULL )
+{
+}
+
+// ------------------------------------------------------------------------
+
+GraphicConverter::~GraphicConverter()
+{
+}
+
+// ------------------------------------------------------------------------
+
+ULONG GraphicConverter::ImplConvert( ULONG nInFormat, void* pInBuffer, ULONG nInBufSize,
+ void** ppOutBuffer, ULONG nOutFormat )
+{
+ ULONG nRetBufSize = 0UL;
+
+ if( ( nInFormat != nOutFormat ) && pInBuffer )
+ {
+ if( ( nInFormat == CVT_SVM ) || ( nInFormat == CVT_BMP ) )
+ {
+ SvMemoryStream aIStm;
+ Graphic aGraphic;
+
+ aIStm.SetBuffer( (char*) pInBuffer, nInBufSize, FALSE, nInBufSize );
+ aIStm >> aGraphic;
+
+ if( !aIStm.GetError() )
+ {
+ SvMemoryStream aOStm( 64535, 64535 );
+
+ mpConvertData = new ConvertData( aGraphic, aOStm, nOutFormat );
+
+ if( maFilterHdl.IsSet() && maFilterHdl.Call( mpConvertData ) )
+ {
+ nRetBufSize = aOStm.Seek( STREAM_SEEK_TO_END );
+ *ppOutBuffer = (void*) aOStm.GetData();
+ aOStm.ObjectOwnsMemory( FALSE );
+ }
+
+ delete mpConvertData;
+ mpConvertData = NULL;
+ }
+ }
+ else if( ( nOutFormat == CVT_SVM ) || ( nOutFormat == CVT_BMP ) )
+ {
+ SvMemoryStream aIStm;
+
+ aIStm.SetBuffer( (char*) pInBuffer, nInBufSize, FALSE, nInBufSize );
+ mpConvertData = new ConvertData( Graphic(), aIStm, nInFormat );
+
+ if( maFilterHdl.IsSet() && maFilterHdl.Call( mpConvertData ) )
+ {
+ SvMemoryStream aOStm( 645535, 64535 );
+ Graphic& rGraphic = mpConvertData->maGraphic;
+
+ if( ( rGraphic.GetType() == GRAPHIC_BITMAP ) && ( CVT_SVM == nOutFormat ) )
+ {
+ GDIMetaFile aMtf;
+
+ aMtf.SetPrefSize( rGraphic.GetPrefSize() );
+ aMtf.SetPrefMapMode( rGraphic.GetPrefMapMode() );
+ aMtf.AddAction( new MetaBmpExScaleAction( Point(), aMtf.GetPrefSize(), rGraphic.GetBitmapEx() ) );
+ rGraphic = aMtf;
+ }
+ else if( ( rGraphic.GetType() == GRAPHIC_GDIMETAFILE ) && ( CVT_BMP == nOutFormat ) )
+ rGraphic = rGraphic.GetBitmapEx();
+
+ aOStm << rGraphic;
+
+ if( !aOStm.GetError() )
+ {
+ nRetBufSize = aOStm.Seek( STREAM_SEEK_TO_END );
+ *ppOutBuffer = (void*) aOStm.GetData();
+ aOStm.ObjectOwnsMemory( FALSE );
+ }
+ }
+
+ delete mpConvertData;
+ mpConvertData = NULL;
+ }
+ }
+
+ return nRetBufSize;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG GraphicConverter::Import( SvStream& rIStm, Graphic& rGraphic, ULONG nFormat )
+{
+ GraphicConverter* pCvt = ImplGetSVData()->maGDIData.mpGrfConverter;
+ ULONG nRet = ERRCODE_IO_GENERAL;
+
+ if( pCvt && pCvt->GetFilterHdl().IsSet() )
+ {
+ ConvertData aData( rGraphic, rIStm, nFormat );
+
+ if( pCvt->GetFilterHdl().Call( &aData ) )
+ {
+ rGraphic = aData.maGraphic;
+ nRet = ERRCODE_NONE;
+ }
+ else if( rIStm.GetError() )
+ nRet = rIStm.GetError();
+ }
+
+ return nRet;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG GraphicConverter::Export( SvStream& rOStm, const Graphic& rGraphic, ULONG nFormat )
+{
+ GraphicConverter* pCvt = ImplGetSVData()->maGDIData.mpGrfConverter;
+ ULONG nRet = ERRCODE_IO_GENERAL;
+
+ if( pCvt && pCvt->GetFilterHdl().IsSet() )
+ {
+ ConvertData aData( rGraphic, rOStm, nFormat );
+
+ if( pCvt->GetFilterHdl().Call( &aData ) )
+ nRet = ERRCODE_NONE;
+ else if( rOStm.GetError() )
+ nRet = rOStm.GetError();
+ }
+
+ return nRet;
+}
diff --git a/vcl/source/gdi/cvtsvm.cxx b/vcl/source/gdi/cvtsvm.cxx
new file mode 100644
index 000000000000..af98e402f158
--- /dev/null
+++ b/vcl/source/gdi/cvtsvm.cxx
@@ -0,0 +1,2516 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define ENABLE_BYTESTRING_STREAM_OPERATORS
+
+#include <algorithm>
+#include <string.h>
+#include <tools/stack.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/cvtsvm.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define CVTSVM_WRITE_SUBACTIONCOUNT 1
+
+// -----------
+// - Inlines -
+// -----------
+
+void ImplReadRect( SvStream& rIStm, Rectangle& rRect )
+{
+ Point aTL;
+ Point aBR;
+
+ rIStm >> aTL;
+ rIStm >> aBR;
+
+ rRect = Rectangle( aTL, aBR );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWriteRect( SvStream& rOStm, const Rectangle& rRect )
+{
+ rOStm << rRect.TopLeft();
+ rOStm << rRect.BottomRight();
+}
+
+// ------------------------------------------------------------------------
+
+void ImplReadPoly( SvStream& rIStm, Polygon& rPoly )
+{
+ INT32 nSize;
+
+ rIStm >> nSize;
+ rPoly = Polygon( (USHORT) nSize );
+
+ for( USHORT i = 0; i < (USHORT) nSize; i++ )
+ rIStm >> rPoly[ i ];
+}
+
+// ------------------------------------------------------------------------
+
+void ImplReadPolyPoly( SvStream& rIStm, PolyPolygon& rPolyPoly )
+{
+ Polygon aPoly;
+ INT32 nPolyCount;
+
+ rIStm >> nPolyCount;
+
+ for( USHORT i = 0; i < (USHORT) nPolyCount; i++ )
+ {
+ ImplReadPoly( rIStm, aPoly );
+ rPolyPoly.Insert( aPoly );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWritePolyPolyAction( SvStream& rOStm, const PolyPolygon& rPolyPoly )
+{
+ const USHORT nPoly = rPolyPoly.Count();
+ USHORT nPoints = 0;
+ USHORT n;
+
+ for( n = 0; n < nPoly; n++ )
+ nPoints = sal::static_int_cast<USHORT>(nPoints + rPolyPoly[ n ].GetSize());
+
+ rOStm << (INT16) GDI_POLYPOLYGON_ACTION;
+ rOStm << (INT32) ( 8 + ( nPoly << 2 ) + ( nPoints << 3 ) );
+ rOStm << (INT32) nPoly;
+
+ for( n = 0; n < nPoly; n++ )
+ {
+ // #i102224# Here the evtl. curved nature of Polygon was
+ // ignored (for all those Years). Adapted to at least write
+ // a polygon representing the curve as good as possible
+ Polygon aSimplePoly;
+ rPolyPoly[n].AdaptiveSubdivide(aSimplePoly);
+ const USHORT nSize(aSimplePoly.GetSize());
+
+ rOStm << (INT32) nSize;
+
+ for( USHORT j = 0; j < nSize; j++ )
+ rOStm << aSimplePoly[ j ];
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImplReadColor( SvStream& rIStm, Color& rColor )
+{
+ INT16 nVal;
+
+ rIStm >> nVal; rColor.SetRed( sal::static_int_cast<UINT8>((USHORT)nVal >> 8) );
+ rIStm >> nVal; rColor.SetGreen( sal::static_int_cast<UINT8>((USHORT)nVal >> 8) );
+ rIStm >> nVal; rColor.SetBlue( sal::static_int_cast<UINT8>((USHORT)nVal >> 8) );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWriteColor( SvStream& rOStm, const Color& rColor )
+{
+ INT16 nVal;
+
+ nVal = ( (INT16) rColor.GetRed() << 8 ) | rColor.GetRed();
+ rOStm << nVal;
+
+ nVal = ( (INT16) rColor.GetGreen() << 8 ) | rColor.GetGreen();
+ rOStm << nVal;
+
+ nVal = ( (INT16) rColor.GetBlue() << 8 ) | rColor.GetBlue();
+ rOStm << nVal;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplReadMapMode( SvStream& rIStm, MapMode& rMapMode )
+{
+ Point aOrg;
+ INT32 nXNum;
+ INT32 nXDenom;
+ INT32 nYNum;
+ INT32 nYDenom;
+ INT16 nUnit;
+
+ rIStm >> nUnit >> aOrg >> nXNum >> nXDenom >> nYNum >> nYDenom;
+ rMapMode = MapMode( (MapUnit) nUnit, aOrg, Fraction( nXNum, nXDenom ), Fraction( nYNum, nYDenom ) );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWriteMapMode( SvStream& rOStm, const MapMode& rMapMode )
+{
+ rOStm << (INT16) rMapMode.GetMapUnit();
+ rOStm << rMapMode.GetOrigin();
+ rOStm << (INT32) rMapMode.GetScaleX().GetNumerator();
+ rOStm << (INT32) rMapMode.GetScaleX().GetDenominator();
+ rOStm << (INT32) rMapMode.GetScaleY().GetNumerator();
+ rOStm << (INT32) rMapMode.GetScaleY().GetDenominator();
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWritePushAction( SvStream& rOStm )
+{
+ rOStm << (INT16) GDI_PUSH_ACTION;
+ rOStm << (INT32) 4;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWritePopAction( SvStream& rOStm )
+{
+ rOStm << (INT16) GDI_POP_ACTION;
+ rOStm << (INT32) 4;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWriteLineColor( SvStream& rOStm, const Color& rColor, INT16 nStyle, INT32 nWidth = 0L )
+{
+ if( rColor.GetTransparency() > 127 )
+ nStyle = 0;
+
+ rOStm << (INT16) GDI_PEN_ACTION;
+ rOStm << (INT32) 16;
+ ImplWriteColor( rOStm, rColor );
+ rOStm << nWidth;
+ rOStm << nStyle;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWriteFillColor( SvStream& rOStm, const Color& rColor, INT16 nStyle )
+{
+ rOStm << (INT16) GDI_FILLBRUSH_ACTION;
+ rOStm << (INT32) 20;
+ ImplWriteColor( rOStm, rColor );
+
+ if( rColor.GetTransparency() > 127 )
+ nStyle = 0;
+
+ if( nStyle > 1 )
+ {
+ ImplWriteColor( rOStm, COL_WHITE );
+ rOStm << nStyle;
+ rOStm << (INT16) 1;
+ }
+ else
+ {
+ ImplWriteColor( rOStm, COL_BLACK );
+ rOStm << nStyle;
+ rOStm << (INT16) 0;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWriteFont( SvStream& rOStm, const Font& rFont,
+ rtl_TextEncoding& rActualCharSet )
+{
+ char aName[32];
+ short nWeight;
+
+ ByteString aByteName( rFont.GetName(), rOStm.GetStreamCharSet() );
+ strncpy( aName, aByteName.GetBuffer(), 32 );
+
+ switch ( rFont.GetWeight() )
+ {
+ case WEIGHT_THIN:
+ case WEIGHT_ULTRALIGHT:
+ case WEIGHT_LIGHT:
+ nWeight = 1;
+ break;
+
+ case WEIGHT_NORMAL:
+ case WEIGHT_MEDIUM:
+ nWeight = 2;
+ break;
+
+ case WEIGHT_BOLD:
+ case WEIGHT_ULTRABOLD:
+ case WEIGHT_BLACK:
+ nWeight = 3;
+ break;
+
+ default:
+ nWeight = 0;
+ break;
+ }
+
+ rOStm << (INT16) GDI_FONT_ACTION;
+ rOStm << (INT32) 78;
+
+ rActualCharSet = GetStoreCharSet( rFont.GetCharSet() );
+ ImplWriteColor( rOStm, rFont.GetColor() );
+ ImplWriteColor( rOStm, rFont.GetFillColor() );
+ rOStm.Write( aName, 32 );
+ rOStm << rFont.GetSize();
+ rOStm << (INT16) 0; // no character orientation anymore
+ rOStm << (INT16) rFont.GetOrientation();
+ rOStm << (INT16) rActualCharSet;
+ rOStm << (INT16) rFont.GetFamily();
+ rOStm << (INT16) rFont.GetPitch();
+ rOStm << (INT16) rFont.GetAlign();
+ rOStm << (INT16) nWeight;
+ rOStm << (INT16) rFont.GetUnderline();
+ rOStm << (INT16) rFont.GetStrikeout();
+ rOStm << (BOOL) ( rFont.GetItalic() != ITALIC_NONE );
+ rOStm << rFont.IsOutline();
+ rOStm << rFont.IsShadow();
+ rOStm << rFont.IsTransparent();
+ if ( rActualCharSet == RTL_TEXTENCODING_DONTKNOW )
+ rActualCharSet = gsl_getSystemTextEncoding();
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWriteRasterOpAction( SvStream& rOStm, INT16 nRasterOp )
+{
+ rOStm << (INT16) GDI_RASTEROP_ACTION << (INT32) 6 << nRasterOp;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool ImplWriteUnicodeComment( SvStream& rOStm, const String& rString )
+{
+ xub_StrLen i, nStringLen = rString.Len();
+ if ( nStringLen )
+ {
+ sal_uInt32 nSize = ( nStringLen << 1 ) + 4;
+ sal_uInt16 nType = GDI_UNICODE_COMMENT;
+
+ rOStm << nType << nSize;
+ for ( i = 0; i < nStringLen; i++ )
+ {
+ sal_Unicode nUni = rString.GetChar( i );
+ rOStm << nUni;
+ }
+ }
+ return nStringLen != 0;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplReadUnicodeComment( sal_uInt32 nStrmPos, SvStream& rIStm, String& rString )
+{
+ sal_uInt32 nOld = rIStm.Tell();
+ if ( nStrmPos )
+ {
+ sal_uInt16 nType;
+ sal_uInt32 nActionSize;
+ xub_StrLen nStringLen;
+
+ rIStm.Seek( nStrmPos );
+ rIStm >> nType
+ >> nActionSize;
+
+ nStringLen = sal::static_int_cast<xub_StrLen>(( nActionSize - 4 ) >> 1);
+
+ if ( nStringLen && ( nType == GDI_UNICODE_COMMENT ) )
+ {
+ sal_Unicode* pBuffer = rString.AllocBuffer( nStringLen );
+ while ( nStringLen-- )
+ rIStm >> *pBuffer++;
+ }
+ }
+ rIStm.Seek( nOld );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplSkipActions( SvStream& rIStm, ULONG nSkipCount )
+{
+ INT32 nActionSize;
+ INT16 nType;
+
+ for( ULONG i = 0UL; i < nSkipCount; i++ )
+ {
+ rIStm >> nType >> nActionSize;
+ rIStm.SeekRel( nActionSize - 4L );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+bool ImplWriteExtendedPolyPolygonAction(SvStream& rOStm, const PolyPolygon& rPolyPolygon, bool bOnlyWhenCurve)
+{
+ const sal_uInt16 nPolygonCount(rPolyPolygon.Count());
+
+ if(nPolygonCount)
+ {
+ sal_uInt32 nAllPolygonCount(0);
+ sal_uInt32 nAllPointCount(0);
+ sal_uInt32 nAllFlagCount(0);
+ sal_uInt16 a(0);
+
+ for(a = 0; a < nPolygonCount; a++)
+ {
+ const Polygon& rCandidate = rPolyPolygon.GetObject(a);
+ const sal_uInt16 nPointCount(rCandidate.GetSize());
+
+ if(nPointCount)
+ {
+ nAllPolygonCount++;
+ nAllPointCount += nPointCount;
+
+ if(rCandidate.HasFlags())
+ {
+ nAllFlagCount += nPointCount;
+ }
+ }
+ }
+
+ if((bOnlyWhenCurve && nAllFlagCount) || (!bOnlyWhenCurve && nAllPointCount))
+ {
+ rOStm << (INT16) GDI_EXTENDEDPOLYGON_ACTION;
+
+ const sal_Int32 nActionSize(
+ 4 + // Action size
+ 2 + // PolygonCount
+ (nAllPolygonCount * 2) + // Points per polygon
+ (nAllPointCount << 3) + // Points themselves
+ nAllPolygonCount + // Bool if (when poly has points) it has flags, too
+ nAllFlagCount); // Flags themselves
+
+ rOStm << nActionSize;
+ rOStm << (sal_uInt16)nAllPolygonCount;
+
+ for(a = 0; a < nPolygonCount; a++)
+ {
+ const Polygon& rCandidate = rPolyPolygon.GetObject(a);
+ const sal_uInt16 nPointCount(rCandidate.GetSize());
+
+ if(nPointCount)
+ {
+ rOStm << nPointCount;
+
+ for(sal_uInt16 b(0); b < nPointCount; b++)
+ {
+ rOStm << rCandidate[b];
+ }
+
+ if(rCandidate.HasFlags())
+ {
+ rOStm << (BYTE)true;
+
+ for(sal_uInt16 c(0); c < nPointCount; c++)
+ {
+ rOStm << (BYTE)rCandidate.GetFlags(c);
+ }
+ }
+ else
+ {
+ rOStm << (BYTE)false;
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplReadExtendedPolyPolygonAction(SvStream& rIStm, PolyPolygon& rPolyPoly)
+{
+ rPolyPoly.Clear();
+ sal_uInt16 nPolygonCount(0);
+ rIStm >> nPolygonCount;
+
+ for(sal_uInt16 a(0); a < nPolygonCount; a++)
+ {
+ sal_uInt16 nPointCount(0);
+ rIStm >> nPointCount;
+ Polygon aCandidate(nPointCount);
+
+ if(nPointCount)
+ {
+ for(sal_uInt16 b(0); b < nPointCount; b++)
+ {
+ rIStm >> aCandidate[b];
+ }
+
+ BYTE bHasFlags(false);
+ rIStm >> bHasFlags;
+
+ if(bHasFlags)
+ {
+ BYTE aPolyFlags(0);
+
+ for(sal_uInt16 c(0); c < nPointCount; c++)
+ {
+ rIStm >> aPolyFlags;
+ aCandidate.SetFlags(c, (PolyFlags)aPolyFlags);
+ }
+ }
+ }
+
+ rPolyPoly.Insert(aCandidate);
+ }
+}
+
+// ----------------
+// - SVMConverter -
+// ----------------
+
+SVMConverter::SVMConverter( SvStream& rStm, GDIMetaFile& rMtf, ULONG nConvertMode )
+{
+ if( !rStm.GetError() )
+ {
+ if( CONVERT_FROM_SVM1 == nConvertMode )
+ ImplConvertFromSVM1( rStm, rMtf );
+ else if( CONVERT_TO_SVM1 == nConvertMode )
+ ImplConvertToSVM1( rStm, rMtf );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf )
+{
+ const ULONG nPos = rIStm.Tell();
+ const USHORT nOldFormat = rIStm.GetNumberFormatInt();
+
+ rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ char aCode[ 5 ];
+ Size aPrefSz;
+ INT16 nSize;
+ INT16 nVersion;
+
+ // read header
+ rIStm.Read( (char*) &aCode, sizeof( aCode ) ); // Kennung
+ rIStm >> nSize; // Size
+ rIStm >> nVersion; // Version
+ rIStm >> aPrefSz.Width(); // PrefSize.Width()
+ rIStm >> aPrefSz.Height(); // PrefSize.Height()
+
+ // check header-magic and version
+ if( rIStm.GetError()
+ || ( memcmp( aCode, "SVGDI", sizeof( aCode ) ) != 0 )
+ || ( nVersion != 200 ) )
+ {
+ rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ rIStm.SetNumberFormatInt( nOldFormat );
+ rIStm.Seek( nPos );
+ return;
+ }
+
+ LineInfo aLineInfo( LINE_NONE, 0 );
+ Stack aLIStack;
+ VirtualDevice aFontVDev;
+ rtl_TextEncoding eActualCharSet = gsl_getSystemTextEncoding();
+ BOOL bFatLine = FALSE;
+
+ // TODO: fix reindentation below if you can accept being blamed by the SCM
+ MapMode aMapMode;
+ Polygon aActionPoly;
+ Rectangle aRect;
+ Point aPt, aPt1;
+ Size aSz;
+ Color aActionColor;
+ INT32 nTmp, nTmp1, nActionSize;
+ INT32 nActions;
+ INT16 nType;
+
+ sal_uInt32 nUnicodeCommentStreamPos = 0;
+ INT32 nUnicodeCommentActionNumber = 0;
+
+ ImplReadMapMode( rIStm, aMapMode ); // MapMode
+ rIStm >> nActions; // Action count
+
+ rMtf.SetPrefSize( aPrefSz );
+ rMtf.SetPrefMapMode( aMapMode );
+ sal_uInt32 nLastPolygonAction(0);
+
+ for( INT32 i = 0L; i < nActions; i++ )
+ {
+ rIStm >> nType;
+ sal_Int32 nActBegin = rIStm.Tell();
+ rIStm >> nActionSize;
+
+ DBG_ASSERT( ( nType <= 33 ) || ( nType >= 1024 ), "Unknown GDIMetaAction while converting!" );
+
+ switch( nType )
+ {
+ case( GDI_PIXEL_ACTION ):
+ {
+ rIStm >> aPt;
+ ImplReadColor( rIStm, aActionColor );
+ rMtf.AddAction( new MetaPixelAction( aPt, aActionColor ) );
+ }
+ break;
+
+ case( GDI_POINT_ACTION ):
+ {
+ rIStm >> aPt;
+ rMtf.AddAction( new MetaPointAction( aPt ) );
+ }
+ break;
+
+ case( GDI_LINE_ACTION ):
+ {
+ rIStm >> aPt >> aPt1;
+ rMtf.AddAction( new MetaLineAction( aPt, aPt1, aLineInfo ) );
+ }
+ break;
+
+ case (GDI_LINEJOIN_ACTION) :
+ {
+ INT16 nLineJoin(0);
+ rIStm >> nLineJoin;
+ aLineInfo.SetLineJoin((basegfx::B2DLineJoin)nLineJoin);
+ }
+ break;
+
+ case (GDI_LINEDASHDOT_ACTION) :
+ {
+ INT16 a(0);
+ INT32 b(0);
+
+ rIStm >> a; aLineInfo.SetDashCount(a);
+ rIStm >> b; aLineInfo.SetDashLen(b);
+ rIStm >> a; aLineInfo.SetDotCount(a);
+ rIStm >> b; aLineInfo.SetDotLen(b);
+ rIStm >> b; aLineInfo.SetDistance(b);
+
+ if(((aLineInfo.GetDashCount() && aLineInfo.GetDashLen())
+ || (aLineInfo.GetDotCount() && aLineInfo.GetDotLen()))
+ && aLineInfo.GetDistance())
+ {
+ aLineInfo.SetStyle(LINE_DASH);
+ }
+ }
+ break;
+
+ case (GDI_EXTENDEDPOLYGON_ACTION) :
+ {
+ // read the PolyPolygon in every case
+ PolyPolygon aInputPolyPolygon;
+ ImplReadExtendedPolyPolygonAction(rIStm, aInputPolyPolygon);
+
+ // now check if it can be set somewhere
+ if(nLastPolygonAction < rMtf.GetActionCount())
+ {
+ MetaPolyLineAction* pPolyLineAction = dynamic_cast< MetaPolyLineAction* >(rMtf.GetAction(nLastPolygonAction));
+
+ if(pPolyLineAction)
+ {
+ // replace MetaPolyLineAction when we have a single polygon. Do not rely on the
+ // same point count; the originally written GDI_POLYLINE_ACTION may have been
+ // Subdivided for better quality for older usages
+ if(1 == aInputPolyPolygon.Count())
+ {
+ rMtf.ReplaceAction(
+ new MetaPolyLineAction(
+ aInputPolyPolygon.GetObject(0),
+ pPolyLineAction->GetLineInfo()),
+ nLastPolygonAction);
+ pPolyLineAction->Delete();
+ }
+ }
+ else
+ {
+ MetaPolyPolygonAction* pPolyPolygonAction = dynamic_cast< MetaPolyPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
+
+ if(pPolyPolygonAction)
+ {
+ // replace MetaPolyPolygonAction when we have a curved polygon. Do rely on the
+ // same sub-polygon count
+ if(pPolyPolygonAction->GetPolyPolygon().Count() == aInputPolyPolygon.Count())
+ {
+ rMtf.ReplaceAction(
+ new MetaPolyPolygonAction(
+ aInputPolyPolygon),
+ nLastPolygonAction);
+ pPolyPolygonAction->Delete();
+ }
+ }
+ else
+ {
+ MetaPolygonAction* pPolygonAction = dynamic_cast< MetaPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
+
+ if(pPolygonAction)
+ {
+ // replace MetaPolygonAction
+ if(1 == aInputPolyPolygon.Count())
+ {
+ rMtf.ReplaceAction(
+ new MetaPolygonAction(
+ aInputPolyPolygon.GetObject(0)),
+ nLastPolygonAction);
+ pPolygonAction->Delete();
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case( GDI_RECT_ACTION ):
+ {
+ ImplReadRect( rIStm, aRect );
+ rIStm >> nTmp >> nTmp1;
+
+ if( nTmp || nTmp1 )
+ rMtf.AddAction( new MetaRoundRectAction( aRect, nTmp, nTmp1 ) );
+ else
+ {
+ rMtf.AddAction( new MetaRectAction( aRect ) );
+
+ if( bFatLine )
+ rMtf.AddAction( new MetaPolyLineAction( aRect, aLineInfo ) );
+ }
+ }
+ break;
+
+ case( GDI_ELLIPSE_ACTION ):
+ {
+ ImplReadRect( rIStm, aRect );
+
+ if( bFatLine )
+ {
+ const Polygon aPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
+
+ rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) );
+ rMtf.AddAction( new MetaPolygonAction( aPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
+ }
+ else
+ rMtf.AddAction( new MetaEllipseAction( aRect ) );
+ }
+ break;
+
+ case( GDI_ARC_ACTION ):
+ {
+ ImplReadRect( rIStm, aRect );
+ rIStm >> aPt >> aPt1;
+
+ if( bFatLine )
+ {
+ const Polygon aPoly( aRect, aPt, aPt1, POLY_ARC );
+
+ rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) );
+ rMtf.AddAction( new MetaPolygonAction( aPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
+ }
+ else
+ rMtf.AddAction( new MetaArcAction( aRect, aPt, aPt1 ) );
+ }
+ break;
+
+ case( GDI_PIE_ACTION ):
+ {
+ ImplReadRect( rIStm, aRect );
+ rIStm >> aPt >> aPt1;
+
+ if( bFatLine )
+ {
+ const Polygon aPoly( aRect, aPt, aPt1, POLY_PIE );
+
+ rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) );
+ rMtf.AddAction( new MetaPolygonAction( aPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
+ }
+ else
+ rMtf.AddAction( new MetaPieAction( aRect, aPt, aPt1 ) );
+ }
+ break;
+
+ case( GDI_INVERTRECT_ACTION ):
+ case( GDI_HIGHLIGHTRECT_ACTION ):
+ {
+ ImplReadRect( rIStm, aRect );
+ rMtf.AddAction( new MetaPushAction( PUSH_RASTEROP ) );
+ rMtf.AddAction( new MetaRasterOpAction( ROP_INVERT ) );
+ rMtf.AddAction( new MetaRectAction( aRect ) );
+ rMtf.AddAction( new MetaPopAction() );
+ }
+ break;
+
+ case( GDI_POLYLINE_ACTION ):
+ {
+ ImplReadPoly( rIStm, aActionPoly );
+ nLastPolygonAction = rMtf.GetActionCount();
+
+ if( bFatLine )
+ rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
+ else
+ rMtf.AddAction( new MetaPolyLineAction( aActionPoly ) );
+ }
+ break;
+
+ case( GDI_POLYGON_ACTION ):
+ {
+ ImplReadPoly( rIStm, aActionPoly );
+
+ if( bFatLine )
+ {
+ rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) );
+ rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
+ }
+ else
+ {
+ nLastPolygonAction = rMtf.GetActionCount();
+ rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
+ }
+ }
+ break;
+
+ case( GDI_POLYPOLYGON_ACTION ):
+ {
+ PolyPolygon aPolyPoly;
+
+ ImplReadPolyPoly( rIStm, aPolyPoly );
+
+ if( bFatLine )
+ {
+ rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) );
+ rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+
+ for( USHORT nPoly = 0, nCount = aPolyPoly.Count(); nPoly < nCount; nPoly++ )
+ rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) );
+ }
+ else
+ {
+ nLastPolygonAction = rMtf.GetActionCount();
+ rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
+ }
+ }
+ break;
+
+ case( GDI_FONT_ACTION ):
+ {
+ Font aFont;
+ char aName[ 32 ];
+ INT32 nWidth, nHeight;
+ INT16 nCharSet, nFamily, nPitch, nAlign, nWeight, nUnderline, nStrikeout;
+ INT16 nCharOrient, nLineOrient;
+ BOOL bItalic, bOutline, bShadow, bTransparent;
+
+ ImplReadColor( rIStm, aActionColor ); aFont.SetColor( aActionColor );
+ ImplReadColor( rIStm, aActionColor ); aFont.SetFillColor( aActionColor );
+ rIStm.Read( aName, 32 );
+ aFont.SetName( UniString( aName, rIStm.GetStreamCharSet() ) );
+ rIStm >> nWidth >> nHeight;
+ rIStm >> nCharOrient >> nLineOrient;
+ rIStm >> nCharSet >> nFamily >> nPitch >> nAlign >> nWeight >> nUnderline >> nStrikeout;
+ rIStm >> bItalic >> bOutline >> bShadow >> bTransparent;
+
+ aFont.SetSize( Size( nWidth, nHeight ) );
+ aFont.SetCharSet( (CharSet) nCharSet );
+ aFont.SetFamily( (FontFamily) nFamily );
+ aFont.SetPitch( (FontPitch) nPitch );
+ aFont.SetAlign( (FontAlign) nAlign );
+ aFont.SetWeight( ( nWeight == 1 ) ? WEIGHT_LIGHT : ( nWeight == 2 ) ? WEIGHT_NORMAL :
+ ( nWeight == 3 ) ? WEIGHT_BOLD : WEIGHT_DONTKNOW );
+ aFont.SetUnderline( (FontUnderline) nUnderline );
+ aFont.SetStrikeout( (FontStrikeout) nStrikeout );
+ aFont.SetItalic( bItalic ? ITALIC_NORMAL : ITALIC_NONE );
+ aFont.SetOutline( bOutline );
+ aFont.SetShadow( bShadow );
+ aFont.SetOrientation( nLineOrient );
+ aFont.SetTransparent( bTransparent );
+
+ eActualCharSet = aFont.GetCharSet();
+ if ( eActualCharSet == RTL_TEXTENCODING_DONTKNOW )
+ eActualCharSet = gsl_getSystemTextEncoding();
+
+ rMtf.AddAction( new MetaFontAction( aFont ) );
+ rMtf.AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
+ rMtf.AddAction( new MetaTextColorAction( aFont.GetColor() ) );
+ rMtf.AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev.SetFont( aFont );
+ }
+ break;
+
+ case( GDI_TEXT_ACTION ):
+ {
+ ByteString aByteStr;
+ INT32 nIndex, nLen;
+
+ rIStm >> aPt >> nIndex >> nLen >> nTmp;
+ if ( nTmp && ( static_cast< sal_uInt32 >( nTmp ) < ( SAL_MAX_UINT16 - 1 ) ) )
+ {
+ rIStm.Read( aByteStr.AllocBuffer( (USHORT)nTmp ), nTmp + 1 );
+ UniString aStr( aByteStr, eActualCharSet );
+ if ( nUnicodeCommentActionNumber == i )
+ ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
+ rMtf.AddAction( new MetaTextAction( aPt, aStr, (USHORT) nIndex, (USHORT) nLen ) );
+ }
+ rIStm.Seek( nActBegin + nActionSize );
+ }
+ break;
+
+ case( GDI_TEXTARRAY_ACTION ):
+ {
+ ByteString aByteStr;
+ sal_Int32* pDXAry = NULL;
+ INT32 nIndex, nLen, nAryLen;
+
+ rIStm >> aPt >> nIndex >> nLen >> nTmp >> nAryLen;
+ if ( nTmp && ( static_cast< sal_uInt32 >( nTmp ) < ( SAL_MAX_UINT16 - 1 ) ) )
+ {
+ rIStm.Read( aByteStr.AllocBuffer( (USHORT)nTmp ), nTmp + 1 );
+ UniString aStr( aByteStr, eActualCharSet );
+
+ if( nAryLen > 0L )
+ {
+ INT32 nStrLen( aStr.Len() );
+
+ pDXAry = new sal_Int32[ Max( nAryLen, nStrLen ) ];
+
+ for( long j = 0L; j < nAryLen; j++ )
+ rIStm >> nTmp, pDXAry[ j ] = nTmp;
+
+ // #106172# Add last DX array elem, if missing
+ if( nAryLen != nStrLen )
+ {
+ if( nAryLen+1 == nStrLen )
+ {
+ sal_Int32* pTmpAry = new sal_Int32[nStrLen];
+
+ aFontVDev.GetTextArray( aStr, pTmpAry, (USHORT) nIndex, (USHORT) nLen );
+
+ // now, the difference between the
+ // last and the second last DX array
+ // is the advancement for the last
+ // glyph. Thus, to complete our meta
+ // action's DX array, just add that
+ // difference to last elem and store
+ // in very last.
+ if( nStrLen > 1 )
+ pDXAry[ nStrLen-1 ] = pDXAry[ nStrLen-2 ] + pTmpAry[ nStrLen-1 ] - pTmpAry[ nStrLen-2 ];
+ else
+ pDXAry[ nStrLen-1 ] = pTmpAry[ nStrLen-1 ]; // len=1: 0th position taken to be 0
+
+ delete[] pTmpAry;
+ }
+ #ifdef DBG_UTIL
+ else
+ DBG_ERROR("More than one DX array element missing on SVM import");
+ #endif
+ }
+ }
+ if ( nUnicodeCommentActionNumber == i )
+ ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
+ rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, pDXAry, (USHORT) nIndex, (USHORT) nLen ) );
+
+ if( pDXAry )
+ delete[] pDXAry;
+ }
+ rIStm.Seek( nActBegin + nActionSize );
+ }
+ break;
+
+ case( GDI_STRETCHTEXT_ACTION ):
+ {
+ ByteString aByteStr;
+ INT32 nIndex, nLen, nWidth;
+
+ rIStm >> aPt >> nIndex >> nLen >> nTmp >> nWidth;
+ if ( nTmp && ( static_cast< sal_uInt32 >( nTmp ) < ( SAL_MAX_INT16 - 1 ) ) )
+ {
+ rIStm.Read( aByteStr.AllocBuffer( (USHORT)nTmp ), nTmp + 1 );
+ UniString aStr( aByteStr, eActualCharSet );
+ if ( nUnicodeCommentActionNumber == i )
+ ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
+ rMtf.AddAction( new MetaStretchTextAction( aPt, nWidth, aStr, (USHORT) nIndex, (USHORT) nLen ) );
+ }
+ rIStm.Seek( nActBegin + nActionSize );
+ }
+ break;
+
+ case( GDI_BITMAP_ACTION ):
+ {
+ Bitmap aBmp;
+
+ rIStm >> aPt >> aBmp;
+ rMtf.AddAction( new MetaBmpAction( aPt, aBmp ) );
+ }
+ break;
+
+ case( GDI_BITMAPSCALE_ACTION ):
+ {
+ Bitmap aBmp;
+
+ rIStm >> aPt >> aSz >> aBmp;
+ rMtf.AddAction( new MetaBmpScaleAction( aPt, aSz, aBmp ) );
+ }
+ break;
+
+ case( GDI_BITMAPSCALEPART_ACTION ):
+ {
+ Bitmap aBmp;
+ Size aSz2;
+
+ rIStm >> aPt >> aSz >> aPt1 >> aSz2 >> aBmp;
+ rMtf.AddAction( new MetaBmpScalePartAction( aPt, aSz, aPt1, aSz2, aBmp ) );
+ }
+ break;
+
+ case( GDI_PEN_ACTION ):
+ {
+ INT32 nPenWidth;
+ INT16 nPenStyle;
+
+ ImplReadColor( rIStm, aActionColor );
+ rIStm >> nPenWidth >> nPenStyle;
+
+ aLineInfo.SetStyle( nPenStyle ? LINE_SOLID : LINE_NONE );
+ aLineInfo.SetWidth( nPenWidth );
+ bFatLine = nPenStyle && !aLineInfo.IsDefault();
+
+ rMtf.AddAction( new MetaLineColorAction( aActionColor, nPenStyle != 0 ) );
+ }
+ break;
+
+ case( GDI_FILLBRUSH_ACTION ):
+ {
+ INT16 nBrushStyle;
+
+ ImplReadColor( rIStm, aActionColor );
+ rIStm.SeekRel( 6L );
+ rIStm >> nBrushStyle;
+ rMtf.AddAction( new MetaFillColorAction( aActionColor, nBrushStyle != 0 ) );
+ rIStm.SeekRel( 2L );
+ }
+ break;
+
+ case( GDI_MAPMODE_ACTION ):
+ {
+ ImplReadMapMode( rIStm, aMapMode );
+ rMtf.AddAction( new MetaMapModeAction( aMapMode ) );
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev.SetMapMode( aMapMode );
+ }
+ break;
+
+ case( GDI_CLIPREGION_ACTION ):
+ {
+ Region aRegion;
+ INT16 nRegType;
+ INT16 bIntersect;
+ BOOL bClip = FALSE;
+
+ rIStm >> nRegType >> bIntersect;
+ ImplReadRect( rIStm, aRect );
+
+ switch( nRegType )
+ {
+ case( 0 ):
+ break;
+
+ case( 1 ):
+ {
+ Rectangle aRegRect;
+
+ ImplReadRect( rIStm, aRegRect );
+ aRegion = Region( aRegRect );
+ bClip = TRUE;
+ }
+ break;
+
+ case( 2 ):
+ {
+ ImplReadPoly( rIStm, aActionPoly );
+ aRegion = Region( aActionPoly );
+ bClip = TRUE;
+ }
+ break;
+
+ case( 3 ):
+ {
+ PolyPolygon aPolyPoly;
+ INT32 nPolyCount;
+
+ rIStm >> nPolyCount;
+
+ for( USHORT j = 0; j < (USHORT) nPolyCount; j++ )
+ {
+ ImplReadPoly( rIStm, aActionPoly );
+ aPolyPoly.Insert( aActionPoly );
+ }
+
+ aRegion = Region( aPolyPoly );
+ bClip = TRUE;
+ }
+ break;
+ }
+
+ if( bIntersect )
+ aRegion.Intersect( aRect );
+
+ rMtf.AddAction( new MetaClipRegionAction( aRegion, bClip ) );
+ }
+ break;
+
+ case( GDI_MOVECLIPREGION_ACTION ):
+ {
+ rIStm >> nTmp >> nTmp1;
+ rMtf.AddAction( new MetaMoveClipRegionAction( nTmp, nTmp1 ) );
+ }
+ break;
+
+ case( GDI_ISECTCLIPREGION_ACTION ):
+ {
+ ImplReadRect( rIStm, aRect );
+ rMtf.AddAction( new MetaISectRectClipRegionAction( aRect ) );
+ }
+ break;
+
+ case( GDI_RASTEROP_ACTION ):
+ {
+ RasterOp eRasterOp;
+ INT16 nRasterOp;
+
+ rIStm >> nRasterOp;
+
+ switch( nRasterOp )
+ {
+ case( 1 ):
+ eRasterOp = ROP_INVERT;
+ break;
+
+ case( 4 ):
+ case( 5 ):
+ eRasterOp = ROP_XOR;
+ break;
+
+ default:
+ eRasterOp = ROP_OVERPAINT;
+ break;
+ }
+
+ rMtf.AddAction( new MetaRasterOpAction( eRasterOp ) );
+ }
+ break;
+
+ case( GDI_PUSH_ACTION ):
+ {
+ aLIStack.Push( new LineInfo( aLineInfo ) );
+ rMtf.AddAction( new MetaPushAction( PUSH_ALL ) );
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev.Push();
+ }
+ break;
+
+ case( GDI_POP_ACTION ):
+ {
+
+ LineInfo* pLineInfo = (LineInfo*) aLIStack.Pop();
+
+ // restore line info
+ if( pLineInfo )
+ {
+ aLineInfo = *pLineInfo;
+ delete pLineInfo;
+ bFatLine = ( LINE_NONE != aLineInfo.GetStyle() ) && !aLineInfo.IsDefault();
+ }
+
+ rMtf.AddAction( new MetaPopAction() );
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev.Pop();
+ }
+ break;
+
+ case( GDI_GRADIENT_ACTION ):
+ {
+ Color aStartCol;
+ Color aEndCol;
+ INT16 nStyle;
+ INT16 nAngle;
+ INT16 nBorder;
+ INT16 nOfsX;
+ INT16 nOfsY;
+ INT16 nIntensityStart;
+ INT16 nIntensityEnd;
+
+ ImplReadRect( rIStm, aRect );
+ rIStm >> nStyle;
+ ImplReadColor( rIStm, aStartCol );
+ ImplReadColor( rIStm, aEndCol );
+ rIStm >> nAngle >> nBorder >> nOfsX >> nOfsY >> nIntensityStart >> nIntensityEnd;
+
+ Gradient aGrad( (GradientStyle) nStyle, aStartCol, aEndCol );
+
+ aGrad.SetAngle( nAngle );
+ aGrad.SetBorder( nBorder );
+ aGrad.SetOfsX( nOfsX );
+ aGrad.SetOfsY( nOfsY );
+ aGrad.SetStartIntensity( nIntensityStart );
+ aGrad.SetEndIntensity( nIntensityEnd );
+ rMtf.AddAction( new MetaGradientAction( aRect, aGrad ) );
+ }
+ break;
+
+ case( GDI_TRANSPARENT_COMMENT ):
+ {
+ PolyPolygon aPolyPoly;
+ INT32 nFollowingActionCount;
+ INT16 nTrans;
+
+ rIStm >> aPolyPoly >> nTrans >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaTransparentAction( aPolyPoly, nTrans ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+ }
+ break;
+
+ case( GDI_FLOATTRANSPARENT_COMMENT ):
+ {
+ GDIMetaFile aMtf;
+ Point aPos;
+ Size aSize;
+ Gradient aGradient;
+ INT32 nFollowingActionCount;
+
+ rIStm >> aMtf >> aPos >> aSize >> aGradient >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaFloatTransparentAction( aMtf, aPos, aSize, aGradient ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+ }
+ break;
+
+ case( GDI_HATCH_COMMENT ):
+ {
+ PolyPolygon aPolyPoly;
+ Hatch aHatch;
+ INT32 nFollowingActionCount;
+
+ rIStm >> aPolyPoly >> aHatch >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaHatchAction( aPolyPoly, aHatch ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+ }
+ break;
+
+ case( GDI_REFPOINT_COMMENT ):
+ {
+ Point aRefPoint;
+ BOOL bSet;
+ INT32 nFollowingActionCount;
+
+ rIStm >> aRefPoint >> bSet >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaRefPointAction( aRefPoint, bSet ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+
+ // #106172# Track font relevant data in shadow VDev
+ if( bSet )
+ aFontVDev.SetRefPoint( aRefPoint );
+ else
+ aFontVDev.SetRefPoint();
+ }
+ break;
+
+ case( GDI_TEXTLINECOLOR_COMMENT ):
+ {
+ Color aColor;
+ BOOL bSet;
+ INT32 nFollowingActionCount;
+
+ rIStm >> aColor >> bSet >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaTextLineColorAction( aColor, bSet ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+ }
+ break;
+
+ case( GDI_TEXTLINE_COMMENT ):
+ {
+ Point aStartPt;
+ long nWidth;
+ sal_uInt32 nStrikeout;
+ sal_uInt32 nUnderline;
+ INT32 nFollowingActionCount;
+
+ rIStm >> aStartPt >> nWidth >> nStrikeout >> nUnderline >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaTextLineAction( aStartPt, nWidth,
+ (FontStrikeout) nStrikeout,
+ (FontUnderline) nUnderline,
+ UNDERLINE_NONE ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+ }
+ break;
+
+ case( GDI_GRADIENTEX_COMMENT ):
+ {
+ PolyPolygon aPolyPoly;
+ Gradient aGradient;
+ INT32 nFollowingActionCount;
+
+ rIStm >> aPolyPoly >> aGradient >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaGradientExAction( aPolyPoly, aGradient ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+ }
+ break;
+
+ case( GDI_COMMENT_COMMENT ):
+ {
+ ByteString aComment;
+ sal_Int32 nValue;
+ sal_uInt32 nDataSize;
+ BYTE* pData;
+ INT32 nFollowingActionCount;
+
+ rIStm >> aComment >> nValue >> nDataSize;
+
+ if( nDataSize )
+ {
+ pData = new BYTE[ nDataSize ];
+ rIStm.Read( pData, nDataSize );
+ }
+ else
+ pData = NULL;
+
+ rIStm >> nFollowingActionCount;
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaCommentAction( aComment, nValue, pData, nDataSize ) );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ i += nFollowingActionCount;
+#endif
+ }
+ break;
+
+ case ( GDI_UNICODE_COMMENT ):
+ {
+ nUnicodeCommentActionNumber = i + 1;
+ nUnicodeCommentStreamPos = rIStm.Tell() - 6;
+ rIStm.SeekRel( nActionSize - 4 );
+ }
+ break;
+
+ default:
+ rIStm.SeekRel( nActionSize - 4L );
+ break;
+ }
+ }
+
+ // cleanup push-pop stack if neccessary
+ for( void* pLineInfo = aLIStack.Pop(); pLineInfo; pLineInfo = aLIStack.Pop() )
+ delete (LineInfo*) pLineInfo;
+
+ rIStm.SetNumberFormatInt( nOldFormat );
+}
+
+// ------------------------------------------------------------------------
+
+void SVMConverter::ImplConvertToSVM1( SvStream& rOStm, GDIMetaFile& rMtf )
+{
+ ULONG nPos;
+ ULONG nCountPos;
+ Font aSaveFont;
+ const USHORT nOldFormat = rOStm.GetNumberFormatInt();
+ rtl_TextEncoding eActualCharSet = gsl_getSystemTextEncoding();
+ const Size aPrefSize( rMtf.GetPrefSize() );
+ BOOL bRop_0_1 = FALSE;
+ VirtualDevice aSaveVDev;
+ Color aLineCol( COL_BLACK );
+ Stack aLineColStack;
+
+ rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ //MagicCode schreiben
+ rOStm << "SVGDI"; // Kennung
+ nPos = rOStm.Tell();
+ rOStm << (INT16) 42; // HeaderSize
+ rOStm << (INT16) 200; // VERSION
+ rOStm << (INT32) aPrefSize.Width();
+ rOStm << (INT32) aPrefSize.Height();
+ ImplWriteMapMode( rOStm, rMtf.GetPrefMapMode() );
+
+ // ActionCount wird spaeter geschrieben
+ nCountPos = rOStm.Tell();
+ rOStm.SeekRel( 4L );
+
+ const INT32 nActCount = ImplWriteActions( rOStm, rMtf, aSaveVDev, bRop_0_1, aLineCol, aLineColStack, eActualCharSet );
+ const ULONG nActPos = rOStm.Tell();
+
+ rOStm.Seek( nCountPos );
+ rOStm << nActCount;
+ rOStm.Seek( nActPos );
+ rOStm.SetNumberFormatInt( nOldFormat );
+
+ // cleanup push-pop stack if neccessary
+ for( void* pCol = aLineColStack.Pop(); pCol; pCol = aLineColStack.Pop() )
+ delete (Color*) pCol;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
+ VirtualDevice& rSaveVDev, BOOL& rRop_0_1,
+ Color& rLineCol, Stack& rLineColStack,
+ rtl_TextEncoding& rActualCharSet )
+{
+ ULONG nCount = 0;
+ for( ULONG i = 0, nActionCount = rMtf.GetActionCount(); i < nActionCount; i++ )
+ {
+ const MetaAction* pAction = rMtf.GetAction( i );
+
+ switch( pAction->GetType() )
+ {
+ case( META_PIXEL_ACTION ):
+ {
+ MetaPixelAction* pAct = (MetaPixelAction*) pAction;
+
+ rOStm << (INT16) GDI_PIXEL_ACTION;
+ rOStm << (INT32) 18;
+ rOStm << pAct->GetPoint();
+ ImplWriteColor( rOStm, pAct->GetColor() );
+ nCount++;
+ }
+ break;
+
+ case( META_POINT_ACTION ):
+ {
+ MetaPointAction* pAct = (MetaPointAction*) pAction;
+
+ rOStm << (INT16) GDI_POINT_ACTION;
+ rOStm << (INT32) 12;
+ rOStm << pAct->GetPoint();
+ nCount++;
+ }
+ break;
+
+ case( META_LINE_ACTION ):
+ {
+ MetaLineAction* pAct = (MetaLineAction*) pAction;
+ const LineInfo& rInfo = pAct->GetLineInfo();
+ const bool bFatLine(!rInfo.IsDefault() && (LINE_NONE != rInfo.GetStyle()));
+ const bool bLineJoin(bFatLine && basegfx::B2DLINEJOIN_ROUND != rInfo.GetLineJoin());
+ const bool bLineDashDot(LINE_DASH == rInfo.GetStyle());
+
+ if( bFatLine )
+ {
+ ImplWritePushAction( rOStm );
+ ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() );
+
+ if(bLineJoin)
+ {
+ rOStm << (INT16) GDI_LINEJOIN_ACTION;
+ rOStm << (INT32) 6;
+ rOStm << (INT16) rInfo.GetLineJoin();
+ }
+
+ if(bLineDashDot)
+ {
+ rOStm << (INT16) GDI_LINEDASHDOT_ACTION;
+ rOStm << (INT32) 4 + 16;
+ rOStm << (INT16)rInfo.GetDashCount();
+ rOStm << (INT32)rInfo.GetDashLen();
+ rOStm << (INT16)rInfo.GetDotCount();
+ rOStm << (INT32)rInfo.GetDotLen();
+ rOStm << (INT32)rInfo.GetDistance();
+ }
+ }
+
+ rOStm << (INT16) GDI_LINE_ACTION;
+ rOStm << (INT32) 20;
+ rOStm << pAct->GetStartPoint();
+ rOStm << pAct->GetEndPoint();
+ nCount++;
+
+ if( bFatLine )
+ {
+ ImplWritePopAction( rOStm );
+ nCount += 3;
+
+ if(bLineJoin)
+ {
+ nCount += 1;
+ }
+
+ if(bLineDashDot)
+ {
+ nCount += 1;
+ }
+ }
+ }
+ break;
+
+ case( META_RECT_ACTION ):
+ {
+ MetaRectAction* pAct = (MetaRectAction*) pAction;
+
+ rOStm << (INT16) GDI_RECT_ACTION;
+ rOStm << (INT32) 28;
+ ImplWriteRect( rOStm, pAct->GetRect() );
+ rOStm << (INT32) 0;
+ rOStm << (INT32) 0;
+ nCount++;
+ }
+ break;
+
+ case( META_ROUNDRECT_ACTION ):
+ {
+ MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction;
+
+ rOStm << (INT16) GDI_RECT_ACTION;
+ rOStm << (INT32) 28;
+ ImplWriteRect( rOStm, pAct->GetRect() );
+ rOStm << (INT32) pAct->GetHorzRound();
+ rOStm << (INT32) pAct->GetVertRound();
+ nCount++;
+ }
+ break;
+
+ case( META_ELLIPSE_ACTION ):
+ {
+ MetaEllipseAction* pAct = (MetaEllipseAction*) pAction;
+
+ rOStm << (INT16) GDI_ELLIPSE_ACTION;
+ rOStm << (INT32) 20;
+ ImplWriteRect( rOStm, pAct->GetRect() );
+ nCount++;
+ }
+ break;
+
+ case( META_ARC_ACTION ):
+ {
+ MetaArcAction* pAct = (MetaArcAction*) pAction;
+
+ rOStm << (INT16) GDI_ARC_ACTION;
+ rOStm << (INT32) 36;
+ ImplWriteRect( rOStm, pAct->GetRect() );
+ rOStm << pAct->GetStartPoint();
+ rOStm << pAct->GetEndPoint();
+ nCount++;
+ }
+ break;
+
+ case( META_PIE_ACTION ):
+ {
+ MetaPieAction* pAct = (MetaPieAction*) pAction;
+
+ rOStm << (INT16) GDI_PIE_ACTION;
+ rOStm << (INT32) 36;
+ ImplWriteRect( rOStm, pAct->GetRect() );
+ rOStm << pAct->GetStartPoint();
+ rOStm << pAct->GetEndPoint();
+ nCount++;
+ }
+ break;
+
+ case( META_CHORD_ACTION ):
+ {
+ MetaChordAction* pAct = (MetaChordAction*) pAction;
+ Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(),
+ pAct->GetEndPoint(), POLY_CHORD );
+ const USHORT nPoints = aChordPoly.GetSize();
+
+ rOStm << (INT16) GDI_POLYGON_ACTION;
+ rOStm << (INT32) ( 8 + ( nPoints << 3 ) );
+ rOStm << (INT32) nPoints;
+
+ for( USHORT n = 0; n < nPoints; n++ )
+ rOStm << aChordPoly[ n ];
+ nCount++;
+ }
+ break;
+
+ case( META_POLYLINE_ACTION ):
+ {
+ // #i102224#
+ MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
+ // #i102224# Here the evtl. curved nature of Polygon was
+ // ignored (for all those Years). Adapted to at least write
+ // a polygon representing the curve as good as possible
+ Polygon aSimplePoly;
+ pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly);
+ const LineInfo& rInfo = pAct->GetLineInfo();
+ const USHORT nPoints(aSimplePoly.GetSize());
+ const bool bFatLine(!rInfo.IsDefault() && (LINE_NONE != rInfo.GetStyle()));
+ const bool bLineJoin(bFatLine && basegfx::B2DLINEJOIN_ROUND != rInfo.GetLineJoin());
+ const bool bLineDashDot(LINE_DASH == rInfo.GetStyle());
+
+ if( bFatLine )
+ {
+ ImplWritePushAction( rOStm );
+ ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() );
+
+ if(bLineJoin)
+ {
+ rOStm << (INT16) GDI_LINEJOIN_ACTION;
+ rOStm << (INT32) 6;
+ rOStm << (INT16) rInfo.GetLineJoin();
+ }
+ }
+
+ if(bLineDashDot)
+ {
+ rOStm << (INT16) GDI_LINEDASHDOT_ACTION;
+ rOStm << (INT32) 4 + 16;
+ rOStm << (INT16)rInfo.GetDashCount();
+ rOStm << (INT32)rInfo.GetDashLen();
+ rOStm << (INT16)rInfo.GetDotCount();
+ rOStm << (INT32)rInfo.GetDotLen();
+ rOStm << (INT32)rInfo.GetDistance();
+ }
+
+ rOStm << (INT16) GDI_POLYLINE_ACTION;
+ rOStm << (INT32) ( 8 + ( nPoints << 3 ) );
+ rOStm << (INT32) nPoints;
+
+ for( USHORT n = 0; n < nPoints; n++ )
+ {
+ rOStm << aSimplePoly[ n ];
+ }
+
+ nCount++;
+
+ const PolyPolygon aPolyPolygon(pAct->GetPolygon());
+ if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true))
+ {
+ nCount++;
+ }
+
+ if( bFatLine )
+ {
+ ImplWritePopAction( rOStm );
+ nCount += 3;
+
+ if(bLineJoin)
+ {
+ nCount += 1;
+ }
+ }
+
+ if(bLineDashDot)
+ {
+ nCount += 1;
+ }
+ }
+ break;
+
+ case( META_POLYGON_ACTION ):
+ {
+ MetaPolygonAction* pAct = (MetaPolygonAction*)pAction;
+ // #i102224# Here the evtl. curved nature of Polygon was
+ // ignored (for all those Years). Adapted to at least write
+ // a polygon representing the curve as good as possible
+ Polygon aSimplePoly;
+ pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly);
+ const USHORT nPoints(aSimplePoly.GetSize());
+
+ rOStm << (INT16) GDI_POLYGON_ACTION;
+ rOStm << (INT32) ( 8 + ( nPoints << 3 ) );
+ rOStm << (INT32) nPoints;
+
+ for( USHORT n = 0; n < nPoints; n++ )
+ rOStm << aSimplePoly[ n ];
+
+ nCount++;
+
+ const PolyPolygon aPolyPolygon(pAct->GetPolygon());
+ if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true))
+ {
+ nCount++;
+ }
+ }
+ break;
+
+ case( META_POLYPOLYGON_ACTION ):
+ {
+ MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
+ ImplWritePolyPolyAction( rOStm, pAct->GetPolyPolygon() );
+ nCount++;
+
+ if(ImplWriteExtendedPolyPolygonAction(rOStm, pAct->GetPolyPolygon(), true))
+ {
+ nCount++;
+ }
+ }
+ break;
+
+ case( META_TEXT_ACTION ):
+ {
+ MetaTextAction* pAct = (MetaTextAction*) pAction;
+ String aUniText( pAct->GetText() );
+ ByteString aText( aUniText, rActualCharSet );
+ const ULONG nStrLen = aText.Len();
+
+ if ( ImplWriteUnicodeComment( rOStm, aUniText ) )
+ nCount++;
+
+ rOStm << (INT16) GDI_TEXT_ACTION;
+ rOStm << (INT32) ( 24 + ( nStrLen + 1 ) );
+ rOStm << pAct->GetPoint();
+ rOStm << (INT32) pAct->GetIndex();
+ rOStm << (INT32) pAct->GetLen();
+ rOStm << (INT32) nStrLen;
+ rOStm.Write( aText.GetBuffer(), nStrLen + 1 );
+ nCount++;
+ }
+ break;
+
+ case( META_TEXTARRAY_ACTION ):
+ {
+ MetaTextArrayAction* pAct = (MetaTextArrayAction*)pAction;
+ ByteString aText( pAct->GetText(), rActualCharSet );
+ String aUniText( pAct->GetText(), pAct->GetIndex(), pAct->GetLen() );
+ ULONG nAryLen;
+ ULONG nLen = pAct->GetLen();
+ const ULONG nTextLen = aText.Len();
+ sal_Int32* pDXArray = pAct->GetDXArray();
+
+ if ( ImplWriteUnicodeComment( rOStm, aUniText ) )
+ nCount++;
+
+ if( ( nLen + pAct->GetIndex() ) > nTextLen )
+ {
+ if( pAct->GetIndex() <= nTextLen )
+ nLen = nTextLen - pAct->GetIndex();
+ else
+ nLen = 0UL;
+ }
+
+ if( !pDXArray || !nLen )
+ nAryLen = 0;
+ else
+ nAryLen = nLen; // #105987# Write out all of DX array
+
+ rOStm << (INT16) GDI_TEXTARRAY_ACTION;
+ rOStm << (INT32) ( 28 + ( nLen + 1 ) + ( nAryLen * 4 ) );
+ rOStm << pAct->GetPoint();
+ rOStm << (INT32) 0;
+ rOStm << (INT32) nLen;
+ rOStm << (INT32) nLen;
+ rOStm << (INT32) nAryLen;
+ rOStm.Write( aText.GetBuffer()+pAct->GetIndex(), nLen + 1 );
+
+ for( ULONG n = 0UL ; n < nAryLen; n++ )
+ rOStm << (INT32) pDXArray[ n ];
+
+ nCount++;
+ }
+ break;
+
+ case( META_STRETCHTEXT_ACTION ):
+ {
+ MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
+ String aUniText( pAct->GetText() );
+ ByteString aText( aUniText, rActualCharSet );
+ const ULONG nStrLen = aText.Len();
+
+ if ( ImplWriteUnicodeComment( rOStm, aUniText ) )
+ nCount++;
+
+ rOStm << (INT16) GDI_STRETCHTEXT_ACTION;
+ rOStm << (INT32) ( 28 + ( nStrLen + 1 ) );
+ rOStm << pAct->GetPoint();
+ rOStm << (INT32) pAct->GetIndex();
+ rOStm << (INT32) pAct->GetLen();
+ rOStm << (INT32) nStrLen;
+ rOStm << (INT32) pAct->GetWidth();
+ rOStm.Write( aText.GetBuffer(), nStrLen + 1 );
+ nCount++;
+ }
+ break;
+
+ case( META_BMP_ACTION ):
+ {
+ MetaBmpAction* pAct = (MetaBmpAction*) pAction;
+
+ rOStm << (INT16) GDI_BITMAP_ACTION;
+ rOStm << (INT32) 12;
+ rOStm << pAct->GetPoint();
+ rOStm << pAct->GetBitmap();
+ nCount++;
+ }
+ break;
+
+ case( META_BMPSCALE_ACTION ):
+ {
+ MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
+
+ rOStm << (INT16) GDI_BITMAPSCALE_ACTION;
+ rOStm << (INT32) 20;
+ rOStm << pAct->GetPoint();
+ rOStm << pAct->GetSize();
+ rOStm << pAct->GetBitmap();
+ nCount++;
+ }
+ break;
+
+ case( META_BMPSCALEPART_ACTION ):
+ {
+ MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
+
+ rOStm << (INT16) GDI_BITMAPSCALEPART_ACTION;
+ rOStm << (INT32) 36;
+ rOStm << pAct->GetDestPoint();
+ rOStm << pAct->GetDestSize();
+ rOStm << pAct->GetSrcPoint();
+ rOStm << pAct->GetSrcSize();
+ rOStm << pAct->GetBitmap();
+ nCount++;
+ }
+ break;
+
+ case( META_BMPEX_ACTION ):
+ {
+ MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
+ const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() );
+
+ rOStm << (INT16) GDI_BITMAP_ACTION;
+ rOStm << (INT32) 12;
+ rOStm << pAct->GetPoint();
+ rOStm << aBmp;
+ nCount++;
+ }
+ break;
+
+ case( META_BMPEXSCALE_ACTION ):
+ {
+ MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
+ const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() );
+
+ rOStm << (INT16) GDI_BITMAPSCALE_ACTION;
+ rOStm << (INT32) 20;
+ rOStm << pAct->GetPoint();
+ rOStm << pAct->GetSize();
+ rOStm << aBmp;
+ nCount++;
+ }
+ break;
+
+ case( META_BMPEXSCALEPART_ACTION ):
+ {
+ MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
+ const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() );
+
+ rOStm << (INT16) GDI_BITMAPSCALEPART_ACTION;
+ rOStm << (INT32) 36;
+ rOStm << pAct->GetDestPoint();
+ rOStm << pAct->GetDestSize();
+ rOStm << pAct->GetSrcPoint();
+ rOStm << pAct->GetSrcSize();
+ rOStm << aBmp;
+ nCount++;
+ }
+ break;
+
+ case( META_GRADIENT_ACTION ):
+ {
+ MetaGradientAction* pAct = (MetaGradientAction*) pAction;
+ const Gradient& rGrad = pAct->GetGradient();
+
+ rOStm << (INT16) GDI_GRADIENT_ACTION;
+ rOStm << (INT32) 46;
+ ImplWriteRect( rOStm, pAct->GetRect() );
+ rOStm << (INT16) rGrad.GetStyle();
+ ImplWriteColor( rOStm, rGrad.GetStartColor() );
+ ImplWriteColor( rOStm, rGrad.GetEndColor() );
+ rOStm << (INT16) rGrad.GetAngle();
+ rOStm << (INT16) rGrad.GetBorder();
+ rOStm << (INT16) rGrad.GetOfsX();
+ rOStm << (INT16) rGrad.GetOfsY();
+ rOStm << (INT16) rGrad.GetStartIntensity();
+ rOStm << (INT16) rGrad.GetEndIntensity();
+ nCount++;
+ }
+ break;
+
+ case( META_GRADIENTEX_ACTION ):
+ {
+ const MetaGradientExAction* pA = (MetaGradientExAction*) pAction;
+ ULONG nOldPos, nNewPos;
+
+ // write RefPoint comment
+ rOStm << (INT16) GDI_GRADIENTEX_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write data
+ rOStm << pA->GetPolyPolygon() << pA->GetGradient();
+ rOStm << (INT32) 0; // number of actions that follow this comment
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos );
+ rOStm.Seek( nNewPos );
+
+ nCount++;
+ }
+ break;
+
+ case( META_WALLPAPER_ACTION ):
+ {
+ MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction;
+ const Color& rColor = pAct->GetWallpaper().GetColor();
+
+ ImplWritePushAction( rOStm );
+ ImplWriteLineColor( rOStm, rColor, 1 );
+ ImplWriteFillColor( rOStm, rColor, 1 );
+
+ rOStm << (INT16) GDI_RECT_ACTION;
+ rOStm << (INT32) 28;
+ ImplWriteRect( rOStm, pAct->GetRect() );
+ rOStm << (INT32) 0;
+ rOStm << (INT32) 0;
+
+ ImplWritePopAction( rOStm );
+ nCount += 5;
+ }
+ break;
+
+ case( META_CLIPREGION_ACTION ):
+ {
+ MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
+ const Region& rRegion = pAct->GetRegion();
+ Rectangle aClipRect;
+
+ rOStm << (INT16) GDI_CLIPREGION_ACTION;
+ rOStm << (INT32) 24;
+
+ if( pAct->IsClipping() )
+ {
+ aClipRect = rRegion.GetBoundRect();
+ rOStm << (INT16) 1;
+ }
+ else
+ rOStm << (INT16) 0;
+
+ rOStm << (INT16) 0;
+ ImplWriteRect( rOStm, aClipRect );
+
+ if( pAct->IsClipping() )
+ ImplWriteRect( rOStm, aClipRect );
+
+ nCount++;
+ }
+ break;
+
+ case( META_ISECTRECTCLIPREGION_ACTION ):
+ {
+ MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction;
+
+ rOStm << (INT16) GDI_ISECTCLIPREGION_ACTION;
+ rOStm << (INT32) 20;
+ rOStm << pAct->GetRect();
+ nCount++;
+ }
+ break;
+
+ case( META_MOVECLIPREGION_ACTION ):
+ {
+ MetaMoveClipRegionAction* pAct = (MetaMoveClipRegionAction*) pAction;
+
+ rOStm << (INT16) GDI_MOVECLIPREGION_ACTION;
+ rOStm << (INT32) 12;
+ rOStm << (INT32) pAct->GetHorzMove();
+ rOStm << (INT32) pAct->GetVertMove();
+ nCount++;
+ }
+ break;
+
+ case( META_LINECOLOR_ACTION ):
+ {
+ MetaLineColorAction* pAct = (MetaLineColorAction*) pAction;
+ ImplWriteLineColor( rOStm, rLineCol = pAct->GetColor(), pAct->IsSetting() ? 1 : 0 );
+ nCount++;
+ }
+ break;
+
+ case( META_FILLCOLOR_ACTION ):
+ {
+ MetaFillColorAction* pAct = (MetaFillColorAction*) pAction;
+ ImplWriteFillColor( rOStm, pAct->GetColor(), pAct->IsSetting() ? 1 : 0 );
+ nCount++;
+ }
+ break;
+
+ case( META_FONT_ACTION ):
+ {
+ rSaveVDev.SetFont( ( (MetaFontAction*) pAction )->GetFont() );
+ ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
+ nCount++;
+ }
+ break;
+
+ case( META_TEXTCOLOR_ACTION ):
+ {
+ Font aSaveFont( rSaveVDev.GetFont() );
+
+ aSaveFont.SetColor( ( (MetaTextColorAction*) pAction )->GetColor() );
+ rSaveVDev.SetFont( aSaveFont );
+ ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
+ nCount++;
+ }
+ break;
+
+ case( META_TEXTFILLCOLOR_ACTION ):
+ {
+ MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction;
+ Font aSaveFont( rSaveVDev.GetFont() );
+
+ if( pAct->IsSetting() )
+ aSaveFont.SetFillColor( pAct->GetColor() );
+ else
+ aSaveFont.SetFillColor( Color( COL_TRANSPARENT ) );
+
+ rSaveVDev.SetFont( aSaveFont );
+ ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
+ nCount++;
+ }
+ break;
+
+ case( META_TEXTALIGN_ACTION ):
+ {
+ Font aSaveFont( rSaveVDev.GetFont() );
+
+ aSaveFont.SetAlign( ( (MetaTextAlignAction*) pAction )->GetTextAlign() );
+ rSaveVDev.SetFont( aSaveFont );
+ ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
+ nCount++;
+ }
+ break;
+
+ case( META_MAPMODE_ACTION ):
+ {
+ MetaMapModeAction* pAct = (MetaMapModeAction*) pAction;
+
+ rOStm << (INT16) GDI_MAPMODE_ACTION;
+ rOStm << (INT32) 30;
+ ImplWriteMapMode( rOStm, pAct->GetMapMode() );
+ nCount++;
+ }
+ break;
+
+ case( META_PUSH_ACTION ):
+ {
+ ImplWritePushAction( rOStm );
+ rLineColStack.Push( new Color( rLineCol ) );
+ rSaveVDev.Push();
+ nCount++;
+ }
+ break;
+
+ case( META_POP_ACTION ):
+ {
+ Color* pCol = (Color*) rLineColStack.Pop();
+
+ if( pCol )
+ {
+ rLineCol = *pCol;
+ delete pCol;
+ }
+
+ ImplWritePopAction( rOStm );
+ rSaveVDev.Pop();
+ nCount++;
+ }
+ break;
+
+ case( META_RASTEROP_ACTION ):
+ {
+ MetaRasterOpAction* pAct = (MetaRasterOpAction*) pAction;
+
+ if( ( pAct->GetRasterOp() != ROP_0 ) && ( pAct->GetRasterOp() != ROP_1 ) )
+ {
+ INT16 nRasterOp;
+
+ // Falls vorher ROP_0/1 gesetzt war, alten
+ // Zustand durch Pop erst wieder herstellen
+ if( rRop_0_1 )
+ {
+ ImplWritePopAction( rOStm );
+ rSaveVDev.Pop();
+ rRop_0_1 = FALSE;
+ nCount++;
+ }
+
+ switch( pAct->GetRasterOp() )
+ {
+ case( ROP_OVERPAINT ) : nRasterOp = 0; break;
+ case( ROP_XOR ) : nRasterOp = 4; break;
+ case( ROP_INVERT ): nRasterOp = 1; break;
+ default: nRasterOp = 0; break;
+ }
+
+ ImplWriteRasterOpAction( rOStm, nRasterOp );
+ nCount++;
+ }
+ else
+ {
+ ImplWritePushAction( rOStm );
+ rSaveVDev.Push();
+
+ if( pAct->GetRasterOp() == ROP_0 )
+ {
+ ImplWriteLineColor( rOStm, COL_BLACK, 1 );
+ ImplWriteFillColor( rOStm, COL_BLACK, 1 );
+ }
+ else
+ {
+ ImplWriteLineColor( rOStm, COL_WHITE, 1 );
+ ImplWriteFillColor( rOStm, COL_WHITE, 1 );
+ }
+
+ ImplWriteRasterOpAction( rOStm, 0 );
+ rRop_0_1 = TRUE;
+ nCount += 4;
+ }
+ }
+ break;
+
+ case( META_TRANSPARENT_ACTION ):
+ {
+ const PolyPolygon& rPolyPoly = ( (MetaTransparentAction*) pAction )->GetPolyPolygon();
+ const INT16 nTrans = ( (MetaTransparentAction*) pAction )->GetTransparence();
+ const INT16 nBrushStyle = ( nTrans < 38 ) ? 8 : ( nTrans < 63 ) ? 9 : 10;
+ ULONG nOldPos, nNewPos;
+
+ // write transparence comment
+ rOStm << (INT16) GDI_TRANSPARENT_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write comment data
+ rOStm << rPolyPoly;
+ rOStm << nTrans;
+ rOStm << (INT32) 15; // number of actions that follow this comment
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos );
+ rOStm.Seek( nNewPos );
+
+ {
+ // write actions for transparence
+ ImplWritePushAction( rOStm );
+ {
+ ImplWriteRasterOpAction( rOStm, 4 );
+ ImplWritePolyPolyAction( rOStm, rPolyPoly );
+
+ ImplWritePushAction( rOStm );
+ {
+ ImplWriteRasterOpAction( rOStm, 2 );
+ ImplWriteFillColor( rOStm, COL_BLACK, nBrushStyle );
+ ImplWritePolyPolyAction( rOStm, rPolyPoly );
+ }
+ ImplWritePopAction( rOStm );
+
+ ImplWriteRasterOpAction( rOStm, 4 );
+ ImplWritePolyPolyAction( rOStm, rPolyPoly );
+ }
+ ImplWritePopAction( rOStm );
+
+ ImplWritePushAction( rOStm );
+ {
+ ImplWriteFillColor( rOStm, Color(), 0 );
+ ImplWritePolyPolyAction( rOStm, rPolyPoly );
+ }
+ ImplWritePopAction( rOStm );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ nCount += 15;
+#endif
+ }
+
+ nCount++;
+ }
+ break;
+
+ case( META_FLOATTRANSPARENT_ACTION ):
+ {
+ const MetaFloatTransparentAction* pA = (MetaFloatTransparentAction*) pAction;
+ const GDIMetaFile& rTransMtf = pA->GetGDIMetaFile();
+ const Point& rPos = pA->GetPoint();
+ const Size& rSize = pA->GetSize();
+ const Gradient& rGradient = pA->GetGradient();
+ ULONG nOldPos, nNewPos;
+
+ // write RefPoint comment
+ rOStm << (INT16) GDI_FLOATTRANSPARENT_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write comment data
+ rOStm << rTransMtf << rPos << rSize << rGradient;
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos + 4 );
+ rOStm.Seek( ( nOldPos = nNewPos ) + 4 );
+
+ {
+ // write actions for float transparence
+ ULONG nAddCount;
+ GDIMetaFile aMtf( rTransMtf );
+ const Size aSrcSize( rTransMtf.GetPrefSize() );
+ Point aSrcPt( rTransMtf.GetPrefMapMode().GetOrigin() );
+ const double fScaleX = aSrcSize.Width() ? (double) rSize.Width() / aSrcSize.Width() : 1.0;
+ const double fScaleY = aSrcSize.Height() ? (double) rSize.Height() / aSrcSize.Height() : 1.0;
+ long nMoveX, nMoveY;
+
+ if( fScaleX != 1.0 || fScaleY != 1.0 )
+ {
+ aMtf.Scale( fScaleX, fScaleY );
+ aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
+ }
+
+ nMoveX = rPos.X() - aSrcPt.X(), nMoveY = rPos.Y() - aSrcPt.Y();
+
+ if( nMoveX || nMoveY )
+ aMtf.Move( nMoveX, nMoveY );
+
+ nAddCount = ImplWriteActions( rOStm, aMtf, rSaveVDev, rRop_0_1, rLineCol, rLineColStack, rActualCharSet );
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) nAddCount;
+ rOStm.Seek( nNewPos );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ nCount += nAddCount;
+#endif
+ }
+
+ nCount++;
+ }
+ break;
+
+ case( META_HATCH_ACTION ):
+ {
+ const MetaHatchAction* pA = (MetaHatchAction*) pAction;
+ const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
+ const Hatch& rHatch = pA->GetHatch();
+ ULONG nOldPos, nNewPos, nAddCount;
+
+ // write hatch comment
+ rOStm << (INT16) GDI_HATCH_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write comment data
+ rOStm << rPolyPoly;
+ rOStm << rHatch;
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos + 4 );
+ rOStm.Seek( ( nOldPos = nNewPos ) + 4 );
+
+ {
+ // write actions for hatch
+ VirtualDevice aVDev;
+ GDIMetaFile aTmpMtf;
+
+ aVDev.AddHatchActions( rPolyPoly, rHatch, aTmpMtf );
+ nAddCount = ImplWriteActions( rOStm, aTmpMtf, rSaveVDev, rRop_0_1, rLineCol, rLineColStack, rActualCharSet );
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) nAddCount;
+ rOStm.Seek( nNewPos );
+
+#ifdef CVTSVM_WRITE_SUBACTIONCOUNT
+ nCount += nAddCount;
+#endif
+ }
+
+ nCount++;
+ }
+ break;
+
+ case( META_REFPOINT_ACTION ):
+ {
+ const MetaRefPointAction* pA = (MetaRefPointAction*) pAction;
+ const Point& rRefPoint = pA->GetRefPoint();
+ const BOOL bSet = pA->IsSetting();
+ ULONG nOldPos, nNewPos;
+
+ // write RefPoint comment
+ rOStm << (INT16) GDI_REFPOINT_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write data
+ rOStm << rRefPoint << bSet;
+ rOStm << (INT32) 0; // number of actions that follow this comment
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos );
+ rOStm.Seek( nNewPos );
+
+ nCount++;
+ }
+ break;
+
+ case( META_TEXTLINECOLOR_ACTION ):
+ {
+ const MetaTextLineColorAction* pA = (MetaTextLineColorAction*) pAction;
+ const Color& rColor = pA->GetColor();
+ const BOOL bSet = pA->IsSetting();
+ ULONG nOldPos, nNewPos;
+
+ // write RefPoint comment
+ rOStm << (INT16) GDI_TEXTLINECOLOR_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write data
+ rOStm << rColor << bSet;
+ rOStm << (INT32) 0; // number of actions that follow this comment
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos );
+ rOStm.Seek( nNewPos );
+
+ nCount++;
+ }
+ break;
+
+#if 0
+ case( META_OVERLINECOLOR_ACTION ):
+ break;
+#endif
+
+ case( META_TEXTLINE_ACTION ):
+ {
+ const MetaTextLineAction* pA = (MetaTextLineAction*) pAction;
+ const Point& rStartPt = pA->GetStartPoint();
+ const long nWidth = pA->GetWidth();
+ const FontStrikeout eStrikeout = pA->GetStrikeout();
+ const FontUnderline eUnderline = pA->GetUnderline();
+ ULONG nOldPos, nNewPos;
+
+ // write RefPoint comment
+ rOStm << (INT16) GDI_TEXTLINE_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write data
+ rOStm << rStartPt << nWidth <<
+ static_cast<sal_uInt32>(eStrikeout) <<
+ static_cast<sal_uInt32>(eUnderline);
+ rOStm << (INT32) 0; // number of actions that follow this comment
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos );
+ rOStm.Seek( nNewPos );
+
+ nCount++;
+ }
+ break;
+
+ case( META_EPS_ACTION ):
+ break;
+
+ case( META_COMMENT_ACTION ):
+ {
+ const MetaCommentAction* pA = (MetaCommentAction*) pAction;
+ const sal_uInt32 nDataSize = pA->GetDataSize();
+ ULONG nOldPos, nNewPos;
+
+ // write RefPoint comment
+ rOStm << (INT16) GDI_COMMENT_COMMENT;
+
+ // we'll write the ActionSize later
+ nOldPos = rOStm.Tell();
+ rOStm.SeekRel( 4 );
+
+ // write data
+ rOStm << pA->GetComment() << pA->GetValue() << nDataSize;
+
+ if( nDataSize )
+ rOStm.Write( pA->GetData(), nDataSize );
+
+ rOStm << (INT32) 0; // number of actions that follow this comment
+
+ // calculate and write ActionSize of comment
+ nNewPos = rOStm.Tell();
+ rOStm.Seek( nOldPos );
+ rOStm << (INT32) ( nNewPos - nOldPos );
+ rOStm.Seek( nNewPos );
+
+ nCount++;
+ }
+ break;
+
+#ifdef DBG_UTIL
+ default:
+ {
+ ByteString aStr( "Missing implementation for Action#: " );
+ aStr += ByteString::CreateFromInt32( pAction->GetType() );
+ aStr += '!';
+ DBG_ERROR( aStr.GetBuffer() );
+ }
+ break;
+#endif
+
+/*
+ case( META_TEXTRECT_ACTION ):
+ {
+ MetaTextRectAction* pAct = (MetaTextRectAction*) pAction;
+
+ rOStm << ;
+ rOStm << ;
+
+ nCount++;
+ }
+ break;
+*/
+
+/*
+ case( META_MASK_ACTION ):
+ {
+ MetaMaskAction* pAct = (MetaMaskAction*) pAction;
+
+ rOStm << ;
+ rOStm << ;
+
+ nCount++;
+ }
+ break;
+*/
+
+/*
+ case( META_MASKSCALE_ACTION ):
+ {
+ MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
+
+ rOStm << ;
+ rOStm << ;
+
+ nCount++;
+ }
+ break;
+*/
+
+/*
+ case( META_MASKSCALEPART_ACTION ):
+ {
+ MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
+
+ rOStm << ;
+ rOStm << ;
+
+ nCount++;
+ }
+ break;
+*/
+
+/*
+ case( META_ISECTREGIONCLIPREGION_ACTION ):
+ {
+ MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction;
+
+ rOStm << ;
+ rOStm << ;
+
+ nCount++;
+ }
+ break;
+*/
+ }
+ }
+
+ return nCount;
+}
diff --git a/vcl/source/gdi/extoutdevdata.cxx b/vcl/source/gdi/extoutdevdata.cxx
new file mode 100644
index 000000000000..eebd6b35765b
--- /dev/null
+++ b/vcl/source/gdi/extoutdevdata.cxx
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/extoutdevdata.hxx>
+#include <tools/rtti.hxx>
+
+namespace vcl
+{
+
+TYPEINIT0(ExtOutDevData);
+ExtOutDevData::~ExtOutDevData()
+{
+}
+
+}
diff --git a/vcl/source/gdi/font.cxx b/vcl/source/gdi/font.cxx
new file mode 100644
index 000000000000..e26c15309c54
--- /dev/null
+++ b/vcl/source/gdi/font.cxx
@@ -0,0 +1,1116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "sft.hxx"
+
+#include "tools/stream.hxx"
+#include "tools/vcompat.hxx"
+#include "tools/debug.hxx"
+#include "vcl/font.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/outfont.hxx"
+#include "unotools/fontcfg.hxx"
+
+#include <algorithm>
+
+using namespace vcl;
+
+// =======================================================================
+
+DBG_NAME( Font )
+
+// -----------------------------------------------------------------------
+
+Impl_Font::Impl_Font() :
+ maColor( COL_TRANSPARENT ),
+ maFillColor( COL_TRANSPARENT )
+{
+ mnRefCount = 1;
+ meCharSet = RTL_TEXTENCODING_DONTKNOW;
+ meLanguage = LANGUAGE_DONTKNOW;
+ meCJKLanguage = LANGUAGE_DONTKNOW;
+ meFamily = FAMILY_DONTKNOW;
+ mePitch = PITCH_DONTKNOW;
+ meAlign = ALIGN_TOP;
+ meWeight = WEIGHT_DONTKNOW;
+ meWidthType = WIDTH_DONTKNOW;
+ meItalic = ITALIC_NONE;
+ meUnderline = UNDERLINE_NONE;
+ meOverline = UNDERLINE_NONE;
+ meStrikeout = STRIKEOUT_NONE;
+ meRelief = RELIEF_NONE;
+ meEmphasisMark = EMPHASISMARK_NONE;
+ mnOrientation = 0;
+ mnKerning = 0;
+ mbWordLine = false;
+ mbOutline = false;
+ mbShadow = false;
+ mbVertical = false;
+ mbTransparent = true;
+ mbConfigLookup = false;
+}
+
+// -----------------------------------------------------------------------
+
+Impl_Font::Impl_Font( const Impl_Font& rImplFont )
+: maFamilyName( rImplFont.maFamilyName ),
+ maStyleName( rImplFont.maStyleName ),
+ maSize( rImplFont.maSize ),
+ maColor( rImplFont.maColor ),
+ maFillColor( rImplFont.maFillColor )
+{
+ mnRefCount = 1;
+ meCharSet = rImplFont.meCharSet;
+ meLanguage = rImplFont.meLanguage;
+ meCJKLanguage = rImplFont.meCJKLanguage;
+ meFamily = rImplFont.meFamily;
+ mePitch = rImplFont.mePitch;
+ meAlign = rImplFont.meAlign;
+ meWeight = rImplFont.meWeight;
+ meWidthType = rImplFont.meWidthType;
+ meItalic = rImplFont.meItalic;
+ meUnderline = rImplFont.meUnderline;
+ meOverline = rImplFont.meOverline;
+ meStrikeout = rImplFont.meStrikeout;
+ meRelief = rImplFont.meRelief;
+ meEmphasisMark = rImplFont.meEmphasisMark;
+ mnOrientation = rImplFont.mnOrientation;
+ mnKerning = rImplFont.mnKerning;
+ mbWordLine = rImplFont.mbWordLine;
+ mbOutline = rImplFont.mbOutline;
+ mbShadow = rImplFont.mbShadow;
+ mbVertical = rImplFont.mbVertical;
+ mbTransparent = rImplFont.mbTransparent;
+ mbConfigLookup = rImplFont.mbConfigLookup;
+}
+
+// -----------------------------------------------------------------------
+
+bool Impl_Font::operator==( const Impl_Font& rOther ) const
+{
+ // equality tests split up for easier debugging
+ if( (meWeight != rOther.meWeight)
+ || (meItalic != rOther.meItalic)
+ || (meFamily != rOther.meFamily)
+ || (mePitch != rOther.mePitch) )
+ return false;
+
+ if( (meCharSet != rOther.meCharSet)
+ || (meLanguage != rOther.meLanguage)
+ || (meCJKLanguage != rOther.meCJKLanguage)
+ || (meAlign != rOther.meAlign) )
+ return false;
+
+ if( (maSize != rOther.maSize)
+ || (mnOrientation != rOther.mnOrientation)
+ || (mbVertical != rOther.mbVertical) )
+ return false;
+
+ if( (maFamilyName != rOther.maFamilyName)
+ || (maStyleName != rOther.maStyleName) )
+ return false;
+
+ if( (maColor != rOther.maColor)
+ || (maFillColor != rOther.maFillColor) )
+ return false;
+
+ if( (meUnderline != rOther.meUnderline)
+ || (meOverline != rOther.meOverline)
+ || (meStrikeout != rOther.meStrikeout)
+ || (meRelief != rOther.meRelief)
+ || (meEmphasisMark != rOther.meEmphasisMark)
+ || (mbWordLine != rOther.mbWordLine)
+ || (mbOutline != rOther.mbOutline)
+ || (mbShadow != rOther.mbShadow)
+ || (mnKerning != rOther.mnKerning)
+ || (mbTransparent != rOther.mbTransparent) )
+ return false;
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void Impl_Font::AskConfig()
+{
+ if( mbConfigLookup )
+ return;
+
+ mbConfigLookup = true;
+
+ // prepare the FontSubst configuration lookup
+ const utl::FontSubstConfiguration* pFontSubst = utl::FontSubstConfiguration::get();
+
+ String aShortName;
+ String aFamilyName;
+ ULONG nType = 0;
+ FontWeight eWeight = WEIGHT_DONTKNOW;
+ FontWidth eWidthType = WIDTH_DONTKNOW;
+ String aMapName = maFamilyName;
+ GetEnglishSearchFontName( aMapName );
+ utl::FontSubstConfiguration::getMapName( aMapName,
+ aShortName, aFamilyName, eWeight, eWidthType, nType );
+
+ // lookup the font name in the configuration
+ const utl::FontNameAttr* pFontAttr = pFontSubst->getSubstInfo( aMapName );
+
+ // if the direct lookup failed try again with an alias name
+ if ( !pFontAttr && (aShortName != aMapName) )
+ pFontAttr = pFontSubst->getSubstInfo( aShortName );
+
+ if( pFontAttr )
+ {
+ // the font was found in the configuration
+ if( meFamily == FAMILY_DONTKNOW )
+ {
+ if ( pFontAttr->Type & IMPL_FONT_ATTR_SERIF )
+ meFamily = FAMILY_ROMAN;
+ else if ( pFontAttr->Type & IMPL_FONT_ATTR_SANSSERIF )
+ meFamily = FAMILY_SWISS;
+ else if ( pFontAttr->Type & IMPL_FONT_ATTR_TYPEWRITER )
+ meFamily = FAMILY_MODERN;
+ else if ( pFontAttr->Type & IMPL_FONT_ATTR_ITALIC )
+ meFamily = FAMILY_SCRIPT;
+ else if ( pFontAttr->Type & IMPL_FONT_ATTR_DECORATIVE )
+ meFamily = FAMILY_DECORATIVE;
+ }
+
+ if( mePitch == PITCH_DONTKNOW )
+ {
+ if ( pFontAttr->Type & IMPL_FONT_ATTR_FIXED )
+ mePitch = PITCH_FIXED;
+ }
+ }
+
+ // if some attributes are still unknown then use the FontSubst magic
+ if( meFamily == FAMILY_DONTKNOW )
+ {
+ if( nType & IMPL_FONT_ATTR_SERIF )
+ meFamily = FAMILY_ROMAN;
+ else if( nType & IMPL_FONT_ATTR_SANSSERIF )
+ meFamily = FAMILY_SWISS;
+ else if( nType & IMPL_FONT_ATTR_TYPEWRITER )
+ meFamily = FAMILY_MODERN;
+ else if( nType & IMPL_FONT_ATTR_ITALIC )
+ meFamily = FAMILY_SCRIPT;
+ else if( nType & IMPL_FONT_ATTR_DECORATIVE )
+ meFamily = FAMILY_DECORATIVE;
+ }
+
+ if( meWeight == WEIGHT_DONTKNOW )
+ meWeight = eWeight;
+ if( meWidthType == WIDTH_DONTKNOW )
+ meWidthType = eWidthType;
+}
+
+// =======================================================================
+
+void Font::MakeUnique()
+{
+ // create a copy if others still reference it
+ if ( mpImplFont->mnRefCount != 1 )
+ {
+ if ( mpImplFont->mnRefCount )
+ mpImplFont->mnRefCount--;
+ mpImplFont = new Impl_Font( *mpImplFont );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Font::Font()
+{
+ DBG_CTOR( Font, NULL );
+
+ static Impl_Font aStaticImplFont;
+ // RefCount is zero for static objects
+ aStaticImplFont.mnRefCount = 0;
+ mpImplFont = &aStaticImplFont;
+}
+
+// -----------------------------------------------------------------------
+
+Font::Font( const Font& rFont )
+{
+ DBG_CTOR( Font, NULL );
+ DBG_CHKOBJ( &rFont, Font, NULL );
+ DBG_ASSERT( rFont.mpImplFont->mnRefCount < 0xFFFE, "Font: RefCount overflow" );
+
+ mpImplFont = rFont.mpImplFont;
+ // do not count static objects (where RefCount is zero)
+ if ( mpImplFont->mnRefCount )
+ mpImplFont->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+Font::Font( const String& rFamilyName, const Size& rSize )
+{
+ DBG_CTOR( Font, NULL );
+
+ mpImplFont = new Impl_Font;
+ mpImplFont->maFamilyName= rFamilyName;
+ mpImplFont->maSize = rSize;
+}
+
+// -----------------------------------------------------------------------
+
+Font::Font( const String& rFamilyName, const String& rStyleName, const Size& rSize )
+{
+ DBG_CTOR( Font, NULL );
+
+ mpImplFont = new Impl_Font;
+ mpImplFont->maFamilyName= rFamilyName;
+ mpImplFont->maStyleName = rStyleName;
+ mpImplFont->maSize = rSize;
+}
+
+// -----------------------------------------------------------------------
+
+Font::Font( FontFamily eFamily, const Size& rSize )
+{
+ DBG_CTOR( Font, NULL );
+
+ mpImplFont = new Impl_Font;
+ mpImplFont->meFamily = eFamily;
+ mpImplFont->maSize = rSize;
+}
+
+// -----------------------------------------------------------------------
+
+Font::~Font()
+{
+ DBG_DTOR( Font, NULL );
+
+ // decrement reference counter and delete if last reference
+ // if the object is not static (Refcounter==0)
+ if ( mpImplFont->mnRefCount )
+ {
+ if ( mpImplFont->mnRefCount == 1 )
+ delete mpImplFont;
+ else
+ mpImplFont->mnRefCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetColor( const Color& rColor )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->maColor != rColor )
+ {
+ MakeUnique();
+ mpImplFont->maColor = rColor;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetFillColor( const Color& rColor )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ MakeUnique();
+ mpImplFont->maFillColor = rColor;
+ if ( rColor.GetTransparency() )
+ mpImplFont->mbTransparent = true;
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetTransparent( BOOL bTransparent )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mbTransparent != bTransparent )
+ {
+ MakeUnique();
+ mpImplFont->mbTransparent = bTransparent;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetAlign( FontAlign eAlign )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meAlign != eAlign )
+ {
+ MakeUnique();
+ mpImplFont->meAlign = eAlign;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetName( const String& rFamilyName )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ MakeUnique();
+ mpImplFont->maFamilyName = rFamilyName;
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetStyleName( const String& rStyleName )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ MakeUnique();
+ mpImplFont->maStyleName = rStyleName;
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetSize( const Size& rSize )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->maSize != rSize )
+ {
+ MakeUnique();
+ mpImplFont->maSize = rSize;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetFamily( FontFamily eFamily )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meFamily != eFamily )
+ {
+ MakeUnique();
+ mpImplFont->meFamily = eFamily;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetCharSet( CharSet eCharSet )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meCharSet != eCharSet )
+ {
+ MakeUnique();
+ mpImplFont->meCharSet = eCharSet;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetLanguage( LanguageType eLanguage )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meLanguage != eLanguage )
+ {
+ MakeUnique();
+ mpImplFont->meLanguage = eLanguage;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetCJKContextLanguage( LanguageType eLanguage )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meCJKLanguage != eLanguage )
+ {
+ MakeUnique();
+ mpImplFont->meCJKLanguage = eLanguage;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetPitch( FontPitch ePitch )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mePitch != ePitch )
+ {
+ MakeUnique();
+ mpImplFont->mePitch = ePitch;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetOrientation( short nOrientation )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mnOrientation != nOrientation )
+ {
+ MakeUnique();
+ mpImplFont->mnOrientation = nOrientation;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetVertical( BOOL bVertical )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mbVertical != bVertical )
+ {
+ MakeUnique();
+ mpImplFont->mbVertical = bVertical;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetKerning( FontKerning nKerning )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mnKerning != nKerning )
+ {
+ MakeUnique();
+ mpImplFont->mnKerning = nKerning;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Font::IsKerning() const
+{
+ return (mpImplFont->mnKerning & KERNING_FONTSPECIFIC) != 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetWeight( FontWeight eWeight )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meWeight != eWeight )
+ {
+ MakeUnique();
+ mpImplFont->meWeight = eWeight;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetWidthType( FontWidth eWidth )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meWidthType != eWidth )
+ {
+ MakeUnique();
+ mpImplFont->meWidthType = eWidth;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetItalic( FontItalic eItalic )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meItalic != eItalic )
+ {
+ MakeUnique();
+ mpImplFont->meItalic = eItalic;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetOutline( BOOL bOutline )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mbOutline != bOutline )
+ {
+ MakeUnique();
+ mpImplFont->mbOutline = bOutline;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetShadow( BOOL bShadow )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mbShadow != bShadow )
+ {
+ MakeUnique();
+ mpImplFont->mbShadow = bShadow;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetUnderline( FontUnderline eUnderline )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meUnderline != eUnderline )
+ {
+ MakeUnique();
+ mpImplFont->meUnderline = eUnderline;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetOverline( FontUnderline eOverline )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meOverline != eOverline )
+ {
+ MakeUnique();
+ mpImplFont->meOverline = eOverline;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetStrikeout( FontStrikeout eStrikeout )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meStrikeout != eStrikeout )
+ {
+ MakeUnique();
+ mpImplFont->meStrikeout = eStrikeout;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetRelief( FontRelief eRelief )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meRelief != eRelief )
+ {
+ MakeUnique();
+ mpImplFont->meRelief = eRelief;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetEmphasisMark( FontEmphasisMark eEmphasisMark )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->meEmphasisMark != eEmphasisMark )
+ {
+ MakeUnique();
+ mpImplFont->meEmphasisMark = eEmphasisMark;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Font::SetWordLineMode( BOOL bWordLine )
+{
+ DBG_CHKTHIS( Font, NULL );
+
+ if( mpImplFont->mbWordLine != bWordLine )
+ {
+ MakeUnique();
+ mpImplFont->mbWordLine = bWordLine;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Font& Font::operator=( const Font& rFont )
+{
+ DBG_CHKTHIS( Font, NULL );
+ DBG_CHKOBJ( &rFont, Font, NULL );
+ DBG_ASSERT( rFont.mpImplFont->mnRefCount < 0xFFFE, "Font: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ // RefCount == 0 fuer statische Objekte
+ if ( rFont.mpImplFont->mnRefCount )
+ rFont.mpImplFont->mnRefCount++;
+
+ // Wenn es keine statischen ImplDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpImplFont->mnRefCount )
+ {
+ if ( mpImplFont->mnRefCount == 1 )
+ delete mpImplFont;
+ else
+ mpImplFont->mnRefCount--;
+ }
+
+ mpImplFont = rFont.mpImplFont;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Font::operator==( const Font& rFont ) const
+{
+ DBG_CHKTHIS( Font, NULL );
+ DBG_CHKOBJ( &rFont, Font, NULL );
+
+ if( mpImplFont == rFont.mpImplFont )
+ return TRUE;
+ if( *mpImplFont == *rFont.mpImplFont )
+ return TRUE;
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Font::Merge( const Font& rFont )
+{
+ if ( rFont.GetName().Len() )
+ {
+ SetName( rFont.GetName() );
+ SetStyleName( rFont.GetStyleName() );
+ SetCharSet( GetCharSet() );
+ SetLanguage( rFont.GetLanguage() );
+ SetCJKContextLanguage( rFont.GetCJKContextLanguage() );
+ // don't use access methods here, might lead to AskConfig(), if DONTKNOW
+ SetFamily( rFont.mpImplFont->meFamily );
+ SetPitch( rFont.mpImplFont->mePitch );
+ }
+
+ // don't use access methods here, might lead to AskConfig(), if DONTKNOW
+ if ( rFont.mpImplFont->meWeight != WEIGHT_DONTKNOW )
+ SetWeight( rFont.GetWeight() );
+ if ( rFont.mpImplFont->meItalic != ITALIC_DONTKNOW )
+ SetItalic( rFont.GetItalic() );
+ if ( rFont.mpImplFont->meWidthType != WIDTH_DONTKNOW )
+ SetWidthType( rFont.GetWidthType() );
+
+
+ if ( rFont.GetSize().Height() )
+ SetSize( rFont.GetSize() );
+ if ( rFont.GetUnderline() != UNDERLINE_DONTKNOW )
+ {
+ SetUnderline( rFont.GetUnderline() );
+ SetWordLineMode( rFont.IsWordLineMode() );
+ }
+ if ( rFont.GetOverline() != UNDERLINE_DONTKNOW )
+ {
+ SetOverline( rFont.GetOverline() );
+ SetWordLineMode( rFont.IsWordLineMode() );
+ }
+ if ( rFont.GetStrikeout() != STRIKEOUT_DONTKNOW )
+ {
+ SetStrikeout( rFont.GetStrikeout() );
+ SetWordLineMode( rFont.IsWordLineMode() );
+ }
+
+ // Defaults?
+ SetOrientation( rFont.GetOrientation() );
+ SetVertical( rFont.IsVertical() );
+ SetEmphasisMark( rFont.GetEmphasisMark() );
+ SetKerning( rFont.IsKerning() );
+ SetOutline( rFont.IsOutline() );
+ SetShadow( rFont.IsShadow() );
+ SetRelief( rFont.GetRelief() );
+}
+
+void Font::GetFontAttributes( ImplFontAttributes& rAttrs ) const
+{
+ // #i56788# Use members directly, don't risc config access.
+ rAttrs.maName = mpImplFont->maFamilyName;
+ rAttrs.maStyleName = mpImplFont->maStyleName;
+ rAttrs.meFamily = mpImplFont->meFamily;
+ rAttrs.mePitch = mpImplFont->mePitch;
+ rAttrs.meItalic = mpImplFont->meItalic;
+ rAttrs.meWeight = mpImplFont->meWeight;
+ rAttrs.meWidthType = WIDTH_DONTKNOW;
+ rAttrs.mbSymbolFlag= (mpImplFont->meCharSet == RTL_TEXTENCODING_SYMBOL);
+}
+
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, Impl_Font& rImpl_Font )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+ UINT16 nTmp16;
+ BOOL bTmp;
+ BYTE nTmp8;
+
+ rIStm.ReadByteString( rImpl_Font.maFamilyName, rIStm.GetStreamCharSet() );
+ rIStm.ReadByteString( rImpl_Font.maStyleName, rIStm.GetStreamCharSet() );
+ rIStm >> rImpl_Font.maSize;
+
+ rIStm >> nTmp16; rImpl_Font.meCharSet = (rtl_TextEncoding) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.meFamily = (FontFamily) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.mePitch = (FontPitch) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.meWeight = (FontWeight) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.meUnderline = (FontUnderline) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.meStrikeout = (FontStrikeout) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.meItalic = (FontItalic) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.meLanguage = (LanguageType) nTmp16;
+ rIStm >> nTmp16; rImpl_Font.meWidthType = (FontWidth) nTmp16;
+
+ rIStm >> rImpl_Font.mnOrientation;
+
+ rIStm >> bTmp; rImpl_Font.mbWordLine = bTmp;
+ rIStm >> bTmp; rImpl_Font.mbOutline = bTmp;
+ rIStm >> bTmp; rImpl_Font.mbShadow = bTmp;
+ rIStm >> nTmp8; rImpl_Font.mnKerning = nTmp8;
+
+ if( aCompat.GetVersion() >= 2 )
+ {
+ rIStm >> nTmp8; rImpl_Font.meRelief = (FontRelief)nTmp8;
+ rIStm >> nTmp16; rImpl_Font.meCJKLanguage = (LanguageType)nTmp16;
+ rIStm >> bTmp; rImpl_Font.mbVertical = bTmp;
+ rIStm >> nTmp16; rImpl_Font.meEmphasisMark = (FontEmphasisMark)nTmp16;
+ }
+ if( aCompat.GetVersion() >= 3 )
+ {
+ rIStm >> nTmp16; rImpl_Font.meOverline = (FontUnderline) nTmp16;
+ }
+ // Relief
+ // CJKContextLanguage
+
+ return rIStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Impl_Font& rImpl_Font )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 3 );
+ rOStm.WriteByteString( rImpl_Font.maFamilyName, rOStm.GetStreamCharSet() );
+ rOStm.WriteByteString( rImpl_Font.maStyleName, rOStm.GetStreamCharSet() );
+ rOStm << rImpl_Font.maSize;
+
+ rOStm << (UINT16) GetStoreCharSet( rImpl_Font.meCharSet );
+ rOStm << (UINT16) rImpl_Font.meFamily;
+ rOStm << (UINT16) rImpl_Font.mePitch;
+ rOStm << (UINT16) rImpl_Font.meWeight;
+ rOStm << (UINT16) rImpl_Font.meUnderline;
+ rOStm << (UINT16) rImpl_Font.meStrikeout;
+ rOStm << (UINT16) rImpl_Font.meItalic;
+ rOStm << (UINT16) rImpl_Font.meLanguage;
+ rOStm << (UINT16) rImpl_Font.meWidthType;
+
+ rOStm << rImpl_Font.mnOrientation;
+
+ rOStm << (BOOL) rImpl_Font.mbWordLine;
+ rOStm << (BOOL) rImpl_Font.mbOutline;
+ rOStm << (BOOL) rImpl_Font.mbShadow;
+ rOStm << (BYTE) rImpl_Font.mnKerning;
+
+ // new in version 2
+ rOStm << (BYTE) rImpl_Font.meRelief;
+ rOStm << (UINT16) rImpl_Font.meCJKLanguage;
+ rOStm << (BOOL) rImpl_Font.mbVertical;
+ rOStm << (UINT16) rImpl_Font.meEmphasisMark;
+
+ // new in version 3
+ rOStm << (UINT16) rImpl_Font.meOverline;
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, Font& rFont )
+{
+ rFont.MakeUnique();
+ return( rIStm >> *rFont.mpImplFont );
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Font& rFont )
+{
+ return( rOStm << *rFont.mpImplFont );
+}
+
+// -----------------------------------------------------------------------
+namespace
+{
+ bool identifyTrueTypeFont( const void* i_pBuffer, sal_uInt32 i_nSize, Font& o_rResult )
+ {
+ bool bResult = false;
+// FIXME: This is HACK. We do not build psprint's part on aqua...
+// How to solve this?
+#ifndef QUARTZ
+ TrueTypeFont* pTTF = NULL;
+ if( OpenTTFontBuffer( const_cast<void*>(i_pBuffer), i_nSize, 0, &pTTF ) == SF_OK )
+ {
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTF, &aInfo );
+ // most important: the family name
+ if( aInfo.ufamily )
+ o_rResult.SetName( aInfo.ufamily );
+ else if( aInfo.family )
+ o_rResult.SetName( rtl::OStringToOUString( aInfo.family, RTL_TEXTENCODING_ASCII_US ) );
+ // set weight
+ if( aInfo.weight )
+ {
+ if( aInfo.weight < FW_EXTRALIGHT )
+ o_rResult.SetWeight( WEIGHT_THIN );
+ else if( aInfo.weight < FW_LIGHT )
+ o_rResult.SetWeight( WEIGHT_ULTRALIGHT );
+ else if( aInfo.weight < FW_NORMAL )
+ o_rResult.SetWeight( WEIGHT_LIGHT );
+ else if( aInfo.weight < FW_MEDIUM )
+ o_rResult.SetWeight( WEIGHT_NORMAL );
+ else if( aInfo.weight < FW_SEMIBOLD )
+ o_rResult.SetWeight( WEIGHT_MEDIUM );
+ else if( aInfo.weight < FW_BOLD )
+ o_rResult.SetWeight( WEIGHT_SEMIBOLD );
+ else if( aInfo.weight < FW_EXTRABOLD )
+ o_rResult.SetWeight( WEIGHT_BOLD );
+ else if( aInfo.weight < FW_BLACK )
+ o_rResult.SetWeight( WEIGHT_ULTRABOLD );
+ else
+ o_rResult.SetWeight( WEIGHT_BLACK );
+ }
+ else
+ o_rResult.SetWeight( (aInfo.macStyle & 1) ? WEIGHT_BOLD : WEIGHT_NORMAL );
+ // set width
+ if( aInfo.width )
+ {
+ if( aInfo.width == FWIDTH_ULTRA_CONDENSED )
+ o_rResult.SetWidth( WIDTH_ULTRA_CONDENSED );
+ else if( aInfo.width == FWIDTH_EXTRA_CONDENSED )
+ o_rResult.SetWidth( WIDTH_EXTRA_CONDENSED );
+ else if( aInfo.width == FWIDTH_CONDENSED )
+ o_rResult.SetWidth( WIDTH_CONDENSED );
+ else if( aInfo.width == FWIDTH_SEMI_CONDENSED )
+ o_rResult.SetWidth( WIDTH_SEMI_CONDENSED );
+ else if( aInfo.width == FWIDTH_NORMAL )
+ o_rResult.SetWidth( WIDTH_NORMAL );
+ else if( aInfo.width == FWIDTH_SEMI_EXPANDED )
+ o_rResult.SetWidth( WIDTH_SEMI_EXPANDED );
+ else if( aInfo.width == FWIDTH_EXPANDED )
+ o_rResult.SetWidth( WIDTH_EXPANDED );
+ else if( aInfo.width == FWIDTH_EXTRA_EXPANDED )
+ o_rResult.SetWidth( WIDTH_EXTRA_EXPANDED );
+ else if( aInfo.width >= FWIDTH_ULTRA_EXPANDED )
+ o_rResult.SetWidth( WIDTH_ULTRA_EXPANDED );
+ }
+ // set italic
+ o_rResult.SetItalic( (aInfo.italicAngle != 0) ? ITALIC_NORMAL : ITALIC_NONE );
+
+ // set pitch
+ o_rResult.SetPitch( (aInfo.pitch == 0) ? PITCH_VARIABLE : PITCH_FIXED );
+
+ // set style name
+ if( aInfo.usubfamily )
+ o_rResult.SetStyleName( rtl::OUString( aInfo.usubfamily ) );
+ else if( aInfo.subfamily )
+ o_rResult.SetStyleName( rtl::OUString::createFromAscii( aInfo.subfamily ) );
+
+ // cleanup
+ CloseTTFont( pTTF );
+ // success
+ bResult = true;
+ }
+#endif
+ return bResult;
+ }
+
+ struct WeightSearchEntry
+ {
+ const char* string;
+ int string_len;
+ FontWeight weight;
+
+ bool operator<( const WeightSearchEntry& rRight ) const
+ {
+ return rtl_str_compareIgnoreAsciiCase_WithLength( string, string_len, rRight.string, rRight.string_len ) < 0;
+ }
+ }
+ weight_table[] =
+ {
+ { "black", 5, WEIGHT_BLACK },
+ { "bold", 4, WEIGHT_BOLD },
+ { "book", 4, WEIGHT_LIGHT },
+ { "demi", 4, WEIGHT_SEMIBOLD },
+ { "heavy", 5, WEIGHT_BLACK },
+ { "light", 5, WEIGHT_LIGHT },
+ { "medium", 6, WEIGHT_MEDIUM },
+ { "regular", 7, WEIGHT_NORMAL },
+ { "super", 5, WEIGHT_ULTRABOLD },
+ { "thin", 4, WEIGHT_THIN }
+ };
+
+ bool identifyType1Font( const char* i_pBuffer, sal_uInt32 i_nSize, Font& o_rResult )
+ {
+ bool bResult = false;
+ // might be a type1, find eexec
+ const char* pStream = i_pBuffer;
+ const char* pExec = "eexec";
+ const char* pExecPos = std::search( pStream, pStream+i_nSize, pExec, pExec+5 );
+ if( pExecPos != pStream+i_nSize)
+ {
+ // find /FamilyName entry
+ static const char* pFam = "/FamilyName";
+ const char* pFamPos = std::search( pStream, pExecPos, pFam, pFam+11 );
+ if( pFamPos != pExecPos )
+ {
+ // extract the string value behind /FamilyName
+ const char* pOpen = pFamPos+11;
+ while( pOpen < pExecPos && *pOpen != '(' )
+ pOpen++;
+ const char* pClose = pOpen;
+ while( pClose < pExecPos && *pClose != ')' )
+ pClose++;
+ if( pClose - pOpen > 1 )
+ {
+ o_rResult.SetName( rtl::OStringToOUString( rtl::OString( pOpen+1, pClose-pOpen-1 ), RTL_TEXTENCODING_ASCII_US ) );
+ }
+ }
+
+ // parse /ItalicAngle
+ static const char* pItalic = "/ItalicAngle";
+ const char* pItalicPos = std::search( pStream, pExecPos, pItalic, pItalic+12 );
+ if( pItalicPos != pExecPos )
+ {
+ sal_Int32 nItalic = rtl_str_toInt32( pItalicPos+12, 10 );
+ o_rResult.SetItalic( (nItalic != 0) ? ITALIC_NORMAL : ITALIC_NONE );
+ }
+
+ // parse /Weight
+ static const char* pWeight = "/Weight";
+ const char* pWeightPos = std::search( pStream, pExecPos, pWeight, pWeight+7 );
+ if( pWeightPos != pExecPos )
+ {
+ // extract the string value behind /Weight
+ const char* pOpen = pWeightPos+7;
+ while( pOpen < pExecPos && *pOpen != '(' )
+ pOpen++;
+ const char* pClose = pOpen;
+ while( pClose < pExecPos && *pClose != ')' )
+ pClose++;
+ if( pClose - pOpen > 1 )
+ {
+ WeightSearchEntry aEnt;
+ aEnt.string = pOpen+1;
+ aEnt.string_len = (pClose-pOpen)-1;
+ aEnt.weight = WEIGHT_NORMAL;
+ const int nEnt = sizeof( weight_table ) / sizeof( weight_table[0] );
+ WeightSearchEntry* pFound = std::lower_bound( weight_table, weight_table+nEnt, aEnt );
+ if( pFound != (weight_table+nEnt) )
+ o_rResult.SetWeight( pFound->weight );
+ }
+ }
+
+ // parse isFixedPitch
+ static const char* pFixed = "/isFixedPitch";
+ const char* pFixedPos = std::search( pStream, pExecPos, pFixed, pFixed+13 );
+ if( pFixedPos != pExecPos )
+ {
+ // skip whitespace
+ while( pFixedPos < pExecPos-4 &&
+ ( *pFixedPos == ' ' ||
+ *pFixedPos == '\t' ||
+ *pFixedPos == '\r' ||
+ *pFixedPos == '\n' ) )
+ {
+ pFixedPos++;
+ }
+ // find "true" value
+ if( rtl_str_compareIgnoreAsciiCase_WithLength( pFixedPos, 4, "true", 4 ) == 0 )
+ o_rResult.SetPitch( PITCH_FIXED );
+ else
+ o_rResult.SetPitch( PITCH_VARIABLE );
+ }
+ }
+ return bResult;
+ }
+}
+
+Font Font::identifyFont( const void* i_pBuffer, sal_uInt32 i_nSize )
+{
+ Font aResult;
+ if( ! identifyTrueTypeFont( i_pBuffer, i_nSize, aResult ) )
+ {
+ const char* pStream = reinterpret_cast<const char*>(i_pBuffer);
+ if( pStream && i_nSize > 100 &&
+ *pStream == '%' && pStream[1] == '!' )
+ {
+ identifyType1Font( pStream, i_nSize, aResult );
+ }
+ }
+
+ return aResult;
+}
+
+// the inlines from the font.hxx header are now instantiated for pImpl-ification
+// TODO: reformat
+const Color& Font::GetColor() const { return mpImplFont->maColor; }
+const Color& Font::GetFillColor() const { return mpImplFont->maFillColor; }
+BOOL Font::IsTransparent() const { return mpImplFont->mbTransparent; }
+FontAlign Font::GetAlign() const { return mpImplFont->meAlign; }
+const String& Font::GetName() const { return mpImplFont->maFamilyName; }
+const String& Font::GetStyleName() const { return mpImplFont->maStyleName; }
+const Size& Font::GetSize() const { return mpImplFont->maSize; }
+void Font::SetHeight( long nHeight ) { SetSize( Size( mpImplFont->maSize.Width(), nHeight ) ); }
+long Font::GetHeight() const { return mpImplFont->maSize.Height(); }
+void Font::SetWidth( long nWidth ) { SetSize( Size( nWidth, mpImplFont->maSize.Height() ) ); }
+long Font::GetWidth() const { return mpImplFont->maSize.Width(); }
+rtl_TextEncoding Font::GetCharSet() const { return mpImplFont->meCharSet; }
+LanguageType Font::GetLanguage() const { return mpImplFont->meLanguage; }
+LanguageType Font::GetCJKContextLanguage() const { return mpImplFont->meCJKLanguage; }
+short Font::GetOrientation() const { return mpImplFont->mnOrientation; }
+BOOL Font::IsVertical() const { return mpImplFont->mbVertical; }
+FontKerning Font::GetKerning() const { return mpImplFont->mnKerning; }
+FontPitch Font::GetPitch() const { return mpImplFont->GetPitch(); }
+FontWeight Font::GetWeight() const { return mpImplFont->GetWeight(); }
+FontWidth Font::GetWidthType() const { return mpImplFont->GetWidthType(); }
+FontItalic Font::GetItalic() const { return mpImplFont->GetItalic(); }
+FontFamily Font::GetFamily() const { return mpImplFont->GetFamily(); }
+BOOL Font::IsOutline() const { return mpImplFont->mbOutline; }
+BOOL Font::IsShadow() const { return mpImplFont->mbShadow; }
+FontRelief Font::GetRelief() const { return mpImplFont->meRelief; }
+FontUnderline Font::GetUnderline() const { return mpImplFont->meUnderline; }
+FontUnderline Font::GetOverline() const { return mpImplFont->meOverline; }
+FontStrikeout Font::GetStrikeout() const { return mpImplFont->meStrikeout; }
+FontEmphasisMark Font::GetEmphasisMark() const { return mpImplFont->meEmphasisMark; }
+BOOL Font::IsWordLineMode() const { return mpImplFont->mbWordLine; }
+BOOL Font::IsSameInstance( const Font& rFont ) const { return (mpImplFont == rFont.mpImplFont); }
diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
new file mode 100644
index 000000000000..01b34286a086
--- /dev/null
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -0,0 +1,2990 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vos/macros.hxx>
+#include <rtl/crc.h>
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/window.hxx>
+#ifndef _SV_CVTSVM_HXX
+#include <vcl/cvtsvm.hxx>
+#endif
+#include <vcl/virdev.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/graphictools.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define GAMMA( _def_cVal, _def_InvGamma ) ((BYTE)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
+
+// --------------------------
+// - Color exchange structs -
+// --------------------------
+
+struct ImplColAdjustParam
+{
+ BYTE* pMapR;
+ BYTE* pMapG;
+ BYTE* pMapB;
+};
+
+struct ImplBmpAdjustParam
+{
+ short nLuminancePercent;
+ short nContrastPercent;
+ short nChannelRPercent;
+ short nChannelGPercent;
+ short nChannelBPercent;
+ double fGamma;
+ BOOL bInvert;
+};
+
+// -----------------------------------------------------------------------------
+
+struct ImplColConvertParam
+{
+ MtfConversion eConversion;
+};
+
+struct ImplBmpConvertParam
+{
+ BmpConversion eConversion;
+};
+
+// -----------------------------------------------------------------------------
+
+struct ImplColMonoParam
+{
+ Color aColor;
+};
+
+struct ImplBmpMonoParam
+{
+ Color aColor;
+};
+
+// -----------------------------------------------------------------------------
+
+struct ImplColReplaceParam
+{
+ ULONG* pMinR;
+ ULONG* pMaxR;
+ ULONG* pMinG;
+ ULONG* pMaxG;
+ ULONG* pMinB;
+ ULONG* pMaxB;
+ const Color* pDstCols;
+ ULONG nCount;
+};
+
+struct ImplBmpReplaceParam
+{
+ const Color* pSrcCols;
+ const Color* pDstCols;
+ ULONG nCount;
+ const ULONG* pTols;
+};
+
+
+// ---------
+// - Label -
+// ---------
+
+struct ImpLabel
+{
+ String aLabelName;
+ ULONG nActionPos;
+
+ ImpLabel( const String& rLabelName, ULONG _nActionPos ) :
+ aLabelName( rLabelName ),
+ nActionPos( _nActionPos ) {}
+};
+
+// -------------
+// - LabelList -
+// -------------
+
+class ImpLabelList : private List
+{
+public:
+
+ ImpLabelList() : List( 8, 4, 4 ) {}
+ ImpLabelList( const ImpLabelList& rList );
+ ~ImpLabelList();
+
+ void ImplInsert( ImpLabel* p ) { Insert( p, LIST_APPEND ); }
+ ImpLabel* ImplRemove( ULONG nPos ) { return (ImpLabel*) Remove( nPos ); }
+ void ImplReplace( ImpLabel* p ) { Replace( (void*)p ); }
+ ImpLabel* ImplFirst() { return (ImpLabel*) First(); }
+ ImpLabel* ImplNext() { return (ImpLabel*) Next(); }
+ ImpLabel* ImplGetLabel( ULONG nPos ) const { return (ImpLabel*) GetObject( nPos ); }
+ ULONG ImplGetLabelPos( const String& rLabelName );
+ ULONG ImplCount() const { return Count(); }
+};
+
+// ------------------------------------------------------------------------
+
+ImpLabelList::ImpLabelList( const ImpLabelList& rList ) :
+ List( rList )
+{
+ for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
+ ImplReplace( new ImpLabel( *pLabel ) );
+}
+
+// ------------------------------------------------------------------------
+
+ImpLabelList::~ImpLabelList()
+{
+ for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
+ delete pLabel;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ImpLabelList::ImplGetLabelPos( const String& rLabelName )
+{
+ ULONG nLabelPos = METAFILE_LABEL_NOTFOUND;
+
+ for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
+ {
+ if ( rLabelName == pLabel->aLabelName )
+ {
+ nLabelPos = GetCurPos();
+ break;
+ }
+ }
+
+ return nLabelPos;
+}
+
+// ---------------
+// - GDIMetaFile -
+// ---------------
+
+GDIMetaFile::GDIMetaFile() :
+ List ( 0x3EFF, 64, 64 ),
+ aPrefSize ( 1, 1 ),
+ pPrev ( NULL ),
+ pNext ( NULL ),
+ pOutDev ( NULL ),
+ pLabelList ( NULL ),
+ bPause ( FALSE ),
+ bRecord ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------------
+
+GDIMetaFile::GDIMetaFile( const GDIMetaFile& rMtf ) :
+ List ( rMtf ),
+ aPrefMapMode ( rMtf.aPrefMapMode ),
+ aPrefSize ( rMtf.aPrefSize ),
+ aHookHdlLink ( rMtf.aHookHdlLink ),
+ pPrev ( rMtf.pPrev ),
+ pNext ( rMtf.pNext ),
+ pOutDev ( NULL ),
+ bPause ( FALSE ),
+ bRecord ( FALSE )
+{
+ // RefCount der MetaActions erhoehen
+ for( void* pAct = First(); pAct; pAct = Next() )
+ ( (MetaAction*) pAct )->Duplicate();
+
+ if( rMtf.pLabelList )
+ pLabelList = new ImpLabelList( *rMtf.pLabelList );
+ else
+ pLabelList = NULL;
+
+ if( rMtf.bRecord )
+ {
+ Record( rMtf.pOutDev );
+
+ if ( rMtf.bPause )
+ Pause( TRUE );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+GDIMetaFile::~GDIMetaFile()
+{
+ Clear();
+}
+
+// ------------------------------------------------------------------------
+
+GDIMetaFile& GDIMetaFile::operator=( const GDIMetaFile& rMtf )
+{
+ if( this != &rMtf )
+ {
+ Clear();
+
+ List::operator=( rMtf );
+
+ // RefCount der MetaActions erhoehen
+ for( void* pAct = First(); pAct; pAct = Next() )
+ ( (MetaAction*) pAct )->Duplicate();
+
+ if( rMtf.pLabelList )
+ pLabelList = new ImpLabelList( *rMtf.pLabelList );
+ else
+ pLabelList = NULL;
+
+ aPrefMapMode = rMtf.aPrefMapMode;
+ aPrefSize = rMtf.aPrefSize;
+ aHookHdlLink = rMtf.aHookHdlLink;
+ pPrev = rMtf.pPrev;
+ pNext = rMtf.pNext;
+ pOutDev = NULL;
+ bPause = FALSE;
+ bRecord = FALSE;
+
+ if( rMtf.bRecord )
+ {
+ Record( rMtf.pOutDev );
+
+ if( rMtf.bPause )
+ Pause( TRUE );
+ }
+ }
+
+ return *this;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const
+{
+ const ULONG nObjCount = Count();
+ BOOL bRet = FALSE;
+
+ if( this == &rMtf )
+ bRet = TRUE;
+ else if( rMtf.GetActionCount() == nObjCount &&
+ rMtf.GetPrefSize() == aPrefSize &&
+ rMtf.GetPrefMapMode() == aPrefMapMode )
+ {
+ bRet = TRUE;
+
+ for( ULONG n = 0UL; n < nObjCount; n++ )
+ {
+ if( GetObject( n ) != rMtf.GetObject( n ) )
+ {
+ bRet = FALSE;
+ break;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool GDIMetaFile::IsEqual( const GDIMetaFile& rMtf ) const
+{
+ const ULONG nObjCount = Count();
+ BOOL bRet = FALSE;
+
+ if( this == &rMtf )
+ bRet = TRUE;
+ else if( rMtf.GetActionCount() == nObjCount &&
+ rMtf.GetPrefSize() == aPrefSize &&
+ rMtf.GetPrefMapMode() == aPrefMapMode )
+ {
+ bRet = TRUE;
+
+ for( ULONG n = 0UL; n < nObjCount; n++ )
+ {
+ if(!((MetaAction*)GetObject( n ))->IsEqual(*((MetaAction*)rMtf.GetObject( n ))))
+ {
+ bRet = FALSE;
+ break;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Clear()
+{
+ if( bRecord )
+ Stop();
+
+ for( void* pAct = First(); pAct; pAct = Next() )
+ ( (MetaAction*) pAct )->Delete();
+
+ List::Clear();
+
+ delete pLabelList;
+ pLabelList = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Linker( OutputDevice* pOut, BOOL bLink )
+{
+ if( bLink )
+ {
+ pNext = NULL;
+ pPrev = pOut->GetConnectMetaFile();
+ pOut->SetConnectMetaFile( this );
+
+ if( pPrev )
+ pPrev->pNext = this;
+ }
+ else
+ {
+ if( pNext )
+ {
+ pNext->pPrev = pPrev;
+
+ if( pPrev )
+ pPrev->pNext = pNext;
+ }
+ else
+ {
+ if( pPrev )
+ pPrev->pNext = NULL;
+
+ pOut->SetConnectMetaFile( pPrev );
+ }
+
+ pPrev = NULL;
+ pNext = NULL;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+long GDIMetaFile::Hook()
+{
+ return aHookHdlLink.Call( this );
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Record( OutputDevice* pOut )
+{
+ if( bRecord )
+ Stop();
+
+ Last();
+ pOutDev = pOut;
+ bRecord = TRUE;
+ Linker( pOut, TRUE );
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Play( GDIMetaFile& rMtf, ULONG nPos )
+{
+ if ( !bRecord && !rMtf.bRecord )
+ {
+ MetaAction* pAction = GetCurAction();
+ const ULONG nObjCount = Count();
+
+ if( nPos > nObjCount )
+ nPos = nObjCount;
+
+ for( ULONG nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ )
+ {
+ if( !Hook() )
+ {
+ pAction->Duplicate();
+ rMtf.AddAction( pAction );
+ }
+
+ pAction = (MetaAction*) Next();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Play( OutputDevice* pOut, ULONG nPos )
+{
+ if( !bRecord )
+ {
+ MetaAction* pAction = GetCurAction();
+ const ULONG nObjCount = Count();
+ ULONG i = 0, nSyncCount = ( pOut->GetOutDevType() == OUTDEV_WINDOW ) ? 0x000000ff : 0xffffffff;
+
+ if( nPos > nObjCount )
+ nPos = nObjCount;
+
+ // #i23407# Set backwards-compatible text language and layout mode
+ // This is necessary, since old metafiles don't even know of these
+ // recent add-ons. Newer metafiles must of course explicitely set
+ // those states.
+ pOut->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE );
+ pOut->SetLayoutMode( 0 );
+ pOut->SetDigitLanguage( 0 );
+
+ for( ULONG nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ )
+ {
+ if( !Hook() )
+ {
+ pAction->Execute( pOut );
+
+ // flush output from time to time
+ if( i++ > nSyncCount )
+ ( (Window*) pOut )->Flush(), i = 0;
+ }
+
+ pAction = (MetaAction*) Next();
+ }
+
+ pOut->Pop();
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos,
+ const Size& rSize, ULONG nPos )
+{
+ Region aDrawClipRegion;
+ MapMode aDrawMap( GetPrefMapMode() );
+ Size aDestSize( pOut->LogicToPixel( rSize ) );
+
+ if( aDestSize.Width() && aDestSize.Height() )
+ {
+ Size aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) );
+ GDIMetaFile* pMtf = pOut->GetConnectMetaFile();
+
+ if( !aTmpPrefSize.Width() )
+ aTmpPrefSize.Width() = aDestSize.Width();
+
+ if( !aTmpPrefSize.Height() )
+ aTmpPrefSize.Height() = aDestSize.Height();
+
+ Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() );
+ Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() );
+
+ aScaleX *= aDrawMap.GetScaleX(); aDrawMap.SetScaleX( aScaleX );
+ aScaleY *= aDrawMap.GetScaleY(); aDrawMap.SetScaleY( aScaleY );
+
+ // #i47260# Convert logical output position to offset within
+ // the metafile's mapmode. Therefore, disable pixel offset on
+ // outdev, it's inverse mnOutOffLogicX/Y is calculated for a
+ // different mapmode (the one currently set on pOut, that is)
+ // - thus, aDrawMap's origin would generally be wrong. And
+ // even _if_ aDrawMap is similar to pOutDev's current mapmode,
+ // it's _still_ undesirable to have pixel offset unequal zero,
+ // because one would still get round-off errors (the
+ // round-trip error for LogicToPixel( PixelToLogic() ) was the
+ // reason for having pixel offset in the first place).
+ const Size& rOldOffset( pOut->GetPixelOffset() );
+ const Size aEmptySize;
+ pOut->SetPixelOffset( aEmptySize );
+ aDrawMap.SetOrigin( pOut->PixelToLogic( pOut->LogicToPixel( rPos ), aDrawMap ) );
+ pOut->SetPixelOffset( rOldOffset );
+
+ pOut->Push();
+
+ if ( pMtf && pMtf->IsRecord() && ( pOut->GetOutDevType() != OUTDEV_PRINTER ) )
+ pOut->SetRelativeMapMode( aDrawMap );
+ else
+ pOut->SetMapMode( aDrawMap );
+
+ // #i23407# Set backwards-compatible text language and layout mode
+ // This is necessary, since old metafiles don't even know of these
+ // recent add-ons. Newer metafiles must of course explicitely set
+ // those states.
+ pOut->SetLayoutMode( 0 );
+ pOut->SetDigitLanguage( 0 );
+
+ Play( pOut, nPos );
+
+ pOut->Pop();
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Pause( BOOL _bPause )
+{
+ if( bRecord )
+ {
+ if( _bPause )
+ {
+ if( !bPause )
+ Linker( pOutDev, FALSE );
+ }
+ else
+ {
+ if( bPause )
+ Linker( pOutDev, TRUE );
+ }
+
+ bPause = _bPause;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Stop()
+{
+ if( bRecord )
+ {
+ bRecord = FALSE;
+
+ if( !bPause )
+ Linker( pOutDev, FALSE );
+ else
+ bPause = FALSE;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::WindStart()
+{
+ if( !bRecord )
+ First();
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::WindEnd()
+{
+ if( !bRecord )
+ Last();
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Wind( ULONG nActionPos )
+{
+ if( !bRecord )
+ Seek( nActionPos );
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::WindPrev()
+{
+ if( !bRecord )
+ Prev();
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::WindNext()
+{
+ if( !bRecord )
+ Next();
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::AddAction( MetaAction* pAction )
+{
+ Insert( pAction, LIST_APPEND );
+
+ if( pPrev )
+ {
+ pAction->Duplicate();
+ pPrev->AddAction( pAction );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::AddAction( MetaAction* pAction, ULONG nPos )
+{
+ Insert( pAction, nPos );
+
+ if( pPrev )
+ {
+ pAction->Duplicate();
+ pPrev->AddAction( pAction, nPos );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+// @since #110496#
+void GDIMetaFile::RemoveAction( ULONG nPos )
+{
+ Remove( nPos );
+
+ if( pPrev )
+ pPrev->RemoveAction( nPos );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* GDIMetaFile::CopyAction( ULONG nPos ) const
+{
+ return ( (MetaAction*) GetObject( nPos ) )->Clone();
+}
+
+// ------------------------------------------------------------------------
+
+ULONG GDIMetaFile::GetActionPos( const String& rLabel )
+{
+ ImpLabel* pLabel = NULL;
+
+ if( pLabelList )
+ pLabel = pLabelList->ImplGetLabel( pLabelList->ImplGetLabelPos( rLabel ) );
+ else
+ pLabel = NULL;
+
+ return( pLabel ? pLabel->nActionPos : METAFILE_LABEL_NOTFOUND );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GDIMetaFile::InsertLabel( const String& rLabel, ULONG nActionPos )
+{
+ BOOL bRet = FALSE;
+
+ if( !pLabelList )
+ pLabelList = new ImpLabelList;
+
+ if( pLabelList->ImplGetLabelPos( rLabel ) == METAFILE_LABEL_NOTFOUND )
+ {
+ pLabelList->ImplInsert( new ImpLabel( rLabel, nActionPos ) );
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::RemoveLabel( const String& rLabel )
+{
+ if( pLabelList )
+ {
+ const ULONG nLabelPos = pLabelList->ImplGetLabelPos( rLabel );
+
+ if( nLabelPos != METAFILE_LABEL_NOTFOUND )
+ delete pLabelList->ImplRemove( nLabelPos );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::RenameLabel( const String& rLabel, const String& rNewLabel )
+{
+ if( pLabelList )
+ {
+ const ULONG nLabelPos = pLabelList->ImplGetLabelPos( rLabel );
+
+ if ( nLabelPos != METAFILE_LABEL_NOTFOUND )
+ pLabelList->ImplGetLabel( nLabelPos )->aLabelName = rNewLabel;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+ULONG GDIMetaFile::GetLabelCount() const
+{
+ return( pLabelList ? pLabelList->ImplCount() : 0UL );
+}
+
+// ------------------------------------------------------------------------
+
+String GDIMetaFile::GetLabel( ULONG nLabel )
+{
+ String aString;
+
+ if( pLabelList )
+ {
+ const ImpLabel* pLabel = pLabelList->ImplGetLabel( nLabel );
+
+ if( pLabel )
+ aString = pLabel->aLabelName;
+ }
+
+ return aString;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GDIMetaFile::SaveStatus()
+{
+ if ( bRecord )
+ {
+ if ( bPause )
+ Linker( pOutDev, TRUE );
+
+ AddAction( new MetaLineColorAction( pOutDev->GetLineColor(),
+ pOutDev->IsLineColor() ) );
+ AddAction( new MetaFillColorAction( pOutDev->GetFillColor(),
+ pOutDev->IsFillColor() ) );
+ AddAction( new MetaFontAction( pOutDev->GetFont() ) );
+ AddAction( new MetaTextColorAction( pOutDev->GetTextColor() ) );
+ AddAction( new MetaTextFillColorAction( pOutDev->GetTextFillColor(),
+ pOutDev->IsTextFillColor() ) );
+ AddAction( new MetaTextLineColorAction( pOutDev->GetTextLineColor(),
+ pOutDev->IsTextLineColor() ) );
+ AddAction( new MetaOverlineColorAction( pOutDev->GetOverlineColor(),
+ pOutDev->IsOverlineColor() ) );
+ AddAction( new MetaTextAlignAction( pOutDev->GetTextAlign() ) );
+ AddAction( new MetaRasterOpAction( pOutDev->GetRasterOp() ) );
+ AddAction( new MetaMapModeAction( pOutDev->GetMapMode() ) );
+ AddAction( new MetaClipRegionAction( pOutDev->GetClipRegion(),
+ pOutDev->IsClipRegion() ) );
+
+ if ( bPause )
+ Linker( pOutDev, FALSE );
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GDIMetaFile::Mirror( ULONG nMirrorFlags )
+{
+ const Size aOldPrefSize( GetPrefSize() );
+ long nMoveX, nMoveY;
+ double fScaleX, fScaleY;
+ BOOL bRet;
+
+ if( nMirrorFlags & MTF_MIRROR_HORZ )
+ nMoveX = VOS_ABS( aOldPrefSize.Width() ) - 1, fScaleX = -1.0;
+ else
+ nMoveX = 0, fScaleX = 1.0;
+
+ if( nMirrorFlags & MTF_MIRROR_VERT )
+ nMoveY = VOS_ABS( aOldPrefSize.Height() ) - 1, fScaleY = -1.0;
+ else
+ nMoveY = 0, fScaleY = 1.0;
+
+ if( ( fScaleX != 1.0 ) || ( fScaleY != 1.0 ) )
+ {
+ Scale( fScaleX, fScaleY );
+ Move( nMoveX, nMoveY );
+ SetPrefSize( aOldPrefSize );
+ bRet = TRUE;
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Move( long nX, long nY )
+{
+ const Size aBaseOffset( nX, nY );
+ Size aOffset( aBaseOffset );
+ VirtualDevice aMapVDev;
+
+ aMapVDev.EnableOutput( FALSE );
+ aMapVDev.SetMapMode( GetPrefMapMode() );
+
+ for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
+ {
+ const long nType = pAct->GetType();
+ MetaAction* pModAct;
+
+ if( pAct->GetRefCount() > 1 )
+ {
+ Replace( pModAct = pAct->Clone(), GetCurPos() );
+ pAct->Delete();
+ }
+ else
+ pModAct = pAct;
+
+ if( ( META_MAPMODE_ACTION == nType ) ||
+ ( META_PUSH_ACTION == nType ) ||
+ ( META_POP_ACTION == nType ) )
+ {
+ pModAct->Execute( &aMapVDev );
+ aOffset = aMapVDev.LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev.GetMapMode() );
+ }
+
+ pModAct->Move( aOffset.Width(), aOffset.Height() );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Scale( double fScaleX, double fScaleY )
+{
+ for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
+ {
+ MetaAction* pModAct;
+
+ if( pAct->GetRefCount() > 1 )
+ {
+ Replace( pModAct = pAct->Clone(), GetCurPos() );
+ pAct->Delete();
+ }
+ else
+ pModAct = pAct;
+
+ pModAct->Scale( fScaleX, fScaleY );
+ }
+
+ aPrefSize.Width() = FRound( aPrefSize.Width() * fScaleX );
+ aPrefSize.Height() = FRound( aPrefSize.Height() * fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY )
+{
+ Scale( (double) rScaleX, (double) rScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Clip( const Rectangle& i_rClipRect )
+{
+ Rectangle aCurRect( i_rClipRect );
+ VirtualDevice aMapVDev;
+
+ aMapVDev.EnableOutput( FALSE );
+ aMapVDev.SetMapMode( GetPrefMapMode() );
+
+ for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
+ {
+ const long nType = pAct->GetType();
+
+ if( ( META_MAPMODE_ACTION == nType ) ||
+ ( META_PUSH_ACTION == nType ) ||
+ ( META_POP_ACTION == nType ) )
+ {
+ pAct->Execute( &aMapVDev );
+ aCurRect = aMapVDev.LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev.GetMapMode() );
+ }
+ else if( nType == META_CLIPREGION_ACTION )
+ {
+ MetaClipRegionAction* pOldAct = (MetaClipRegionAction*)pAct;
+ Region aNewReg( aCurRect );
+ if( pOldAct->IsClipping() )
+ aNewReg.Intersect( pOldAct->GetRegion() );
+ MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, TRUE );
+ Replace( pNewAct, GetCurPos() );
+ pOldAct->Delete();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt,
+ const Size& rOffset, double fSin, double fCos )
+{
+ const long nX = rPt.X() - rRotatePt.X();
+ const long nY = rPt.Y() - rRotatePt.Y();
+
+ return Point( FRound( fCos * nX + fSin * nY ) + rRotatePt.X() + rOffset.Width(),
+ -FRound( fSin * nX - fCos * nY ) + rRotatePt.Y() + rOffset.Height() );
+}
+
+// ------------------------------------------------------------------------
+
+Polygon GDIMetaFile::ImplGetRotatedPolygon( const Polygon& rPoly, const Point& rRotatePt,
+ const Size& rOffset, double fSin, double fCos )
+{
+ Polygon aRet( rPoly );
+
+ aRet.Rotate( rRotatePt, fSin, fCos );
+ aRet.Move( rOffset.Width(), rOffset.Height() );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+PolyPolygon GDIMetaFile::ImplGetRotatedPolyPolygon( const PolyPolygon& rPolyPoly, const Point& rRotatePt,
+ const Size& rOffset, double fSin, double fCos )
+{
+ PolyPolygon aRet( rPolyPoly );
+
+ aRet.Rotate( rRotatePt, fSin, fCos );
+ aRet.Move( rOffset.Width(), rOffset.Height() );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::ImplAddGradientEx( GDIMetaFile& rMtf,
+ const OutputDevice& rMapDev,
+ const PolyPolygon& rPolyPoly,
+ const Gradient& rGrad )
+{
+ // #105055# Generate comment, GradientEx and Gradient actions
+ // (within DrawGradient)
+ VirtualDevice aVDev( rMapDev, 0 );
+ aVDev.EnableOutput( FALSE );
+ GDIMetaFile aGradMtf;
+
+ aGradMtf.Record( &aVDev );
+ aVDev.DrawGradient( rPolyPoly, rGrad );
+ aGradMtf.Stop();
+
+ int i, nAct( aGradMtf.GetActionCount() );
+ for( i=0; i<nAct; ++i )
+ {
+ MetaAction* pMetaAct = aGradMtf.GetAction(i);
+ pMetaAct->Duplicate();
+ rMtf.AddAction( pMetaAct );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Rotate( long nAngle10 )
+{
+ nAngle10 %= 3600L;
+ nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10;
+
+ if( nAngle10 )
+ {
+ GDIMetaFile aMtf;
+ VirtualDevice aMapVDev;
+ const double fAngle = F_PI1800 * nAngle10;
+ const double fSin = sin( fAngle );
+ const double fCos = cos( fAngle );
+ Rectangle aRect=Rectangle( Point(), GetPrefSize() );
+ Polygon aPoly( aRect );
+
+ aPoly.Rotate( Point(), fSin, fCos );
+
+ aMapVDev.EnableOutput( FALSE );
+ aMapVDev.SetMapMode( GetPrefMapMode() );
+
+ const Rectangle aNewBound( aPoly.GetBoundRect() );
+
+ const Point aOrigin( GetPrefMapMode().GetOrigin().X(), GetPrefMapMode().GetOrigin().Y() );
+ const Size aOffset( -aNewBound.Left(), -aNewBound.Top() );
+
+ Point aRotAnchor( aOrigin );
+ Size aRotOffset( aOffset );
+
+ for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
+ {
+ const USHORT nActionType = pAction->GetType();
+
+ switch( nActionType )
+ {
+ case( META_PIXEL_ACTION ):
+ {
+ MetaPixelAction* pAct = (MetaPixelAction*) pAction;
+ aMtf.AddAction( new MetaPixelAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetColor() ) );
+ }
+ break;
+
+ case( META_POINT_ACTION ):
+ {
+ MetaPointAction* pAct = (MetaPointAction*) pAction;
+ aMtf.AddAction( new MetaPointAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_LINE_ACTION ):
+ {
+ MetaLineAction* pAct = (MetaLineAction*) pAction;
+ aMtf.AddAction( new MetaLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
+ ImplGetRotatedPoint( pAct->GetEndPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetLineInfo() ) );
+ }
+ break;
+
+ case( META_RECT_ACTION ):
+ {
+ MetaRectAction* pAct = (MetaRectAction*) pAction;
+ aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_ROUNDRECT_ACTION ):
+ {
+ MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction;
+ const Polygon aRoundRectPoly( pAct->GetRect(), pAct->GetHorzRound(), pAct->GetVertRound() );
+
+ aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aRoundRectPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_ELLIPSE_ACTION ):
+ {
+ MetaEllipseAction* pAct = (MetaEllipseAction*) pAction;
+ const Polygon aEllipsePoly( pAct->GetRect().Center(), pAct->GetRect().GetWidth() >> 1, pAct->GetRect().GetHeight() >> 1 );
+
+ aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aEllipsePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_ARC_ACTION ):
+ {
+ MetaArcAction* pAct = (MetaArcAction*) pAction;
+ const Polygon aArcPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_ARC );
+
+ aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aArcPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_PIE_ACTION ):
+ {
+ MetaPieAction* pAct = (MetaPieAction*) pAction;
+ const Polygon aPiePoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_PIE );
+
+ aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aPiePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_CHORD_ACTION ):
+ {
+ MetaChordAction* pAct = (MetaChordAction*) pAction;
+ const Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_CHORD );
+
+ aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aChordPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_POLYLINE_ACTION ):
+ {
+ MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
+ aMtf.AddAction( new MetaPolyLineAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->GetLineInfo() ) );
+ }
+ break;
+
+ case( META_POLYGON_ACTION ):
+ {
+ MetaPolygonAction* pAct = (MetaPolygonAction*) pAction;
+ aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_POLYPOLYGON_ACTION ):
+ {
+ MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
+ aMtf.AddAction( new MetaPolyPolygonAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_TEXT_ACTION ):
+ {
+ MetaTextAction* pAct = (MetaTextAction*) pAction;
+ aMtf.AddAction( new MetaTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
+ }
+ break;
+
+ case( META_TEXTARRAY_ACTION ):
+ {
+ MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction;
+ aMtf.AddAction( new MetaTextArrayAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetText(), pAct->GetDXArray(), pAct->GetIndex(), pAct->GetLen() ) );
+ }
+ break;
+
+ case( META_STRETCHTEXT_ACTION ):
+ {
+ MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
+ aMtf.AddAction( new MetaStretchTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetWidth(), pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
+ }
+ break;
+
+ case( META_TEXTLINE_ACTION ):
+ {
+ MetaTextLineAction* pAct = (MetaTextLineAction*) pAction;
+ aMtf.AddAction( new MetaTextLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetWidth(), pAct->GetStrikeout(), pAct->GetUnderline(), pAct->GetOverline() ) );
+ }
+ break;
+
+ case( META_BMPSCALE_ACTION ):
+ {
+ MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
+ Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
+ Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
+ BitmapEx aBmpEx( pAct->GetBitmap() );
+
+ aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
+ aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(),
+ aBmpEx ) );
+ }
+ break;
+
+ case( META_BMPSCALEPART_ACTION ):
+ {
+ MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
+ Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
+ Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
+ BitmapEx aBmpEx( pAct->GetBitmap() );
+
+ aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
+ aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
+
+ aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
+ }
+ break;
+
+ case( META_BMPEXSCALE_ACTION ):
+ {
+ MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
+ Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
+ Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
+ BitmapEx aBmpEx( pAct->GetBitmapEx() );
+
+ aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
+
+ aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
+ }
+ break;
+
+ case( META_BMPEXSCALEPART_ACTION ):
+ {
+ MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
+ Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
+ Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
+ BitmapEx aBmpEx( pAct->GetBitmapEx() );
+
+ aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
+ aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
+
+ aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
+ }
+ break;
+
+ case( META_GRADIENT_ACTION ):
+ {
+ MetaGradientAction* pAct = (MetaGradientAction*) pAction;
+
+ ImplAddGradientEx( aMtf, aMapVDev,
+ ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetGradient() );
+ }
+ break;
+
+ case( META_GRADIENTEX_ACTION ):
+ {
+ MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
+ aMtf.AddAction( new MetaGradientExAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetGradient() ) );
+ }
+ break;
+
+ // #105055# Handle gradientex comment block correctly
+ case( META_COMMENT_ACTION ):
+ {
+ MetaCommentAction* pCommentAct = (MetaCommentAction*) pAction;
+ if( pCommentAct->GetComment().Equals( "XGRAD_SEQ_BEGIN" ) )
+ {
+ int nBeginComments( 1 );
+ pAction = (MetaAction*) Next();
+
+ // skip everything, except gradientex action
+ while( pAction )
+ {
+ const USHORT nType = pAction->GetType();
+
+ if( META_GRADIENTEX_ACTION == nType )
+ {
+ // Add rotated gradientex
+ MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
+ ImplAddGradientEx( aMtf, aMapVDev,
+ ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetGradient() );
+ }
+ else if( META_COMMENT_ACTION == nType)
+ {
+ MetaCommentAction* pAct = (MetaCommentAction*) pAction;
+ if( pAct->GetComment().Equals( "XGRAD_SEQ_END" ) )
+ {
+ // handle nested blocks
+ --nBeginComments;
+
+ // gradientex comment block: end reached, done.
+ if( !nBeginComments )
+ break;
+ }
+ else if( pAct->GetComment().Equals( "XGRAD_SEQ_BEGIN" ) )
+ {
+ // handle nested blocks
+ ++nBeginComments;
+ }
+
+ }
+
+ pAction = (MetaAction*) Next();
+ }
+ }
+ else
+ {
+ sal_Bool bPathStroke = pCommentAct->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" );
+ if ( bPathStroke || pCommentAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
+ {
+ if ( pCommentAct->GetDataSize() )
+ {
+ SvMemoryStream aMemStm( (void*)pCommentAct->GetData(), pCommentAct->GetDataSize(), STREAM_READ );
+ SvMemoryStream aDest;
+ if ( bPathStroke )
+ {
+ SvtGraphicStroke aStroke;
+ aMemStm >> aStroke;
+ Polygon aPath;
+ aStroke.getPath( aPath );
+ aStroke.setPath( ImplGetRotatedPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
+ aDest << aStroke;
+ aMtf.AddAction( new MetaCommentAction( "XPATHSTROKE_SEQ_BEGIN", 0,
+ static_cast<const BYTE*>( aDest.GetData()), aDest.Tell() ) );
+ }
+ else
+ {
+ SvtGraphicFill aFill;
+ aMemStm >> aFill;
+ PolyPolygon aPath;
+ aFill.getPath( aPath );
+ aFill.setPath( ImplGetRotatedPolyPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
+ aDest << aFill;
+ aMtf.AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
+ static_cast<const BYTE*>( aDest.GetData()), aDest.Tell() ) );
+ }
+ }
+ }
+ else if ( pCommentAct->GetComment().Equals( "XPATHSTROKE_SEQ_END" )
+ || pCommentAct->GetComment().Equals( "XPATHFILL_SEQ_END" ) )
+ {
+ pAction->Execute( &aMapVDev );
+ pAction->Duplicate();
+ aMtf.AddAction( pAction );
+ }
+ }
+ }
+ break;
+
+ case( META_HATCH_ACTION ):
+ {
+ MetaHatchAction* pAct = (MetaHatchAction*) pAction;
+ Hatch aHatch( pAct->GetHatch() );
+
+ aHatch.SetAngle( aHatch.GetAngle() + (USHORT) nAngle10 );
+ aMtf.AddAction( new MetaHatchAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
+ aHatch ) );
+ }
+ break;
+
+ case( META_TRANSPARENT_ACTION ):
+ {
+ MetaTransparentAction* pAct = (MetaTransparentAction*) pAction;
+ aMtf.AddAction( new MetaTransparentAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
+ pAct->GetTransparence() ) );
+ }
+ break;
+
+ case( META_FLOATTRANSPARENT_ACTION ):
+ {
+ MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
+ GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
+ Polygon aMtfPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
+ Rectangle aMtfRect( aMtfPoly.GetBoundRect() );
+
+ aTransMtf.Rotate( nAngle10 );
+ aMtf.AddAction( new MetaFloatTransparentAction( aTransMtf, aMtfRect.TopLeft(), aMtfRect.GetSize(),
+ pAct->GetGradient() ) );
+ }
+ break;
+
+ case( META_EPS_ACTION ):
+ {
+ MetaEPSAction* pAct = (MetaEPSAction*) pAction;
+ GDIMetaFile aEPSMtf( pAct->GetSubstitute() );
+ Polygon aEPSPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
+ Rectangle aEPSRect( aEPSPoly.GetBoundRect() );
+
+ aEPSMtf.Rotate( nAngle10 );
+ aMtf.AddAction( new MetaEPSAction( aEPSRect.TopLeft(), aEPSRect.GetSize(),
+ pAct->GetLink(), aEPSMtf ) );
+ }
+ break;
+
+ case( META_CLIPREGION_ACTION ):
+ {
+ MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
+
+ if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygon() )
+ aMtf.AddAction( new MetaClipRegionAction( Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), TRUE ) );
+ else
+ {
+ pAction->Duplicate();
+ aMtf.AddAction( pAction );
+ }
+ }
+ break;
+
+ case( META_ISECTRECTCLIPREGION_ACTION ):
+ {
+ MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction;
+ aMtf.AddAction( new MetaISectRegionClipRegionAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
+ }
+ break;
+
+ case( META_ISECTREGIONCLIPREGION_ACTION ):
+ {
+ MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction;
+ const Region& rRegion = pAct->GetRegion();
+
+ if( rRegion.HasPolyPolygon() )
+ aMtf.AddAction( new MetaISectRegionClipRegionAction( Region( ImplGetRotatedPolyPolygon( rRegion.GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) );
+ else
+ {
+ pAction->Duplicate();
+ aMtf.AddAction( pAction );
+ }
+ }
+ break;
+
+ case( META_REFPOINT_ACTION ):
+ {
+ MetaRefPointAction* pAct = (MetaRefPointAction*) pAction;
+ aMtf.AddAction( new MetaRefPointAction( ImplGetRotatedPoint( pAct->GetRefPoint(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->IsSetting() ) );
+ }
+ break;
+
+ case( META_FONT_ACTION ):
+ {
+ MetaFontAction* pAct = (MetaFontAction*) pAction;
+ Font aFont( pAct->GetFont() );
+
+ aFont.SetOrientation( aFont.GetOrientation() + (USHORT) nAngle10 );
+ aMtf.AddAction( new MetaFontAction( aFont ) );
+ }
+ break;
+
+ case( META_BMP_ACTION ):
+ case( META_BMPEX_ACTION ):
+ case( META_MASK_ACTION ):
+ case( META_MASKSCALE_ACTION ):
+ case( META_MASKSCALEPART_ACTION ):
+ case( META_WALLPAPER_ACTION ):
+ case( META_TEXTRECT_ACTION ):
+ case( META_MOVECLIPREGION_ACTION ):
+ {
+ DBG_ERROR( "GDIMetaFile::Rotate(): unsupported action" );
+ }
+ break;
+
+ default:
+ {
+ pAction->Execute( &aMapVDev );
+ pAction->Duplicate();
+ aMtf.AddAction( pAction );
+
+ // update rotation point and offset, if necessary
+ if( ( META_MAPMODE_ACTION == nActionType ) ||
+ ( META_PUSH_ACTION == nActionType ) ||
+ ( META_POP_ACTION == nActionType ) )
+ {
+ aRotAnchor = aMapVDev.LogicToLogic( aOrigin, aPrefMapMode, aMapVDev.GetMapMode() );
+ aRotOffset = aMapVDev.LogicToLogic( aOffset, aPrefMapMode, aMapVDev.GetMapMode() );
+ }
+ }
+ break;
+ }
+ }
+
+ aMtf.aPrefMapMode = aPrefMapMode;
+ aMtf.aPrefSize = aNewBound.GetSize();
+
+ *this = aMtf;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+static void ImplActionBounds( Rectangle& o_rOutBounds,
+ const Rectangle& i_rInBounds,
+ const std::vector<Rectangle>& i_rClipStack )
+{
+ Rectangle aBounds( i_rInBounds );
+ if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() )
+ aBounds.Intersection( i_rClipStack.back() );
+ if( ! aBounds.IsEmpty() )
+ {
+ if( ! o_rOutBounds.IsEmpty() )
+ o_rOutBounds.Union( aBounds );
+ else
+ o_rOutBounds = aBounds;
+ }
+}
+
+Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference )
+{
+ GDIMetaFile aMtf;
+ VirtualDevice aMapVDev( i_rReference );
+
+ aMapVDev.EnableOutput( FALSE );
+ aMapVDev.SetMapMode( GetPrefMapMode() );
+
+ std::vector<Rectangle> aClipStack( 1, Rectangle() );
+ std::vector<USHORT> aPushFlagStack;
+
+ Rectangle aBound;
+
+ for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
+ {
+ const USHORT nActionType = pAction->GetType();
+
+ switch( nActionType )
+ {
+ case( META_PIXEL_ACTION ):
+ {
+ MetaPixelAction* pAct = (MetaPixelAction*) pAction;
+ ImplActionBounds( aBound,
+ Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
+ aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
+ aClipStack );
+ }
+ break;
+
+ case( META_POINT_ACTION ):
+ {
+ MetaPointAction* pAct = (MetaPointAction*) pAction;
+ ImplActionBounds( aBound,
+ Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
+ aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
+ aClipStack );
+ }
+ break;
+
+ case( META_LINE_ACTION ):
+ {
+ MetaLineAction* pAct = (MetaLineAction*) pAction;
+ Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() );
+ Rectangle aRect( aP1, aP2 );
+ aRect.Justify();
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_RECT_ACTION ):
+ {
+ MetaRectAction* pAct = (MetaRectAction*) pAction;
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_ROUNDRECT_ACTION ):
+ {
+ MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction;
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_ELLIPSE_ACTION ):
+ {
+ MetaEllipseAction* pAct = (MetaEllipseAction*) pAction;
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_ARC_ACTION ):
+ {
+ MetaArcAction* pAct = (MetaArcAction*) pAction;
+ // FIXME: this is imprecise
+ // e.g. for small arcs the whole rectangle is WAY too large
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_PIE_ACTION ):
+ {
+ MetaPieAction* pAct = (MetaPieAction*) pAction;
+ // FIXME: this is imprecise
+ // e.g. for small arcs the whole rectangle is WAY too large
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_CHORD_ACTION ):
+ {
+ MetaChordAction* pAct = (MetaChordAction*) pAction;
+ // FIXME: this is imprecise
+ // e.g. for small arcs the whole rectangle is WAY too large
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_POLYLINE_ACTION ):
+ {
+ MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
+ Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_POLYGON_ACTION ):
+ {
+ MetaPolygonAction* pAct = (MetaPolygonAction*) pAction;
+ Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_POLYPOLYGON_ACTION ):
+ {
+ MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
+ Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_TEXT_ACTION ):
+ {
+ MetaTextAction* pAct = (MetaTextAction*) pAction;
+ Rectangle aRect;
+ // hdu said base = index
+ aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() );
+ Point aPt( pAct->GetPoint() );
+ aRect.Move( aPt.X(), aPt.Y() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_TEXTARRAY_ACTION ):
+ {
+ MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction;
+ Rectangle aRect;
+ // hdu said base = index
+ aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
+ 0, pAct->GetDXArray() );
+ Point aPt( pAct->GetPoint() );
+ aRect.Move( aPt.X(), aPt.Y() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_STRETCHTEXT_ACTION ):
+ {
+ MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
+ Rectangle aRect;
+ // hdu said base = index
+ aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
+ pAct->GetWidth(), NULL );
+ Point aPt( pAct->GetPoint() );
+ aRect.Move( aPt.X(), aPt.Y() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_TEXTLINE_ACTION ):
+ {
+ MetaTextLineAction* pAct = (MetaTextLineAction*) pAction;
+ // measure a test string to get ascend and descent right
+ static const sal_Unicode pStr[] = { 0xc4, 0x67, 0 };
+ String aStr( pStr );
+
+ Rectangle aRect;
+ aMapVDev.GetTextBoundRect( aRect, aStr, 0, 0, aStr.Len(), 0, NULL );
+ Point aPt( pAct->GetStartPoint() );
+ aRect.Move( aPt.X(), aPt.Y() );
+ aRect.Right() = aRect.Left() + pAct->GetWidth();
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_BMPSCALE_ACTION ):
+ {
+ MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
+ Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_BMPSCALEPART_ACTION ):
+ {
+ MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
+ Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_BMPEXSCALE_ACTION ):
+ {
+ MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
+ Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_BMPEXSCALEPART_ACTION ):
+ {
+ MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
+ Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_GRADIENT_ACTION ):
+ {
+ MetaGradientAction* pAct = (MetaGradientAction*) pAction;
+ Rectangle aRect( pAct->GetRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_GRADIENTEX_ACTION ):
+ {
+ MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
+ Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_COMMENT_ACTION ):
+ {
+ // nothing to do
+ };
+ break;
+
+ case( META_HATCH_ACTION ):
+ {
+ MetaHatchAction* pAct = (MetaHatchAction*) pAction;
+ Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_TRANSPARENT_ACTION ):
+ {
+ MetaTransparentAction* pAct = (MetaTransparentAction*) pAction;
+ Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_FLOATTRANSPARENT_ACTION ):
+ {
+ MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
+ GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
+ // get the bound rect of the contained metafile
+ Rectangle aRect( aTransMtf.GetBoundRect( i_rReference ) );
+ // scale the rect now on the assumption that the correct top left of the metafile
+ // (not its bounds !) is (0,0)
+ Size aPSize( aTransMtf.GetPrefSize() );
+ aPSize = aMapVDev.LogicToLogic( aPSize, aTransMtf.GetPrefMapMode(), aMapVDev.GetMapMode() );
+ Size aActSize( pAct->GetSize() );
+ double fX = double(aActSize.Width())/double(aPSize.Width());
+ double fY = double(aActSize.Height())/double(aPSize.Height());
+ aRect.Left() = long(double(aRect.Left())*fX);
+ aRect.Right() = long(double(aRect.Right())*fX);
+ aRect.Top() = long(double(aRect.Top())*fY);
+ aRect.Bottom() = long(double(aRect.Bottom())*fY);
+
+ // transform the rect to current VDev state
+ aRect = aMapVDev.LogicToLogic( aRect, aTransMtf.GetPrefMapMode(), aMapVDev.GetMapMode() );
+
+ ImplActionBounds( aBound, aRect, aClipStack );
+ }
+ break;
+
+ case( META_EPS_ACTION ):
+ {
+ MetaEPSAction* pAct = (MetaEPSAction*) pAction;
+ Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_CLIPREGION_ACTION ):
+ {
+ MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
+ if( pAct->IsClipping() )
+ aClipStack.back() = aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() );
+ else
+ aClipStack.back() = Rectangle();
+ }
+ break;
+
+ case( META_ISECTRECTCLIPREGION_ACTION ):
+ {
+ MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction;
+ Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
+ if( aClipStack.back().IsEmpty() )
+ aClipStack.back() = aRect;
+ else
+ aClipStack.back().Intersection( aRect );
+ }
+ break;
+
+ case( META_ISECTREGIONCLIPREGION_ACTION ):
+ {
+ MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction;
+ Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
+ if( aClipStack.back().IsEmpty() )
+ aClipStack.back() = aRect;
+ else
+ aClipStack.back().Intersection( aRect );
+ }
+ break;
+
+ case( META_BMP_ACTION ):
+ {
+ MetaBmpAction* pAct = (MetaBmpAction*) pAction;
+ Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_BMPEX_ACTION ):
+ {
+ MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
+ Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmapEx().GetSizePixel() ) );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_MASK_ACTION ):
+ {
+ MetaMaskAction* pAct = (MetaMaskAction*) pAction;
+ Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_MASKSCALE_ACTION ):
+ {
+ MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
+ Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_MASKSCALEPART_ACTION ):
+ {
+ MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
+ Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_WALLPAPER_ACTION ):
+ {
+ MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction;
+ Rectangle aRect( pAct->GetRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_TEXTRECT_ACTION ):
+ {
+ MetaTextRectAction* pAct = (MetaTextRectAction*) pAction;
+ Rectangle aRect( pAct->GetRect() );
+ ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
+ }
+ break;
+
+ case( META_MOVECLIPREGION_ACTION ):
+ {
+ MetaMoveClipRegionAction* pAct = (MetaMoveClipRegionAction*) pAction;
+ if( ! aClipStack.back().IsEmpty() )
+ {
+ Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() );
+ aDelta = aMapVDev.LogicToLogic( aDelta, aMapVDev.GetMapMode(), GetPrefMapMode() );
+ aClipStack.back().Move( aDelta.Width(), aDelta.Width() );
+ }
+ }
+ break;
+
+ default:
+ {
+ pAction->Execute( &aMapVDev );
+
+ if( nActionType == META_PUSH_ACTION )
+ {
+ MetaPushAction* pAct = (MetaPushAction*) pAction;
+ aPushFlagStack.push_back( pAct->GetFlags() );
+ if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
+ {
+ Rectangle aRect( aClipStack.back() );
+ aClipStack.push_back( aRect );
+ }
+ }
+ else if( nActionType == META_POP_ACTION )
+ {
+ // sanity check
+ if( ! aPushFlagStack.empty() )
+ {
+ if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
+ {
+ if( aClipStack.size() > 1 )
+ aClipStack.pop_back();
+ }
+ aPushFlagStack.pop_back();
+ }
+ }
+ }
+ break;
+ }
+ }
+ return aBound;
+}
+
+// ------------------------------------------------------------------------
+
+Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam )
+{
+ return Color( rColor.GetTransparency(),
+ ( (const ImplColAdjustParam*) pColParam )->pMapR[ rColor.GetRed() ],
+ ( (const ImplColAdjustParam*) pColParam )->pMapG[ rColor.GetGreen() ],
+ ( (const ImplColAdjustParam*) pColParam )->pMapB[ rColor.GetBlue() ] );
+
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
+{
+ const ImplBmpAdjustParam* p = (const ImplBmpAdjustParam*) pBmpParam;
+ BitmapEx aRet( rBmpEx );
+
+ aRet.Adjust( p->nLuminancePercent, p->nContrastPercent,
+ p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent,
+ p->fGamma, p->bInvert );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam )
+{
+ BYTE cLum = rColor.GetLuminance();
+
+ if( MTF_CONVERSION_1BIT_THRESHOLD == ( (const ImplColConvertParam*) pColParam )->eConversion )
+ cLum = ( cLum < 128 ) ? 0 : 255;
+
+ return Color( rColor.GetTransparency(), cLum, cLum, cLum );
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
+{
+ BitmapEx aRet( rBmpEx );
+
+ aRet.Convert( ( (const ImplBmpConvertParam*) pBmpParam )->eConversion );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam )
+{
+ return( ( (const ImplColMonoParam*) pColParam )->aColor );
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
+{
+ BitmapPalette aPal( 3 );
+
+ aPal[ 0 ] = Color( COL_BLACK );
+ aPal[ 1 ] = Color( COL_WHITE );
+ aPal[ 2 ] = ( (const ImplBmpMonoParam*) pBmpParam )->aColor;
+
+ Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal );
+ aBmp.Erase( ( (const ImplBmpMonoParam*) pBmpParam )->aColor );
+
+ if( rBmpEx.IsAlpha() )
+ return BitmapEx( aBmp, rBmpEx.GetAlpha() );
+ else if( rBmpEx.IsTransparent() )
+ return BitmapEx( aBmp, rBmpEx.GetMask() );
+ else
+ return aBmp;
+}
+
+// ------------------------------------------------------------------------
+
+Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam )
+{
+ const ULONG nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue();
+
+ for( ULONG i = 0; i < ( (const ImplColReplaceParam*) pColParam )->nCount; i++ )
+ {
+ if( ( ( (const ImplColReplaceParam*) pColParam )->pMinR[ i ] <= nR ) &&
+ ( ( (const ImplColReplaceParam*) pColParam )->pMaxR[ i ] >= nR ) &&
+ ( ( (const ImplColReplaceParam*) pColParam )->pMinG[ i ] <= nG ) &&
+ ( ( (const ImplColReplaceParam*) pColParam )->pMaxG[ i ] >= nG ) &&
+ ( ( (const ImplColReplaceParam*) pColParam )->pMinB[ i ] <= nB ) &&
+ ( ( (const ImplColReplaceParam*) pColParam )->pMaxB[ i ] >= nB ) )
+ {
+ return( ( (const ImplColReplaceParam*) pColParam )->pDstCols[ i ] );
+ }
+ }
+
+ return rColor;
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
+{
+ const ImplBmpReplaceParam* p = (const ImplBmpReplaceParam*) pBmpParam;
+ BitmapEx aRet( rBmpEx );
+
+ aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount, p->pTols );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam,
+ BmpExchangeFnc pFncBmp, const void* pBmpParam )
+{
+ GDIMetaFile aMtf;
+
+ aMtf.aPrefSize = aPrefSize;
+ aMtf.aPrefMapMode = aPrefMapMode;
+
+ for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
+ {
+ const USHORT nType = pAction->GetType();
+
+ switch( nType )
+ {
+ case( META_PIXEL_ACTION ):
+ {
+ MetaPixelAction* pAct = (MetaPixelAction*) pAction;
+ aMtf.Insert( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
+ }
+ break;
+
+ case( META_LINECOLOR_ACTION ):
+ {
+ MetaLineColorAction* pAct = (MetaLineColorAction*) pAction;
+
+ if( !pAct->IsSetting() )
+ pAct->Duplicate();
+ else
+ pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE );
+
+ aMtf.Insert( pAct, LIST_APPEND );
+ }
+ break;
+
+ case( META_FILLCOLOR_ACTION ):
+ {
+ MetaFillColorAction* pAct = (MetaFillColorAction*) pAction;
+
+ if( !pAct->IsSetting() )
+ pAct->Duplicate();
+ else
+ pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE );
+
+ aMtf.Insert( pAct, LIST_APPEND );
+ }
+ break;
+
+ case( META_TEXTCOLOR_ACTION ):
+ {
+ MetaTextColorAction* pAct = (MetaTextColorAction*) pAction;
+ aMtf.Insert( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
+ }
+ break;
+
+ case( META_TEXTFILLCOLOR_ACTION ):
+ {
+ MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction;
+
+ if( !pAct->IsSetting() )
+ pAct->Duplicate();
+ else
+ pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE );
+
+ aMtf.Insert( pAct, LIST_APPEND );
+ }
+ break;
+
+ case( META_TEXTLINECOLOR_ACTION ):
+ {
+ MetaTextLineColorAction* pAct = (MetaTextLineColorAction*) pAction;
+
+ if( !pAct->IsSetting() )
+ pAct->Duplicate();
+ else
+ pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE );
+
+ aMtf.Insert( pAct, LIST_APPEND );
+ }
+ break;
+
+ case( META_OVERLINECOLOR_ACTION ):
+ {
+ MetaOverlineColorAction* pAct = (MetaOverlineColorAction*) pAction;
+
+ if( !pAct->IsSetting() )
+ pAct->Duplicate();
+ else
+ pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE );
+
+ aMtf.Insert( pAct, LIST_APPEND );
+ }
+ break;
+
+ case( META_FONT_ACTION ):
+ {
+ MetaFontAction* pAct = (MetaFontAction*) pAction;
+ Font aFont( pAct->GetFont() );
+
+ aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) );
+ aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) );
+ aMtf.Insert( new MetaFontAction( aFont ), LIST_APPEND );
+ }
+ break;
+
+ case( META_WALLPAPER_ACTION ):
+ {
+ MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction;
+ Wallpaper aWall( pAct->GetWallpaper() );
+ const Rectangle& rRect = pAct->GetRect();
+
+ aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) );
+
+ if( aWall.IsBitmap() )
+ aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) );
+
+ if( aWall.IsGradient() )
+ {
+ Gradient aGradient( aWall.GetGradient() );
+
+ aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
+ aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
+ aWall.SetGradient( aGradient );
+ }
+
+ aMtf.Insert( new MetaWallpaperAction( rRect, aWall ), LIST_APPEND );
+ }
+ break;
+
+ case( META_BMP_ACTION ):
+ case( META_BMPEX_ACTION ):
+ case( META_MASK_ACTION ):
+ {
+ DBG_ERROR( "Don't use bitmap actions of this type in metafiles!" );
+ }
+ break;
+
+ case( META_BMPSCALE_ACTION ):
+ {
+ MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
+ aMtf.Insert( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(),
+ pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
+ LIST_APPEND );
+ }
+ break;
+
+ case( META_BMPSCALEPART_ACTION ):
+ {
+ MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
+ aMtf.Insert( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
+ pAct->GetSrcPoint(), pAct->GetSrcSize(),
+ pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
+ LIST_APPEND );
+ }
+ break;
+
+ case( META_BMPEXSCALE_ACTION ):
+ {
+ MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
+ aMtf.Insert( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(),
+ pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
+ LIST_APPEND );
+ }
+ break;
+
+ case( META_BMPEXSCALEPART_ACTION ):
+ {
+ MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
+ aMtf.Insert( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
+ pAct->GetSrcPoint(), pAct->GetSrcSize(),
+ pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
+ LIST_APPEND );
+ }
+ break;
+
+ case( META_MASKSCALE_ACTION ):
+ {
+ MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
+ aMtf.Insert( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(),
+ pAct->GetBitmap(),
+ pFncCol( pAct->GetColor(), pColParam ) ),
+ LIST_APPEND );
+ }
+ break;
+
+ case( META_MASKSCALEPART_ACTION ):
+ {
+ MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
+ aMtf.Insert( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
+ pAct->GetSrcPoint(), pAct->GetSrcSize(),
+ pAct->GetBitmap(),
+ pFncCol( pAct->GetColor(), pColParam ) ),
+ LIST_APPEND );
+ }
+ break;
+
+ case( META_GRADIENT_ACTION ):
+ {
+ MetaGradientAction* pAct = (MetaGradientAction*) pAction;
+ Gradient aGradient( pAct->GetGradient() );
+
+ aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
+ aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
+ aMtf.Insert( new MetaGradientAction( pAct->GetRect(), aGradient ), LIST_APPEND );
+ }
+ break;
+
+ case( META_GRADIENTEX_ACTION ):
+ {
+ MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
+ Gradient aGradient( pAct->GetGradient() );
+
+ aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
+ aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
+ aMtf.Insert( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ), LIST_APPEND );
+ }
+ break;
+
+ case( META_HATCH_ACTION ):
+ {
+ MetaHatchAction* pAct = (MetaHatchAction*) pAction;
+ Hatch aHatch( pAct->GetHatch() );
+
+ aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) );
+ aMtf.Insert( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ), LIST_APPEND );
+ }
+ break;
+
+ case( META_FLOATTRANSPARENT_ACTION ):
+ {
+ MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
+ GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
+
+ aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
+ aMtf.Insert( new MetaFloatTransparentAction( aTransMtf,
+ pAct->GetPoint(), pAct->GetSize(),
+ pAct->GetGradient() ),
+ LIST_APPEND );
+ }
+ break;
+
+ case( META_EPS_ACTION ):
+ {
+ MetaEPSAction* pAct = (MetaEPSAction*) pAction;
+ GDIMetaFile aSubst( pAct->GetSubstitute() );
+
+ aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
+ aMtf.Insert( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(),
+ pAct->GetLink(), aSubst ),
+ LIST_APPEND );
+ }
+ break;
+
+ default:
+ {
+ pAction->Duplicate();
+ aMtf.Insert( pAction, LIST_APPEND );
+ }
+ break;
+ }
+ }
+
+ *this = aMtf;
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent,
+ short nChannelRPercent, short nChannelGPercent,
+ short nChannelBPercent, double fGamma, BOOL bInvert )
+{
+ // nothing to do? => return quickly
+ if( nLuminancePercent || nContrastPercent ||
+ nChannelRPercent || nChannelGPercent || nChannelBPercent ||
+ ( fGamma != 1.0 ) || bInvert )
+ {
+ double fM, fROff, fGOff, fBOff, fOff;
+ ImplColAdjustParam aColParam;
+ ImplBmpAdjustParam aBmpParam;
+
+ aColParam.pMapR = new BYTE[ 256 ];
+ aColParam.pMapG = new BYTE[ 256 ];
+ aColParam.pMapB = new BYTE[ 256 ];
+
+ // calculate slope
+ if( nContrastPercent >= 0 )
+ fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
+ else
+ fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
+
+ // total offset = luminance offset + contrast offset
+ fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
+
+ // channel offset = channel offset + total offset
+ fROff = nChannelRPercent * 2.55 + fOff;
+ fGOff = nChannelGPercent * 2.55 + fOff;
+ fBOff = nChannelBPercent * 2.55 + fOff;
+
+ // calculate gamma value
+ fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
+ const BOOL bGamma = ( fGamma != 1.0 );
+
+ // create mapping table
+ for( long nX = 0L; nX < 256L; nX++ )
+ {
+ aColParam.pMapR[ nX ] = (BYTE) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
+ aColParam.pMapG[ nX ] = (BYTE) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
+ aColParam.pMapB[ nX ] = (BYTE) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
+
+ if( bGamma )
+ {
+ aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma );
+ aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma );
+ aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma );
+ }
+
+ if( bInvert )
+ {
+ aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ];
+ aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ];
+ aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ];
+ }
+ }
+
+ aBmpParam.nLuminancePercent = nLuminancePercent;
+ aBmpParam.nContrastPercent = nContrastPercent;
+ aBmpParam.nChannelRPercent = nChannelRPercent;
+ aBmpParam.nChannelGPercent = nChannelGPercent;
+ aBmpParam.nChannelBPercent = nChannelBPercent;
+ aBmpParam.fGamma = fGamma;
+ aBmpParam.bInvert = bInvert;
+
+ // do color adjustment
+ ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam );
+
+ delete[] aColParam.pMapR;
+ delete[] aColParam.pMapG;
+ delete[] aColParam.pMapB;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::Convert( MtfConversion eConversion )
+{
+ // nothing to do? => return quickly
+ if( eConversion != MTF_CONVERSION_NONE )
+ {
+ ImplColConvertParam aColParam;
+ ImplBmpConvertParam aBmpParam;
+
+ aColParam.eConversion = eConversion;
+ aBmpParam.eConversion = ( MTF_CONVERSION_1BIT_THRESHOLD == eConversion ) ? BMP_CONVERSION_1BIT_THRESHOLD : BMP_CONVERSION_8BIT_GREYS;
+
+ ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::ReplaceColors( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol )
+{
+ ReplaceColors( &rSearchColor, &rReplaceColor, 1, &nTol );
+}
+
+// ------------------------------------------------------------------------
+
+void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, ULONG nColorCount, ULONG* pTols )
+{
+ ImplColReplaceParam aColParam;
+ ImplBmpReplaceParam aBmpParam;
+
+ aColParam.pMinR = new ULONG[ nColorCount ];
+ aColParam.pMaxR = new ULONG[ nColorCount ];
+ aColParam.pMinG = new ULONG[ nColorCount ];
+ aColParam.pMaxG = new ULONG[ nColorCount ];
+ aColParam.pMinB = new ULONG[ nColorCount ];
+ aColParam.pMaxB = new ULONG[ nColorCount ];
+
+ for( ULONG i = 0; i < nColorCount; i++ )
+ {
+ const long nTol = pTols ? ( pTols[ i ] * 255 ) / 100 : 0;
+ long nVal;
+
+ nVal = pSearchColors[ i ].GetRed();
+ aColParam.pMinR[ i ] = (ULONG) Max( nVal - nTol, 0L );
+ aColParam.pMaxR[ i ] = (ULONG) Min( nVal + nTol, 255L );
+
+ nVal = pSearchColors[ i ].GetGreen();
+ aColParam.pMinG[ i ] = (ULONG) Max( nVal - nTol, 0L );
+ aColParam.pMaxG[ i ] = (ULONG) Min( nVal + nTol, 255L );
+
+ nVal = pSearchColors[ i ].GetBlue();
+ aColParam.pMinB[ i ] = (ULONG) Max( nVal - nTol, 0L );
+ aColParam.pMaxB[ i ] = (ULONG) Min( nVal + nTol, 255L );
+ }
+
+ aColParam.pDstCols = pReplaceColors;
+ aColParam.nCount = nColorCount;
+
+ aBmpParam.pSrcCols = pSearchColors;
+ aBmpParam.pDstCols = pReplaceColors;
+ aBmpParam.nCount = nColorCount;
+ aBmpParam.pTols = pTols;
+
+ ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam );
+
+ delete[] aColParam.pMinR;
+ delete[] aColParam.pMaxR;
+ delete[] aColParam.pMinG;
+ delete[] aColParam.pMaxG;
+ delete[] aColParam.pMinB;
+ delete[] aColParam.pMaxB;
+};
+
+// ------------------------------------------------------------------------
+
+GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const
+{
+ GDIMetaFile aRet( *this );
+
+ ImplColMonoParam aColParam;
+ ImplBmpMonoParam aBmpParam;
+
+ aColParam.aColor = rColor;
+ aBmpParam.aColor = rColor;
+
+ aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG GDIMetaFile::GetChecksum() const
+{
+ GDIMetaFile aMtf;
+ SvMemoryStream aMemStm( 65535, 65535 );
+ ImplMetaWriteData aWriteData; aWriteData.meActualCharSet = aMemStm.GetStreamCharSet();
+ SVBT16 aBT16;
+ SVBT32 aBT32;
+ ULONG nCrc = 0;
+
+ for( ULONG i = 0, nObjCount = GetActionCount(); i < nObjCount; i++ )
+ {
+ MetaAction* pAction = GetAction( i );
+
+ switch( pAction->GetType() )
+ {
+ case( META_BMP_ACTION ):
+ {
+ MetaBmpAction* pAct = (MetaBmpAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_BMPSCALE_ACTION ):
+ {
+ MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_BMPSCALEPART_ACTION ):
+ {
+ MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_BMPEX_ACTION ):
+ {
+ MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_BMPEXSCALE_ACTION ):
+ {
+ MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_BMPEXSCALEPART_ACTION ):
+ {
+ MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_MASK_ACTION ):
+ {
+ MetaMaskAction* pAct = (MetaMaskAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_MASKSCALE_ACTION ):
+ {
+ MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case( META_MASKSCALEPART_ACTION ):
+ {
+ MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
+
+ ShortToSVBT16( pAct->GetType(), aBT16 );
+ nCrc = rtl_crc32( nCrc, aBT16, 2 );
+
+ UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+
+ UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
+ nCrc = rtl_crc32( nCrc, aBT32, 4 );
+ }
+ break;
+
+ case META_EPS_ACTION :
+ {
+ MetaEPSAction* pAct = (MetaEPSAction*) pAction;
+ nCrc = rtl_crc32( nCrc, pAct->GetLink().GetData(), pAct->GetLink().GetDataSize() );
+ }
+ break;
+
+ default:
+ {
+ pAction->Write( aMemStm, &aWriteData );
+ nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() );
+ aMemStm.Seek( 0 );
+ }
+ break;
+ }
+ }
+
+ return nCrc;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG GDIMetaFile::GetSizeBytes() const
+{
+ ULONG nSizeBytes = 0;
+
+ for( ULONG i = 0, nObjCount = GetActionCount(); i < nObjCount; ++i )
+ {
+ MetaAction* pAction = GetAction( i );
+
+ // default action size is set to 32 (=> not the exact value)
+ nSizeBytes += 32;
+
+ // add sizes for large action content
+ switch( pAction->GetType() )
+ {
+ case( META_BMP_ACTION ): nSizeBytes += ( (MetaBmpAction*) pAction )->GetBitmap().GetSizeBytes(); break;
+ case( META_BMPSCALE_ACTION ): nSizeBytes += ( (MetaBmpScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
+ case( META_BMPSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
+
+ case( META_BMPEX_ACTION ): nSizeBytes += ( (MetaBmpExAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
+ case( META_BMPEXSCALE_ACTION ): nSizeBytes += ( (MetaBmpExScaleAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
+ case( META_BMPEXSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpExScalePartAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
+
+ case( META_MASK_ACTION ): nSizeBytes += ( (MetaMaskAction*) pAction )->GetBitmap().GetSizeBytes(); break;
+ case( META_MASKSCALE_ACTION ): nSizeBytes += ( (MetaMaskScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
+ case( META_MASKSCALEPART_ACTION ): nSizeBytes += ( (MetaMaskScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
+
+ case( META_POLYLINE_ACTION ): nSizeBytes += ( ( (MetaPolyLineAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
+ case( META_POLYGON_ACTION ): nSizeBytes += ( ( (MetaPolygonAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
+ case( META_POLYPOLYGON_ACTION ):
+ {
+ const PolyPolygon& rPolyPoly = ( (MetaPolyPolygonAction*) pAction )->GetPolyPolygon();
+
+ for( USHORT n = 0; n < rPolyPoly.Count(); ++n )
+ nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) );
+ }
+ break;
+
+ case( META_TEXT_ACTION ): nSizeBytes += ( ( (MetaTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
+ case( META_STRETCHTEXT_ACTION ): nSizeBytes += ( ( (MetaStretchTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
+ case( META_TEXTRECT_ACTION ): nSizeBytes += ( ( (MetaTextRectAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
+ case( META_TEXTARRAY_ACTION ):
+ {
+ MetaTextArrayAction* pTextArrayAction = (MetaTextArrayAction*) pAction;
+
+ nSizeBytes += ( pTextArrayAction->GetText().Len() * sizeof( sal_Unicode ) );
+
+ if( pTextArrayAction->GetDXArray() )
+ nSizeBytes += ( pTextArrayAction->GetLen() << 2 );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return( nSizeBytes );
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile )
+{
+ if( !rIStm.GetError() )
+ {
+ char aId[ 7 ];
+ ULONG nStmPos = rIStm.Tell();
+ USHORT nOldFormat = rIStm.GetNumberFormatInt();
+
+ rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ aId[ 0 ] = 0;
+ aId[ 6 ] = 0;
+ rIStm.Read( aId, 6 );
+
+ if ( !strcmp( aId, "VCLMTF" ) )
+ {
+ // new format
+ VersionCompat* pCompat;
+ MetaAction* pAction;
+ UINT32 nStmCompressMode = 0;
+ UINT32 nCount = 0;
+
+ pCompat = new VersionCompat( rIStm, STREAM_READ );
+
+ rIStm >> nStmCompressMode;
+ rIStm >> rGDIMetaFile.aPrefMapMode;
+ rIStm >> rGDIMetaFile.aPrefSize;
+ rIStm >> nCount;
+
+ delete pCompat;
+
+ ImplMetaReadData aReadData;
+ aReadData.meActualCharSet = rIStm.GetStreamCharSet();
+
+ for( UINT32 nAction = 0UL; ( nAction < nCount ) && !rIStm.IsEof(); nAction++ )
+ {
+ pAction = MetaAction::ReadMetaAction( rIStm, &aReadData );
+
+ if( pAction )
+ rGDIMetaFile.AddAction( pAction );
+ }
+ }
+ else
+ {
+ // to avoid possible compiler optimizations => new/delete
+ rIStm.Seek( nStmPos );
+ delete( new SVMConverter( rIStm, rGDIMetaFile, CONVERT_FROM_SVM1 ) );
+ }
+
+ // check for errors
+ if( rIStm.GetError() )
+ {
+ rGDIMetaFile.Clear();
+ rIStm.Seek( nStmPos );
+ }
+
+ rIStm.SetNumberFormatInt( nOldFormat );
+ }
+
+ return rIStm;
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile )
+{
+ if( !rOStm.GetError() )
+ {
+ if( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 )
+ ((GDIMetaFile&) rGDIMetaFile ).Write( rOStm );
+ else
+ delete( new SVMConverter( rOStm, (GDIMetaFile&) rGDIMetaFile, CONVERT_TO_SVM1 ) );
+ }
+
+ return rOStm;
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& GDIMetaFile::Read( SvStream& rIStm )
+{
+ Clear();
+ rIStm >> *this;
+
+ return rIStm;
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& GDIMetaFile::Write( SvStream& rOStm )
+{
+ VersionCompat* pCompat;
+ const UINT32 nStmCompressMode = rOStm.GetCompressMode();
+ USHORT nOldFormat = rOStm.GetNumberFormatInt();
+
+ rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+ rOStm.Write( "VCLMTF", 6 );
+
+ pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 );
+
+ rOStm << nStmCompressMode;
+ rOStm << aPrefMapMode;
+ rOStm << aPrefSize;
+ rOStm << (UINT32) GetActionCount();
+
+ delete pCompat;
+
+ ImplMetaWriteData aWriteData;
+ aWriteData.meActualCharSet = rOStm.GetStreamCharSet();
+
+ MetaAction* pAct = (MetaAction*)First();
+ while ( pAct )
+ {
+ pAct->Write( rOStm, &aWriteData );
+ pAct = (MetaAction*)Next();
+ }
+
+ rOStm.SetNumberFormatInt( nOldFormat );
+
+ return rOStm;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GDIMetaFile::CreateThumbnail( sal_uInt32 nMaximumExtent,
+ BitmapEx& rBmpEx,
+ const BitmapEx* pOverlay,
+ const Rectangle* pOverlayRect ) const
+{
+ // the implementation is provided by KA
+
+ // initialization seems to be complicated but is used to avoid rounding errors
+ VirtualDevice aVDev;
+ const Point aNullPt;
+ const Point aTLPix( aVDev.LogicToPixel( aNullPt, GetPrefMapMode() ) );
+ const Point aBRPix( aVDev.LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) );
+ Size aDrawSize( aVDev.LogicToPixel( GetPrefSize(), GetPrefMapMode() ) );
+ Size aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
+ Point aPosPix;
+
+ if ( !rBmpEx.IsEmpty() )
+ rBmpEx.SetEmpty();
+
+ // determine size that has the same aspect ratio as image size and
+ // fits into the rectangle determined by nMaximumExtent
+ if ( aSizePix.Width() && aSizePix.Height()
+ && ( sal::static_int_cast< unsigned long >(aSizePix.Width()) >
+ nMaximumExtent ||
+ sal::static_int_cast< unsigned long >(aSizePix.Height()) >
+ nMaximumExtent ) )
+ {
+ const Size aOldSizePix( aSizePix );
+ double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height();
+
+ if ( fWH <= 1.0 )
+ {
+ aSizePix.Width() = FRound( nMaximumExtent * fWH );
+ aSizePix.Height() = nMaximumExtent;
+ }
+ else
+ {
+ aSizePix.Width() = nMaximumExtent;
+ aSizePix.Height() = FRound( nMaximumExtent / fWH );
+ }
+
+ aDrawSize.Width() = FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() );
+ aDrawSize.Height() = FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() );
+ }
+
+ Size aFullSize;
+ Point aBackPosPix;
+ Rectangle aOverlayRect;
+
+ // calculate addigtional positions and sizes if an overlay image is used
+ if ( pOverlay )
+ {
+ aFullSize = Size( nMaximumExtent, nMaximumExtent );
+ aOverlayRect = Rectangle( aNullPt, aFullSize );
+
+ aOverlayRect.Intersection( pOverlayRect ? *pOverlayRect : Rectangle( aNullPt, pOverlay->GetSizePixel() ) );
+
+ if ( !aOverlayRect.IsEmpty() )
+ aBackPosPix = Point( ( nMaximumExtent - aSizePix.Width() ) >> 1, ( nMaximumExtent - aSizePix.Height() ) >> 1 );
+ else
+ pOverlay = NULL;
+ }
+ else
+ {
+ aFullSize = aSizePix;
+ pOverlay = NULL;
+ }
+
+ // draw image(s) into VDev and get resulting image
+ if ( aVDev.SetOutputSizePixel( aFullSize ) )
+ {
+ // draw metafile into VDev
+ const_cast<GDIMetaFile *>(this)->WindStart();
+ const_cast<GDIMetaFile *>(this)->Play( &aVDev, aBackPosPix, aDrawSize );
+
+ // draw overlay if neccessary
+ if ( pOverlay )
+ aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), *pOverlay );
+
+ // get paint bitmap
+ Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
+
+ // assure that we have a true color image
+ if ( aBmp.GetBitCount() != 24 )
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+
+ // create resulting mask bitmap with metafile output set to black
+ GDIMetaFile aMonchromeMtf( GetMonochromeMtf( COL_BLACK ) );
+ aVDev.DrawWallpaper( Rectangle( aNullPt, aSizePix ), Wallpaper( Color( COL_WHITE ) ) );
+ aMonchromeMtf.WindStart();
+ aMonchromeMtf.Play( &aVDev, aBackPosPix, aDrawSize );
+
+ // watch for overlay mask
+ if ( pOverlay )
+ {
+ Bitmap aOverlayMergeBmp( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ) );
+
+ // create ANDed resulting mask at overlay area
+ if ( pOverlay->IsTransparent() )
+ aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), pOverlay->GetMask() );
+ else
+ {
+ aVDev.SetLineColor( COL_BLACK );
+ aVDev.SetFillColor( COL_BLACK );
+ aVDev.DrawRect( aOverlayRect);
+ }
+
+ aOverlayMergeBmp.CombineSimple( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ), BMP_COMBINE_AND );
+ aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), aOverlayMergeBmp );
+ }
+
+ rBmpEx = BitmapEx( aBmp, aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
+ }
+
+ return !rBmpEx.IsEmpty();
+}
diff --git a/vcl/source/gdi/gfxlink.cxx b/vcl/source/gdi/gfxlink.cxx
new file mode 100644
index 000000000000..60ad94a63273
--- /dev/null
+++ b/vcl/source/gdi/gfxlink.cxx
@@ -0,0 +1,469 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <osl/file.h>
+#include <tools/vcompat.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/tempfile.hxx>
+#include <ucbhelper/content.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/gfxlink.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <com/sun/star/ucb/CommandAbortedException.hpp>
+
+// -----------
+// - GfxLink -
+// -----------
+
+GfxLink::GfxLink() :
+ meType ( GFX_LINK_TYPE_NONE ),
+ mpBuf ( NULL ),
+ mpSwap ( NULL ),
+ mnBufSize ( 0 ),
+ mnUserId ( 0UL ),
+ mpImpData ( new ImpGfxLink )
+{
+}
+
+// ------------------------------------------------------------------------
+
+GfxLink::GfxLink( const GfxLink& rGfxLink ) :
+ mpImpData( new ImpGfxLink )
+{
+ ImplCopy( rGfxLink );
+}
+
+// ------------------------------------------------------------------------
+
+GfxLink::GfxLink( BYTE* pBuf, sal_uInt32 nSize, GfxLinkType nType, BOOL bOwns ) :
+ mpImpData( new ImpGfxLink )
+{
+ DBG_ASSERT( (pBuf != NULL && nSize) || (!bOwns && nSize == 0),
+ "GfxLink::GfxLink(): empty/NULL buffer given" );
+
+ meType = nType;
+ mnBufSize = nSize;
+ mpSwap = NULL;
+ mnUserId = 0UL;
+
+ if( bOwns )
+ mpBuf = new ImpBuffer( pBuf );
+ else if( nSize )
+ {
+ mpBuf = new ImpBuffer( nSize );
+ memcpy( mpBuf->mpBuffer, pBuf, nSize );
+ }
+ else
+ mpBuf = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+GfxLink::~GfxLink()
+{
+ if( mpBuf && !( --mpBuf->mnRefCount ) )
+ delete mpBuf;
+
+ if( mpSwap && !( --mpSwap->mnRefCount ) )
+ delete mpSwap;
+
+ delete mpImpData;
+}
+
+// ------------------------------------------------------------------------
+
+GfxLink& GfxLink::operator=( const GfxLink& rGfxLink )
+{
+ if( &rGfxLink != this )
+ {
+ if ( mpBuf && !( --mpBuf->mnRefCount ) )
+ delete mpBuf;
+
+ if( mpSwap && !( --mpSwap->mnRefCount ) )
+ delete mpSwap;
+
+ ImplCopy( rGfxLink );
+ }
+
+ return *this;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool GfxLink::IsEqual( const GfxLink& rGfxLink ) const
+{
+ sal_Bool bIsEqual = sal_False;
+
+ if ( ( mnBufSize == rGfxLink.mnBufSize ) && ( meType == rGfxLink.meType ) )
+ {
+ const sal_uInt8* pSource = GetData();
+ const sal_uInt8* pDest = rGfxLink.GetData();
+ sal_uInt32 nSourceSize = GetDataSize();
+ sal_uInt32 nDestSize = rGfxLink.GetDataSize();
+ if ( pSource && pDest && ( nSourceSize == nDestSize ) )
+ {
+ bIsEqual = memcmp( pSource, pDest, nSourceSize ) == 0;
+ }
+ else if ( ( pSource == 0 ) && ( pDest == 0 ) )
+ bIsEqual = sal_True;
+ }
+ return bIsEqual;
+}
+
+// ------------------------------------------------------------------------
+
+void GfxLink::ImplCopy( const GfxLink& rGfxLink )
+{
+ mnBufSize = rGfxLink.mnBufSize;
+ meType = rGfxLink.meType;
+ mpBuf = rGfxLink.mpBuf;
+ mpSwap = rGfxLink.mpSwap;
+ mnUserId = rGfxLink.mnUserId;
+ *mpImpData = *rGfxLink.mpImpData;
+
+ if( mpBuf )
+ mpBuf->mnRefCount++;
+
+ if( mpSwap )
+ mpSwap->mnRefCount++;
+}
+
+// ------------------------------------------------------------------------
+
+GfxLinkType GfxLink::GetType() const
+{
+ return meType;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GfxLink::IsNative() const
+{
+ return( meType >= GFX_LINK_FIRST_NATIVE_ID && meType <= GFX_LINK_LAST_NATIVE_ID );
+}
+
+// ------------------------------------------------------------------------
+
+sal_uInt32 GfxLink::GetDataSize() const
+{
+ return mnBufSize;
+}
+
+// ------------------------------------------------------------------------
+
+const BYTE* GfxLink::GetData() const
+{
+ if( IsSwappedOut() )
+ ( (GfxLink*) this )->SwapIn();
+
+ return( mpBuf ? mpBuf->mpBuffer : NULL );
+}
+
+// ------------------------------------------------------------------------
+
+const Size& GfxLink::GetPrefSize() const
+{
+ return mpImpData->maPrefSize;
+}
+
+// ------------------------------------------------------------------------
+
+void GfxLink::SetPrefSize( const Size& rPrefSize )
+{
+ mpImpData->maPrefSize = rPrefSize;
+ mpImpData->mbPrefSizeValid = true;
+}
+
+// ------------------------------------------------------------------------
+
+bool GfxLink::IsPrefSizeValid()
+{
+ return mpImpData->mbPrefSizeValid;
+}
+
+// ------------------------------------------------------------------------
+
+const MapMode& GfxLink::GetPrefMapMode() const
+{
+ return mpImpData->maPrefMapMode;
+}
+
+// ------------------------------------------------------------------------
+
+void GfxLink::SetPrefMapMode( const MapMode& rPrefMapMode )
+{
+ mpImpData->maPrefMapMode = rPrefMapMode;
+ mpImpData->mbPrefMapModeValid = true;
+}
+
+// ------------------------------------------------------------------------
+
+bool GfxLink::IsPrefMapModeValid()
+{
+ return mpImpData->mbPrefMapModeValid;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GfxLink::LoadNative( Graphic& rGraphic )
+{
+ BOOL bRet = FALSE;
+
+ if( IsNative() && mnBufSize )
+ {
+ const BYTE* pData = GetData();
+
+ if( pData )
+ {
+ SvMemoryStream aMemStm;
+ ULONG nCvtType;
+
+ aMemStm.SetBuffer( (char*) pData, mnBufSize, FALSE, mnBufSize );
+
+ switch( meType )
+ {
+ case( GFX_LINK_TYPE_NATIVE_GIF ): nCvtType = CVT_GIF; break;
+ case( GFX_LINK_TYPE_NATIVE_JPG ): nCvtType = CVT_JPG; break;
+ case( GFX_LINK_TYPE_NATIVE_PNG ): nCvtType = CVT_PNG; break;
+ case( GFX_LINK_TYPE_NATIVE_TIF ): nCvtType = CVT_TIF; break;
+ case( GFX_LINK_TYPE_NATIVE_WMF ): nCvtType = CVT_WMF; break;
+ case( GFX_LINK_TYPE_NATIVE_MET ): nCvtType = CVT_MET; break;
+ case( GFX_LINK_TYPE_NATIVE_PCT ): nCvtType = CVT_PCT; break;
+
+ default: nCvtType = CVT_UNKNOWN; break;
+ }
+
+ if( nCvtType && ( GraphicConverter::Import( aMemStm, rGraphic, nCvtType ) == ERRCODE_NONE ) )
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void GfxLink::SwapOut()
+{
+ if( !IsSwappedOut() && mpBuf )
+ {
+ mpSwap = new ImpSwap( mpBuf->mpBuffer, mnBufSize );
+
+ if( !mpSwap->IsSwapped() )
+ {
+ delete mpSwap;
+ mpSwap = NULL;
+ }
+ else
+ {
+ if( !( --mpBuf->mnRefCount ) )
+ delete mpBuf;
+
+ mpBuf = NULL;
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void GfxLink::SwapIn()
+{
+ if( IsSwappedOut() )
+ {
+ mpBuf = new ImpBuffer( mpSwap->GetData() );
+
+ if( !( --mpSwap->mnRefCount ) )
+ delete mpSwap;
+
+ mpSwap = NULL;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GfxLink::ExportNative( SvStream& rOStream ) const
+{
+ if( GetDataSize() )
+ {
+ if( IsSwappedOut() )
+ mpSwap->WriteTo( rOStream );
+ else if( GetData() )
+ rOStream.Write( GetData(), GetDataSize() );
+ }
+
+ return ( rOStream.GetError() == ERRCODE_NONE );
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const GfxLink& rGfxLink )
+{
+ VersionCompat* pCompat = new VersionCompat( rOStream, STREAM_WRITE, 2 );
+
+ // Version 1
+ rOStream << (UINT16) rGfxLink.GetType() << rGfxLink.GetDataSize() << rGfxLink.GetUserId();
+
+ // Version 2
+ rOStream << rGfxLink.GetPrefSize() << rGfxLink.GetPrefMapMode();
+
+ delete pCompat;
+
+ if( rGfxLink.GetDataSize() )
+ {
+ if( rGfxLink.IsSwappedOut() )
+ rGfxLink.mpSwap->WriteTo( rOStream );
+ else if( rGfxLink.GetData() )
+ rOStream.Write( rGfxLink.GetData(), rGfxLink.GetDataSize() );
+ }
+
+ return rOStream;
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStream, GfxLink& rGfxLink)
+{
+ Size aSize;
+ MapMode aMapMode;
+ sal_uInt32 nSize;
+ sal_uInt32 nUserId;
+ UINT16 nType;
+ BYTE* pBuf;
+ bool bMapAndSizeValid( false );
+ VersionCompat* pCompat = new VersionCompat( rIStream, STREAM_READ );
+
+ // Version 1
+ rIStream >> nType >> nSize >> nUserId;
+
+ if( pCompat->GetVersion() >= 2 )
+ {
+ rIStream >> aSize >> aMapMode;
+ bMapAndSizeValid = true;
+ }
+
+ delete pCompat;
+
+ pBuf = new BYTE[ nSize ];
+ rIStream.Read( pBuf, nSize );
+
+ rGfxLink = GfxLink( pBuf, nSize, (GfxLinkType) nType, TRUE );
+ rGfxLink.SetUserId( nUserId );
+
+ if( bMapAndSizeValid )
+ {
+ rGfxLink.SetPrefSize( aSize );
+ rGfxLink.SetPrefMapMode( aMapMode );
+ }
+
+ return rIStream;
+}
+
+// -----------
+// - ImpSwap -
+// -----------
+
+ImpSwap::ImpSwap( BYTE* pData, ULONG nDataSize ) :
+ mnDataSize( nDataSize ),
+ mnRefCount( 1UL )
+{
+ if( pData && mnDataSize )
+ {
+ ::utl::TempFile aTempFile;
+
+ maURL = aTempFile.GetURL();
+ if( maURL.getLength() )
+ {
+ SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( maURL, STREAM_READWRITE | STREAM_SHARE_DENYWRITE );
+ if( pOStm )
+ {
+ pOStm->Write( pData, mnDataSize );
+ sal_Bool bError = ( ERRCODE_NONE != pOStm->GetError() );
+ delete pOStm;
+
+ if( bError )
+ {
+ osl_removeFile( maURL.pData );
+ maURL = String();
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+ImpSwap::~ImpSwap()
+{
+ if( IsSwapped() )
+ osl_removeFile( maURL.pData );
+}
+
+// ------------------------------------------------------------------------
+
+BYTE* ImpSwap::GetData() const
+{
+ BYTE* pData;
+
+ if( IsSwapped() )
+ {
+ SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( maURL, STREAM_READWRITE );
+ if( pIStm )
+ {
+ pData = new BYTE[ mnDataSize ];
+ pIStm->Read( pData, mnDataSize );
+ sal_Bool bError = ( ERRCODE_NONE != pIStm->GetError() );
+ delete pIStm;
+
+ if( bError )
+ delete[] pData, pData = NULL;
+ }
+ else
+ pData = NULL;
+ }
+ else
+ pData = NULL;
+
+ return pData;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpSwap::WriteTo( SvStream& rOStm ) const
+{
+ BYTE* pData = GetData();
+
+ if( pData )
+ {
+ rOStm.Write( pData, mnDataSize );
+ delete[] pData;
+ }
+}
diff --git a/vcl/source/gdi/gradient.cxx b/vcl/source/gdi/gradient.cxx
new file mode 100644
index 000000000000..9856e2213d85
--- /dev/null
+++ b/vcl/source/gdi/gradient.cxx
@@ -0,0 +1,344 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/debug.hxx>
+#include <vcl/gradient.hxx>
+
+// =======================================================================
+
+DBG_NAME( Gradient )
+
+// -----------------------------------------------------------------------
+
+Impl_Gradient::Impl_Gradient() :
+ maStartColor( COL_BLACK ),
+ maEndColor( COL_WHITE )
+{
+ mnRefCount = 1;
+ meStyle = GRADIENT_LINEAR;
+ mnAngle = 0;
+ mnBorder = 0;
+ mnOfsX = 50;
+ mnOfsY = 50;
+ mnIntensityStart = 100;
+ mnIntensityEnd = 100;
+ mnStepCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+Impl_Gradient::Impl_Gradient( const Impl_Gradient& rImplGradient ) :
+ maStartColor( rImplGradient.maStartColor ),
+ maEndColor( rImplGradient.maEndColor )
+{
+ mnRefCount = 1;
+ meStyle = rImplGradient.meStyle;
+ mnAngle = rImplGradient.mnAngle;
+ mnBorder = rImplGradient.mnBorder;
+ mnOfsX = rImplGradient.mnOfsX;
+ mnOfsY = rImplGradient.mnOfsY;
+ mnIntensityStart = rImplGradient.mnIntensityStart;
+ mnIntensityEnd = rImplGradient.mnIntensityEnd;
+ mnStepCount = rImplGradient.mnStepCount;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::MakeUnique()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpImplGradient->mnRefCount != 1 )
+ {
+ if( mpImplGradient->mnRefCount )
+ mpImplGradient->mnRefCount--;
+
+ mpImplGradient = new Impl_Gradient( *mpImplGradient );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Gradient::Gradient()
+{
+ DBG_CTOR( Gradient, NULL );
+
+ mpImplGradient = new Impl_Gradient;
+}
+
+// -----------------------------------------------------------------------
+
+Gradient::Gradient( const Gradient& rGradient )
+{
+ DBG_CTOR( Gradient, NULL );
+ DBG_CHKOBJ( &rGradient, Gradient, NULL );
+
+ // Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpImplGradient = rGradient.mpImplGradient;
+ mpImplGradient->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+Gradient::Gradient( GradientStyle eStyle )
+{
+ DBG_CTOR( Gradient, NULL );
+
+ mpImplGradient = new Impl_Gradient;
+ mpImplGradient->meStyle = eStyle;
+}
+
+// -----------------------------------------------------------------------
+
+Gradient::Gradient( GradientStyle eStyle,
+ const Color& rStartColor, const Color& rEndColor )
+{
+ DBG_CTOR( Gradient, NULL );
+
+ mpImplGradient = new Impl_Gradient;
+ mpImplGradient->meStyle = eStyle;
+ mpImplGradient->maStartColor = rStartColor;
+ mpImplGradient->maEndColor = rEndColor;
+}
+
+// -----------------------------------------------------------------------
+
+Gradient::~Gradient()
+{
+ DBG_DTOR( Gradient, NULL );
+
+ // Wenn es die letzte Referenz ist, loeschen,
+ // sonst Referenzcounter decrementieren
+ if ( mpImplGradient->mnRefCount == 1 )
+ delete mpImplGradient;
+ else
+ mpImplGradient->mnRefCount--;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetStyle( GradientStyle eStyle )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->meStyle = eStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetStartColor( const Color& rColor )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->maStartColor = rColor;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetEndColor( const Color& rColor )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->maEndColor = rColor;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetAngle( USHORT nAngle )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->mnAngle = nAngle;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetBorder( USHORT nBorder )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->mnBorder = nBorder;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetOfsX( USHORT nOfsX )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->mnOfsX = nOfsX;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetOfsY( USHORT nOfsY )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->mnOfsY = nOfsY;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetStartIntensity( USHORT nIntens )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->mnIntensityStart = nIntens;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetEndIntensity( USHORT nIntens )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->mnIntensityEnd = nIntens;
+}
+
+// -----------------------------------------------------------------------
+
+void Gradient::SetSteps( USHORT nSteps )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+
+ MakeUnique();
+ mpImplGradient->mnStepCount = nSteps;
+}
+
+// -----------------------------------------------------------------------
+
+Gradient& Gradient::operator=( const Gradient& rGradient )
+{
+ DBG_CHKTHIS( Gradient, NULL );
+ DBG_CHKOBJ( &rGradient, Gradient, NULL );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ rGradient.mpImplGradient->mnRefCount++;
+
+ // Wenn es die letzte Referenz ist, loeschen,
+ // sonst Referenzcounter decrementieren
+ if ( mpImplGradient->mnRefCount == 1 )
+ delete mpImplGradient;
+ else
+ mpImplGradient->mnRefCount--;
+ mpImplGradient = rGradient.mpImplGradient;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Gradient::operator==( const Gradient& rGradient ) const
+{
+ DBG_CHKTHIS( Gradient, NULL );
+ DBG_CHKOBJ( &rGradient, Gradient, NULL );
+
+ if ( mpImplGradient == rGradient.mpImplGradient )
+ return TRUE;
+
+ if ( (mpImplGradient->meStyle == rGradient.mpImplGradient->meStyle) ||
+ (mpImplGradient->mnAngle == rGradient.mpImplGradient->mnAngle) ||
+ (mpImplGradient->mnBorder == rGradient.mpImplGradient->mnBorder) ||
+ (mpImplGradient->mnOfsX == rGradient.mpImplGradient->mnOfsX) ||
+ (mpImplGradient->mnOfsY == rGradient.mpImplGradient->mnOfsY) ||
+ (mpImplGradient->mnStepCount == rGradient.mpImplGradient->mnStepCount) ||
+ (mpImplGradient->mnIntensityStart == rGradient.mpImplGradient->mnIntensityStart) ||
+ (mpImplGradient->mnIntensityEnd == rGradient.mpImplGradient->mnIntensityEnd) ||
+ (mpImplGradient->maStartColor == rGradient.mpImplGradient->maStartColor) ||
+ (mpImplGradient->maEndColor == rGradient.mpImplGradient->maEndColor) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+SvStream& operator>>( SvStream& rIStm, Impl_Gradient& rImpl_Gradient )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+ UINT16 nTmp16;
+
+ rIStm >> nTmp16; rImpl_Gradient.meStyle = (GradientStyle) nTmp16;
+
+ rIStm >> rImpl_Gradient.maStartColor >>
+ rImpl_Gradient.maEndColor >>
+ rImpl_Gradient.mnAngle >>
+ rImpl_Gradient.mnBorder >>
+ rImpl_Gradient.mnOfsX >>
+ rImpl_Gradient.mnOfsY >>
+ rImpl_Gradient.mnIntensityStart >>
+ rImpl_Gradient.mnIntensityEnd >>
+ rImpl_Gradient.mnStepCount;
+
+ return rIStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Impl_Gradient& rImpl_Gradient )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 1 );
+
+ rOStm << (UINT16) rImpl_Gradient.meStyle <<
+ rImpl_Gradient.maStartColor <<
+ rImpl_Gradient.maEndColor <<
+ rImpl_Gradient.mnAngle <<
+ rImpl_Gradient.mnBorder <<
+ rImpl_Gradient.mnOfsX <<
+ rImpl_Gradient.mnOfsY <<
+ rImpl_Gradient.mnIntensityStart <<
+ rImpl_Gradient.mnIntensityEnd <<
+ rImpl_Gradient.mnStepCount;
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, Gradient& rGradient )
+{
+ rGradient.MakeUnique();
+ return( rIStm >> *rGradient.mpImplGradient );
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Gradient& rGradient )
+{
+ return( rOStm << *rGradient.mpImplGradient );
+}
diff --git a/vcl/source/gdi/graph.cxx b/vcl/source/gdi/graph.cxx
new file mode 100644
index 000000000000..790c3d43bb85
--- /dev/null
+++ b/vcl/source/gdi/graph.cxx
@@ -0,0 +1,814 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/impgraph.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/graph.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+// -----------------------
+// - Compression defines -
+// -----------------------
+
+#define COMPRESS_OWN ('S'|('D'<<8UL))
+#define COMPRESS_NONE ( 0UL )
+#define RLE_8 ( 1UL )
+#define RLE_4 ( 2UL )
+#define BITFIELDS ( 3UL )
+#define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */
+
+using namespace ::com::sun::star;
+
+// -----------------------
+// - Default-Drawmethode -
+// -----------------------
+
+static void ImplDrawDefault( OutputDevice* pOutDev, const UniString* pText,
+ Font* pFont, const Bitmap* pBitmap, const BitmapEx* pBitmapEx,
+ const Point& rDestPt, const Size& rDestSize )
+{
+ USHORT nPixel = (USHORT) pOutDev->PixelToLogic( Size( 1, 1 ) ).Width();
+ USHORT nPixelWidth = nPixel;
+ Point aPoint( rDestPt.X() + nPixelWidth, rDestPt.Y() + nPixelWidth );
+ Size aSize( rDestSize.Width() - ( nPixelWidth << 1 ), rDestSize.Height() - ( nPixelWidth << 1 ) );
+ BOOL bFilled = ( pBitmap != NULL || pBitmapEx != NULL || pFont != NULL );
+ Rectangle aBorderRect( aPoint, aSize );
+
+ pOutDev->Push();
+
+ pOutDev->SetFillColor();
+
+ // Auf dem Drucker ein schwarzes Rechteck und auf dem Bildschirm eins mit 3D-Effekt
+ if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER )
+ pOutDev->SetLineColor( COL_BLACK );
+ else
+ {
+ aBorderRect.Left() += nPixel;
+ aBorderRect.Top() += nPixel;
+
+ pOutDev->SetLineColor( COL_LIGHTGRAY );
+ pOutDev->DrawRect( aBorderRect );
+
+ aBorderRect.Left() -= nPixel;
+ aBorderRect.Top() -= nPixel;
+ aBorderRect.Right() -= nPixel;
+ aBorderRect.Bottom() -= nPixel;
+ pOutDev->SetLineColor( COL_GRAY );
+ }
+
+ pOutDev->DrawRect( aBorderRect );
+
+ aPoint.X() += nPixelWidth + 2*nPixel;
+ aPoint.Y() += nPixelWidth + 2*nPixel;
+ aSize.Width() -= 2*nPixelWidth + 4*nPixel;
+ aSize.Height() -= 2*nPixelWidth + 4*nPixel;
+
+ if( aSize.Width() > 0 && aSize.Height() > 0
+ && ( ( pBitmap && !!*pBitmap ) || ( pBitmapEx && !!*pBitmapEx ) ) )
+ {
+ Size aBitmapSize( pOutDev->PixelToLogic( pBitmap ? pBitmap->GetSizePixel() : pBitmapEx->GetSizePixel() ) );
+
+ if( aSize.Height() > aBitmapSize.Height() && aSize.Width() > aBitmapSize.Width() )
+ {
+ if ( pBitmap )
+ pOutDev->DrawBitmap( aPoint, *pBitmap );
+ else
+ pOutDev->DrawBitmapEx( aPoint, *pBitmapEx );
+ aPoint.X() += aBitmapSize.Width() + 2*nPixel;
+ aSize.Width() -= aBitmapSize.Width() + 2*nPixel;
+ }
+ }
+
+ if ( aSize.Width() > 0 && aSize.Height() > 0 && pFont && pText && pText->Len()
+ && !(!pOutDev->IsOutputEnabled() /*&& pOutDev->GetConnectMetaFile() */) )
+ {
+ MapMode aMapMode( MAP_POINT );
+ Size aSz = pOutDev->LogicToLogic( Size( 0, 12 ), &aMapMode, NULL );
+ long nThreshold = aSz.Height() / 2;
+ long nStep = nThreshold / 3;
+
+ if ( !nStep )
+ nStep = aSz.Height() - nThreshold;
+
+ for(;; aSz.Height() -= nStep )
+ {
+ pFont->SetSize( aSz );
+ pOutDev->SetFont( *pFont );
+
+ long nTextHeight = pOutDev->GetTextHeight();
+ long nTextWidth = pOutDev->GetTextWidth( *pText );
+ if ( nTextHeight )
+ {
+ // Die N"aherung ber"ucksichtigt keine Ungenauigkeiten durch
+ // Wortumbr"uche
+ long nLines = aSize.Height() / nTextHeight;
+ long nWidth = aSize.Width() * nLines; // N"aherung!!!
+
+ if ( nTextWidth <= nWidth || aSz.Height() <= nThreshold )
+ {
+ USHORT nStart = 0;
+ USHORT nLen = 0;
+
+ while( nStart < pText->Len() && pText->GetChar( nStart ) == ' ' )
+ nStart++;
+ while( nStart+nLen < pText->Len() && pText->GetChar( nStart+nLen ) != ' ' )
+ nLen++;
+ while( nStart < pText->Len() && nLines-- )
+ {
+ USHORT nNext = nLen;
+ do
+ {
+ while ( nStart+nNext < pText->Len() && pText->GetChar( nStart+nNext ) == ' ' )
+ nNext++;
+ while ( nStart+nNext < pText->Len() && pText->GetChar( nStart+nNext ) != ' ' )
+ nNext++;
+ nTextWidth = pOutDev->GetTextWidth( *pText, nStart, nNext );
+ if ( nTextWidth > aSize.Width() )
+ break;
+ nLen = nNext;
+ }
+ while ( nStart+nNext < pText->Len() );
+
+ USHORT n = nLen;
+ nTextWidth = pOutDev->GetTextWidth( *pText, nStart, n );
+ while( nTextWidth > aSize.Width() )
+ nTextWidth = pOutDev->GetTextWidth( *pText, nStart, --n );
+ pOutDev->DrawText( aPoint, *pText, nStart, n );
+
+ aPoint.Y() += nTextHeight;
+ nStart = sal::static_int_cast<USHORT>(nStart + nLen);
+ nLen = nNext-nLen;
+ while( nStart < pText->Len() && pText->GetChar( nStart ) == ' ' )
+ {
+ nStart++;
+ nLen--;
+ }
+ }
+ break;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ // Falls die Default-Graphik keinen Inhalt hat,
+ // malen wir ein rotes Kreuz
+ if( !bFilled )
+ {
+ aBorderRect.Left()++;
+ aBorderRect.Top()++;
+ aBorderRect.Right()--;
+ aBorderRect.Bottom()--;
+
+ pOutDev->SetLineColor( COL_LIGHTRED );
+ pOutDev->DrawLine( aBorderRect.TopLeft(), aBorderRect.BottomRight() );
+ pOutDev->DrawLine( aBorderRect.TopRight(), aBorderRect.BottomLeft() );
+ }
+
+ pOutDev->Pop();
+}
+
+// -----------
+// - Graphic -
+// -----------
+
+TYPEINIT1_AUTOFACTORY( Graphic, SvDataCopyStream );
+
+// ------------------------------------------------------------------------
+
+Graphic::Graphic()
+{
+ mpImpGraphic = new ImpGraphic;
+}
+
+// ------------------------------------------------------------------------
+
+Graphic::Graphic( const Graphic& rGraphic ) :
+SvDataCopyStream()
+{
+ if( rGraphic.IsAnimated() )
+ mpImpGraphic = new ImpGraphic( *rGraphic.mpImpGraphic );
+ else
+ {
+ mpImpGraphic = rGraphic.mpImpGraphic;
+ mpImpGraphic->mnRefCount++;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+Graphic::Graphic( const Bitmap& rBmp )
+{
+ mpImpGraphic = new ImpGraphic( rBmp );
+}
+
+// ------------------------------------------------------------------------
+
+Graphic::Graphic( const BitmapEx& rBmpEx )
+{
+ mpImpGraphic = new ImpGraphic( rBmpEx );
+}
+
+// ------------------------------------------------------------------------
+
+Graphic::Graphic( const Animation& rAnimation )
+{
+ mpImpGraphic = new ImpGraphic( rAnimation );
+}
+
+// ------------------------------------------------------------------------
+
+Graphic::Graphic( const GDIMetaFile& rMtf )
+{
+ mpImpGraphic = new ImpGraphic( rMtf );
+}
+
+// ------------------------------------------------------------------------
+
+Graphic::Graphic( const ::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic >& rxGraphic )
+{
+ uno::Reference< lang::XUnoTunnel > xTunnel( rxGraphic, uno::UNO_QUERY );
+ uno::Reference< lang::XTypeProvider > xProv( rxGraphic, uno::UNO_QUERY );
+ const ::Graphic* pGraphic = ( ( xTunnel.is() && xProv.is() ) ?
+ reinterpret_cast< ::Graphic* >( xTunnel->getSomething( xProv->getImplementationId() ) ) :
+ NULL );
+
+ if( pGraphic )
+ {
+ if( pGraphic->IsAnimated() )
+ mpImpGraphic = new ImpGraphic( *pGraphic->mpImpGraphic );
+ else
+ {
+ mpImpGraphic = pGraphic->mpImpGraphic;
+ mpImpGraphic->mnRefCount++;
+ }
+ }
+ else
+ mpImpGraphic = new ImpGraphic;
+}
+
+// ------------------------------------------------------------------------
+
+Graphic::~Graphic()
+{
+ if( mpImpGraphic->mnRefCount == 1UL )
+ delete mpImpGraphic;
+ else
+ mpImpGraphic->mnRefCount--;
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::ImplTestRefCount()
+{
+ if( mpImpGraphic->mnRefCount > 1UL )
+ {
+ mpImpGraphic->mnRefCount--;
+ mpImpGraphic = new ImpGraphic( *mpImpGraphic );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+Graphic& Graphic::operator=( const Graphic& rGraphic )
+{
+ if( &rGraphic != this )
+ {
+ if( rGraphic.IsAnimated() )
+ {
+ if( mpImpGraphic->mnRefCount == 1UL )
+ delete mpImpGraphic;
+ else
+ mpImpGraphic->mnRefCount--;
+
+ mpImpGraphic = new ImpGraphic( *rGraphic.mpImpGraphic );
+ }
+ else
+ {
+ rGraphic.mpImpGraphic->mnRefCount++;
+
+ if( mpImpGraphic->mnRefCount == 1UL )
+ delete mpImpGraphic;
+ else
+ mpImpGraphic->mnRefCount--;
+
+ mpImpGraphic = rGraphic.mpImpGraphic;
+ }
+ }
+
+ return *this;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::operator==( const Graphic& rGraphic ) const
+{
+ return( *mpImpGraphic == *rGraphic.mpImpGraphic );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::operator!=( const Graphic& rGraphic ) const
+{
+ return( *mpImpGraphic != *rGraphic.mpImpGraphic );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::operator!() const
+{
+ return( GRAPHIC_NONE == mpImpGraphic->ImplGetType() );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::Load( SvStream& rIStm )
+{
+ rIStm >> *this;
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::Save( SvStream& rOStm )
+{
+ rOStm << *this;
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::Assign( const SvDataCopyStream& rCopyStream )
+{
+ *this = (const Graphic& ) rCopyStream;
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::Clear()
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplClear();
+}
+
+// ------------------------------------------------------------------------
+
+GraphicType Graphic::GetType() const
+{
+ return mpImpGraphic->ImplGetType();
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::SetDefaultType()
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplSetDefaultType();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::IsSupportedGraphic() const
+{
+ return mpImpGraphic->ImplIsSupportedGraphic();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::IsTransparent() const
+{
+ return mpImpGraphic->ImplIsTransparent();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::IsAlpha() const
+{
+ return mpImpGraphic->ImplIsAlpha();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::IsAnimated() const
+{
+ return mpImpGraphic->ImplIsAnimated();
+}
+
+// ------------------------------------------------------------------------
+
+Bitmap Graphic::GetBitmap(const GraphicConversionParameters& rParameters) const
+{
+ return mpImpGraphic->ImplGetBitmap(rParameters);
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx Graphic::GetBitmapEx(const GraphicConversionParameters& rParameters) const
+{
+ return mpImpGraphic->ImplGetBitmapEx(rParameters);
+}
+
+// ------------------------------------------------------------------------
+
+Animation Graphic::GetAnimation() const
+{
+ return mpImpGraphic->ImplGetAnimation();
+}
+
+// ------------------------------------------------------------------------
+
+const GDIMetaFile& Graphic::GetGDIMetaFile() const
+{
+ return mpImpGraphic->ImplGetGDIMetaFile();
+}
+
+// ------------------------------------------------------------------------
+
+uno::Reference< graphic::XGraphic > Graphic::GetXGraphic() const
+{
+ uno::Reference< graphic::XGraphic > xRet;
+
+ if( GetType() != GRAPHIC_NONE )
+ {
+ uno::Reference < lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() );
+
+ if( xMSF.is() )
+ {
+ uno::Reference< graphic::XGraphicProvider > xProv( xMSF->createInstance(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.graphic.GraphicProvider" ) ) ),
+ uno::UNO_QUERY );
+
+ if( xProv.is() )
+ {
+ uno::Sequence< beans::PropertyValue > aLoadProps( 1 );
+ ::rtl::OUString aURL( RTL_CONSTASCII_USTRINGPARAM( "private:memorygraphic/" ) );
+
+ aLoadProps[ 0 ].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
+ aLoadProps[ 0 ].Value <<= ( aURL += ::rtl::OUString::valueOf( reinterpret_cast< sal_Int64 >( this ) ) );
+
+ xRet = xProv->queryGraphic( aLoadProps );
+ }
+ }
+ }
+
+ return xRet;
+}
+
+// ------------------------------------------------------------------------
+
+Size Graphic::GetPrefSize() const
+{
+ return mpImpGraphic->ImplGetPrefSize();
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::SetPrefSize( const Size& rPrefSize )
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplSetPrefSize( rPrefSize );
+}
+
+// ------------------------------------------------------------------------
+
+MapMode Graphic::GetPrefMapMode() const
+{
+ return mpImpGraphic->ImplGetPrefMapMode();
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::SetPrefMapMode( const MapMode& rPrefMapMode )
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplSetPrefMapMode( rPrefMapMode );
+}
+
+// ------------------------------------------------------------------
+
+Size Graphic::GetSizePixel( const OutputDevice* pRefDevice ) const
+{
+ Size aRet;
+
+ if( GRAPHIC_BITMAP == mpImpGraphic->ImplGetType() )
+ aRet = mpImpGraphic->ImplGetBitmapEx(GraphicConversionParameters()).GetSizePixel();
+ else
+ aRet = ( pRefDevice ? pRefDevice : Application::GetDefaultDevice() )->LogicToPixel( GetPrefSize(), GetPrefMapMode() );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------
+
+ULONG Graphic::GetSizeBytes() const
+{
+ return mpImpGraphic->ImplGetSizeBytes();
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
+{
+ mpImpGraphic->ImplDraw( pOutDev, rDestPt );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::Draw( OutputDevice* pOutDev,
+ const Point& rDestPt, const Size& rDestSz ) const
+{
+ if( GRAPHIC_DEFAULT == mpImpGraphic->ImplGetType() )
+ ImplDrawDefault( pOutDev, NULL, NULL, NULL, NULL, rDestPt, rDestSz );
+ else
+ mpImpGraphic->ImplDraw( pOutDev, rDestPt, rDestSz );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::Draw( OutputDevice* pOutDev, const String& rText,
+ Font& rFont, const Bitmap& rBitmap,
+ const Point& rDestPt, const Size& rDestSz )
+{
+ ImplDrawDefault( pOutDev, &rText, &rFont, &rBitmap, NULL, rDestPt, rDestSz );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::DrawEx( OutputDevice* pOutDev, const String& rText,
+ Font& rFont, const BitmapEx& rBitmap,
+ const Point& rDestPt, const Size& rDestSz )
+{
+ ImplDrawDefault( pOutDev, &rText, &rFont, NULL, &rBitmap, rDestPt, rDestSz );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::StartAnimation( OutputDevice* pOutDev, const Point& rDestPt, long nExtraData,
+ OutputDevice* pFirstFrameOutDev )
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplStartAnimation( pOutDev, rDestPt, nExtraData, pFirstFrameOutDev );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::StartAnimation( OutputDevice* pOutDev, const Point& rDestPt,
+ const Size& rDestSz, long nExtraData,
+ OutputDevice* pFirstFrameOutDev )
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplStartAnimation( pOutDev, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::StopAnimation( OutputDevice* pOutDev, long nExtraData )
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplStopAnimation( pOutDev, nExtraData );
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::SetAnimationNotifyHdl( const Link& rLink )
+{
+ mpImpGraphic->ImplSetAnimationNotifyHdl( rLink );
+}
+
+// ------------------------------------------------------------------------
+
+Link Graphic::GetAnimationNotifyHdl() const
+{
+ return mpImpGraphic->ImplGetAnimationNotifyHdl();
+}
+
+// ------------------------------------------------------------------------
+
+ULONG Graphic::GetAnimationLoopCount() const
+{
+ return mpImpGraphic->ImplGetAnimationLoopCount();
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::ResetAnimationLoopCount()
+{
+ mpImpGraphic->ImplResetAnimationLoopCount();
+}
+
+// ------------------------------------------------------------------------
+
+List* Graphic::GetAnimationInfoList() const
+{
+ return mpImpGraphic->ImplGetAnimationInfoList();
+}
+
+// ------------------------------------------------------------------------
+
+GraphicReader* Graphic::GetContext()
+{
+ return mpImpGraphic->ImplGetContext();
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::SetContext( GraphicReader* pReader )
+{
+ mpImpGraphic->ImplSetContext( pReader );
+}
+
+// ------------------------------------------------------------------------
+
+USHORT Graphic::GetGraphicsCompressMode( SvStream& rIStm )
+{
+ const ULONG nPos = rIStm.Tell();
+ const USHORT nOldFormat = rIStm.GetNumberFormatInt();
+ UINT32 nTmp32;
+ UINT16 nTmp16;
+ USHORT nCompressMode = COMPRESSMODE_NONE;
+
+ rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ rIStm >> nTmp32;
+
+ // is it a swapped graphic with a bitmap?
+ rIStm.SeekRel( (nTmp32 == (UINT32) GRAPHIC_BITMAP ) ? 40 : -4 );
+
+ // try to read bitmap id
+ rIStm >> nTmp16;
+
+ // check id of BitmapFileHeader
+ if( 0x4D42 == nTmp16 )
+ {
+ // seek to compress field of BitmapInfoHeader
+ rIStm.SeekRel( 28 );
+ rIStm >> nTmp32;
+
+ // Compare with our own compressmode
+ if( ZCOMPRESS == nTmp32 )
+ nCompressMode = COMPRESSMODE_ZBITMAP;
+ }
+
+ rIStm.SetNumberFormatInt( nOldFormat );
+ rIStm.Seek( nPos );
+
+ return nCompressMode;
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::SetDocFileName( const String& rName, ULONG nFilePos )
+{
+ mpImpGraphic->ImplSetDocFileName( rName, nFilePos );
+}
+
+// ------------------------------------------------------------------------
+
+const String& Graphic::GetDocFileName() const
+{
+ return mpImpGraphic->ImplGetDocFileName();
+}
+
+// ------------------------------------------------------------------------
+
+ULONG Graphic::GetDocFilePos() const
+{
+ return mpImpGraphic->ImplGetDocFilePos();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::ReadEmbedded( SvStream& rIStream, BOOL bSwap )
+{
+ ImplTestRefCount();
+ return mpImpGraphic->ImplReadEmbedded( rIStream, bSwap );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::WriteEmbedded( SvStream& rOStream )
+{
+ ImplTestRefCount();
+ return mpImpGraphic->ImplWriteEmbedded( rOStream );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::SwapOut()
+{
+ ImplTestRefCount();
+ return mpImpGraphic->ImplSwapOut();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::SwapOut( SvStream* pOStream )
+{
+ ImplTestRefCount();
+ return mpImpGraphic->ImplSwapOut( pOStream );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::SwapIn()
+{
+ ImplTestRefCount();
+ return mpImpGraphic->ImplSwapIn();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::SwapIn( SvStream* pStrm )
+{
+ ImplTestRefCount();
+ return mpImpGraphic->ImplSwapIn( pStrm );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::IsSwapOut() const
+{
+ return mpImpGraphic->ImplIsSwapOut();
+}
+
+// ------------------------------------------------------------------------
+
+void Graphic::SetLink( const GfxLink& rGfxLink )
+{
+ ImplTestRefCount();
+ mpImpGraphic->ImplSetLink( rGfxLink );
+}
+
+// ------------------------------------------------------------------------
+
+GfxLink Graphic::GetLink() const
+{
+ return mpImpGraphic->ImplGetLink();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::IsLink() const
+{
+ return mpImpGraphic->ImplIsLink();
+}
+
+// ------------------------------------------------------------------------
+
+ULONG Graphic::GetChecksum() const
+{
+ return mpImpGraphic->ImplGetChecksum();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL Graphic::ExportNative( SvStream& rOStream ) const
+{
+ return mpImpGraphic->ImplExportNative( rOStream );
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStream, Graphic& rGraphic )
+{
+ rGraphic.ImplTestRefCount();
+ return rIStream >> *rGraphic.mpImpGraphic;
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const Graphic& rGraphic )
+{
+ return rOStream << *rGraphic.mpImpGraphic;
+}
diff --git a/vcl/source/gdi/graphictools.cxx b/vcl/source/gdi/graphictools.cxx
new file mode 100644
index 000000000000..83c0cd628cdb
--- /dev/null
+++ b/vcl/source/gdi/graphictools.cxx
@@ -0,0 +1,759 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/vcompat.hxx>
+
+#include <vcl/graphictools.hxx>
+
+static ::rtl::OString polyToString( const Polygon& rPoly )
+{
+ ::rtl::OString aStr;
+ USHORT nVertex;
+ for(nVertex=0; nVertex<rPoly.GetSize(); ++nVertex)
+ {
+ aStr += "(";
+ switch( rPoly.GetFlags(nVertex) )
+ {
+ case POLY_NORMAL:
+ case POLY_SMOOTH:
+ case POLY_SYMMTR:
+ aStr += "n: ";
+ break;
+
+ case POLY_CONTROL:
+ aStr += "c: ";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicStroke::polyToString invalid flag");
+ break;
+ }
+ aStr += ::rtl::OString::valueOf( static_cast< double >( rPoly[nVertex].getX() ) );
+ aStr += ",";
+ aStr += ::rtl::OString::valueOf( static_cast< double >( rPoly[nVertex].getY() ) );
+ aStr += ") ";
+ }
+
+ return aStr;
+}
+
+static ::rtl::OString polyPolyToString( const PolyPolygon& rPolyPoly )
+{
+ ::rtl::OString aStr;
+ USHORT nPoly;
+ for(nPoly=0; nPoly<rPolyPoly.Count(); ++nPoly)
+ {
+ const Polygon& rPoly = rPolyPoly[nPoly];
+
+ aStr += "{ ";
+ aStr += polyToString( rPoly );
+ aStr += "} ";
+ }
+
+ return aStr;
+}
+
+static ::rtl::OString dashToString( const SvtGraphicStroke::DashArray& rDashArray )
+{
+ ::rtl::OString aStr;
+
+ aStr += "dash: [ ";
+
+ int i, nDashes( rDashArray.size() );
+ for(i=0; i<nDashes; ++i)
+ {
+ aStr += ::rtl::OString::valueOf( rDashArray[i] );
+ aStr += " ";
+ }
+
+ aStr += "] ";
+
+ return aStr;
+}
+
+static ::rtl::OString colorToString( Color aColor )
+{
+ ::rtl::OString aStr;
+
+ aStr += "color: [ ";
+ aStr += ::rtl::OString::valueOf( aColor.GetRed() );
+ aStr += " ";
+ aStr += ::rtl::OString::valueOf( aColor.GetGreen() );
+ aStr += " ";
+ aStr += ::rtl::OString::valueOf( aColor.GetBlue() );
+ aStr += " ] ";
+
+ return aStr;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+SvtGraphicFill::Transform::Transform()
+{
+ matrix[0] = 1.0; matrix[1] = 0.0; matrix[2] = 0.0;
+ matrix[3] = 0.0; matrix[4] = 1.0; matrix[5] = 0.0;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+SvtGraphicStroke::SvtGraphicStroke() :
+ maPath(),
+ maStartArrow(),
+ maEndArrow(),
+ mfTransparency(),
+ mfStrokeWidth(),
+ maCapType(),
+ maJoinType(),
+ mfMiterLimit( 3.0 ),
+ maDashArray()
+{
+}
+
+SvtGraphicStroke::SvtGraphicStroke( const Polygon& rPath,
+ const PolyPolygon& rStartArrow,
+ const PolyPolygon& rEndArrow,
+ double fTransparency,
+ double fStrokeWidth,
+ CapType aCap,
+ JoinType aJoin,
+ double fMiterLimit,
+ const DashArray& rDashArray ) :
+ maPath( rPath ),
+ maStartArrow( rStartArrow ),
+ maEndArrow( rEndArrow ),
+ mfTransparency( fTransparency ),
+ mfStrokeWidth( fStrokeWidth ),
+ maCapType( aCap ),
+ maJoinType( aJoin ),
+ mfMiterLimit( fMiterLimit ),
+ maDashArray( rDashArray )
+{
+}
+
+void SvtGraphicStroke::getPath( Polygon& rPath ) const
+{
+ rPath = maPath;
+}
+
+void SvtGraphicStroke::getStartArrow( PolyPolygon& rPath ) const
+{
+ rPath = maStartArrow;
+}
+
+void SvtGraphicStroke::getEndArrow( PolyPolygon& rPath ) const
+{
+ rPath = maEndArrow;
+}
+
+double SvtGraphicStroke::getTransparency() const
+{
+ return mfTransparency;
+}
+
+double SvtGraphicStroke::getStrokeWidth() const
+{
+ return mfStrokeWidth;
+}
+
+SvtGraphicStroke::CapType SvtGraphicStroke::getCapType() const
+{
+ return maCapType;
+}
+
+SvtGraphicStroke::JoinType SvtGraphicStroke::getJoinType() const
+{
+ return maJoinType;
+}
+
+double SvtGraphicStroke::getMiterLimit() const
+{
+ return mfMiterLimit;
+}
+
+void SvtGraphicStroke::getDashArray( DashArray& rDashArray ) const
+{
+ rDashArray = maDashArray;
+}
+
+::rtl::OString SvtGraphicStroke::toString() const
+{
+ ::rtl::OString aStr;
+
+ aStr += polyToString( maPath );
+ aStr += "trans: ";
+ aStr += ::rtl::OString::valueOf( static_cast< double >(getTransparency()) );
+ aStr += " width: ";
+ aStr += ::rtl::OString::valueOf( static_cast< double >(getStrokeWidth()) );
+ aStr += " cap: ";
+ switch( getCapType() )
+ {
+ case capButt:
+ aStr += "butt";
+ break;
+
+ case capRound:
+ aStr += "round";
+ break;
+
+ case capSquare:
+ aStr += "square";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicStroke::toString missing cap type");
+ break;
+ }
+ aStr += " join: ";
+ switch( getJoinType() )
+ {
+ case joinMiter:
+ aStr += "miter";
+ break;
+
+ case joinRound:
+ aStr += "round";
+ break;
+
+ case joinBevel:
+ aStr += "bevel";
+ break;
+
+ case joinNone:
+ aStr += "none";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicStroke::toString missing join type");
+ break;
+ }
+ aStr += " ";
+
+ if( maStartArrow.Count() )
+ {
+ aStr += "start: ";
+ aStr += polyPolyToString( maStartArrow );
+ aStr += " ";
+ }
+
+ if( maEndArrow.Count() )
+ {
+ aStr += "end: ";
+ aStr += polyPolyToString( maEndArrow );
+ aStr += " ";
+ }
+
+ aStr += dashToString( maDashArray );
+
+ return aStr;
+}
+
+void SvtGraphicStroke::setPath( const Polygon& rPoly )
+{
+ maPath = rPoly;
+}
+
+void SvtGraphicStroke::setStartArrow( const PolyPolygon& rPoly )
+{
+ maStartArrow = rPoly;
+}
+
+void SvtGraphicStroke::setEndArrow( const PolyPolygon& rPoly )
+{
+ maEndArrow = rPoly;
+}
+
+void SvtGraphicStroke::setTransparency( double fTrans )
+{
+ mfTransparency = fTrans;
+}
+
+void SvtGraphicStroke::setStrokeWidth( double fWidth )
+{
+ mfStrokeWidth = fWidth;
+}
+
+void SvtGraphicStroke::setCapType( CapType eType )
+{
+ maCapType = eType;
+}
+
+void SvtGraphicStroke::setJoinType( JoinType eType )
+{
+ maJoinType = eType;
+}
+
+void SvtGraphicStroke::setMiterLimit( double fMiterLimit )
+{
+ mfMiterLimit = fMiterLimit;
+}
+
+void SvtGraphicStroke::setDashArray( const DashArray& rDashArray )
+{
+ maDashArray = rDashArray;
+}
+
+SvStream& operator<<( SvStream& rOStm, const SvtGraphicStroke& rClass )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 1 );
+
+ rClass.maPath.Write( rOStm );
+ rClass.maStartArrow.Write( rOStm );
+ rClass.maEndArrow.Write( rOStm );
+ rOStm << rClass.mfTransparency;
+ rOStm << rClass.mfStrokeWidth;
+ UINT16 nTmp = sal::static_int_cast<UINT16>( rClass.maCapType );
+ rOStm << nTmp;
+ nTmp = sal::static_int_cast<UINT16>( rClass.maJoinType );
+ rOStm << nTmp;
+ rOStm << rClass.mfMiterLimit;
+
+ rOStm << static_cast<sal_uInt32>(rClass.maDashArray.size());
+ size_t i;
+ for(i=0; i<rClass.maDashArray.size(); ++i)
+ rOStm << rClass.maDashArray[i];
+
+ return rOStm;
+}
+
+SvStream& operator>>( SvStream& rIStm, SvtGraphicStroke& rClass )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+
+ rClass.maPath.Read( rIStm );
+ rClass.maStartArrow.Read( rIStm );
+ rClass.maEndArrow.Read( rIStm );
+ rIStm >> rClass.mfTransparency;
+ rIStm >> rClass.mfStrokeWidth;
+ UINT16 nTmp;
+ rIStm >> nTmp;
+ rClass.maCapType = SvtGraphicStroke::CapType(nTmp);
+ rIStm >> nTmp;
+ rClass.maJoinType = SvtGraphicStroke::JoinType(nTmp);
+ rIStm >> rClass.mfMiterLimit;
+
+ sal_uInt32 nSize;
+ rIStm >> nSize;
+ rClass.maDashArray.resize(nSize);
+ size_t i;
+ for(i=0; i<rClass.maDashArray.size(); ++i)
+ rIStm >> rClass.maDashArray[i];
+
+ return rIStm;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+SvtGraphicFill::SvtGraphicFill() :
+ maPath(),
+ maFillColor( COL_BLACK ),
+ mfTransparency(),
+ maFillRule(),
+ maFillType(),
+ maFillTransform(),
+ maHatchType(),
+ maHatchColor( COL_BLACK ),
+ maGradientType(),
+ maGradient1stColor( COL_BLACK ),
+ maGradient2ndColor( COL_BLACK ),
+ maGradientStepCount( gradientStepsInfinite ),
+ maFillGraphic()
+{
+}
+
+SvtGraphicFill::SvtGraphicFill( const PolyPolygon& rPath,
+ Color aFillColor,
+ double fTransparency,
+ FillRule aFillRule,
+ FillType aFillType,
+ const Transform& aFillTransform,
+ bool bTiling,
+ HatchType aHatchType,
+ Color aHatchColor,
+ GradientType aGradientType,
+ Color aGradient1stColor,
+ Color aGradient2ndColor,
+ int aGradientStepCount,
+ const Graphic& aFillGraphic ) :
+ maPath( rPath ),
+ maFillColor( aFillColor ),
+ mfTransparency( fTransparency ),
+ maFillRule( aFillRule ),
+ maFillType( aFillType ),
+ maFillTransform( aFillTransform ),
+ mbTiling( bTiling ),
+ maHatchType( aHatchType ),
+ maHatchColor( aHatchColor ),
+ maGradientType( aGradientType ),
+ maGradient1stColor( aGradient1stColor ),
+ maGradient2ndColor( aGradient2ndColor ),
+ maGradientStepCount( aGradientStepCount ),
+ maFillGraphic( aFillGraphic )
+{
+}
+
+void SvtGraphicFill::getPath( PolyPolygon& rPath ) const
+{
+ rPath = maPath;
+}
+
+Color SvtGraphicFill::getFillColor() const
+{
+ return maFillColor;
+}
+
+double SvtGraphicFill::getTransparency() const
+{
+ return mfTransparency;
+}
+
+SvtGraphicFill::FillRule SvtGraphicFill::getFillRule() const
+{
+ return maFillRule;
+}
+
+SvtGraphicFill::FillType SvtGraphicFill::getFillType() const
+{
+ return maFillType;
+}
+
+void SvtGraphicFill::getTransform( Transform& rTrans ) const
+{
+ rTrans = maFillTransform;
+}
+
+bool SvtGraphicFill::IsTiling() const
+{
+ return mbTiling;
+}
+
+bool SvtGraphicFill::isTiling() const
+{
+ return mbTiling;
+}
+
+SvtGraphicFill::HatchType SvtGraphicFill::getHatchType() const
+{
+ return maHatchType;
+}
+
+Color SvtGraphicFill::getHatchColor() const
+{
+ return maHatchColor;
+}
+
+SvtGraphicFill::GradientType SvtGraphicFill::getGradientType() const
+{
+ return maGradientType;
+}
+
+Color SvtGraphicFill::getGradient1stColor() const
+{
+ return maGradient1stColor;
+}
+
+Color SvtGraphicFill::getGradient2ndColor() const
+{
+ return maGradient2ndColor;
+}
+
+int SvtGraphicFill::getGradientStepCount() const
+{
+ return maGradientStepCount;
+}
+
+void SvtGraphicFill::getGraphic( Graphic& rGraphic ) const
+{
+ rGraphic = maFillGraphic;
+}
+
+::rtl::OString SvtGraphicFill::toString() const
+{
+ ::rtl::OString aStr;
+
+ aStr += polyPolyToString( maPath );
+ aStr += "fill";
+ aStr += colorToString( getFillColor() );
+ aStr += " trans: ";
+ aStr += ::rtl::OString::valueOf( static_cast< double >(getTransparency()) );
+ aStr += " rule: ";
+ switch( getFillRule() )
+ {
+ case fillNonZero:
+ aStr += "nonzero";
+ break;
+
+ case fillEvenOdd:
+ aStr += "evenodd";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicFill::toString missing fill rule");
+ break;
+ }
+ aStr += " type: ";
+ switch( getFillType() )
+ {
+ case fillSolid:
+ aStr += "solid";
+ break;
+
+ case fillGradient:
+ aStr += "gradient";
+ break;
+
+ case fillHatch:
+ aStr += "hatch";
+ break;
+
+ case fillTexture:
+ aStr += "bitmap";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicStroke::toString missing fill type");
+ break;
+ }
+
+ aStr += " transform: [ ";
+ int i;
+ for(i=0; i<Transform::MatrixSize; ++i)
+ aStr += ::rtl::OString::valueOf( maFillTransform.matrix[i] );
+ aStr += " ] ";
+
+ aStr += " hatch: ";
+ switch( getHatchType() )
+ {
+ case hatchSingle:
+ aStr += "single";
+ break;
+
+ case hatchDouble:
+ aStr += "double";
+ break;
+
+ case hatchTriple:
+ aStr += "triple";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicStroke::toString missing hatch type");
+ break;
+ }
+
+ aStr += " hatch";
+ aStr += colorToString( getHatchColor() );
+
+ aStr += " gradient: ";
+ switch( getGradientType() )
+ {
+ case gradientLinear:
+ aStr += "linear";
+ break;
+
+ case gradientRadial:
+ aStr += "radial";
+ break;
+
+ case gradientRectangular:
+ aStr += "rectangular";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicStroke::toString missing gradient type");
+ break;
+ }
+
+ aStr += " grad1st";
+ aStr += colorToString( getGradient1stColor() );
+
+ aStr += " grad2nd";
+ aStr += colorToString( getGradient2ndColor() );
+
+ aStr += " gradstep";
+ aStr += ::rtl::OString::valueOf( (sal_Int32)getGradientStepCount() );
+
+ if( maFillGraphic.GetType() != GRAPHIC_NONE )
+ {
+ aStr += " fillgraphic: ";
+ switch( maFillGraphic.GetType() )
+ {
+ case GRAPHIC_BITMAP:
+ aStr += "bitmap";
+ break;
+
+ case GRAPHIC_GDIMETAFILE:
+ aStr += "metafile";
+ break;
+
+ case GRAPHIC_DEFAULT:
+ aStr += "default";
+ break;
+
+ default:
+ DBG_ERROR( "SvtGraphicStroke::toString missing graphic type");
+ break;
+ }
+
+ aStr += " of ";
+ aStr += ::rtl::OString::valueOf( static_cast< sal_Int32 >(maFillGraphic.GetSizeBytes()) );
+ aStr += " bytes";
+ }
+
+ return aStr;
+}
+
+void SvtGraphicFill::setPath( const PolyPolygon& rPath )
+{
+ maPath = rPath;
+}
+
+void SvtGraphicFill::setFillColor( Color aFillColor )
+{
+ maFillColor = aFillColor;
+}
+
+void SvtGraphicFill::setTransparency( double fTransparency )
+{
+ mfTransparency = fTransparency;
+}
+
+void SvtGraphicFill::setFillRule( FillRule aFillRule )
+{
+ maFillRule = aFillRule;
+}
+
+void SvtGraphicFill::setFillType( FillType aFillType )
+{
+ maFillType = aFillType;
+}
+
+void SvtGraphicFill::setTransform( const Transform& rTransform )
+{
+ maFillTransform = rTransform;
+}
+
+void SvtGraphicFill::setTiling( bool bTiling )
+{
+ mbTiling = bTiling;
+}
+
+void SvtGraphicFill::setHatchType( HatchType aHatchType )
+{
+ maHatchType = aHatchType;
+}
+
+void SvtGraphicFill::setHatchColor( Color aHatchColor )
+{
+ maHatchColor = aHatchColor;
+}
+
+void SvtGraphicFill::setGradientType( GradientType aGradType )
+{
+ maGradientType = aGradType;
+}
+
+void SvtGraphicFill::setGradient1stColor( Color aColor )
+{
+ maGradient1stColor = aColor;
+}
+
+void SvtGraphicFill::setGradient2ndColor( Color aColor )
+{
+ maGradient2ndColor = aColor;
+}
+
+void SvtGraphicFill::setGradientStepCount( int aCount )
+{
+ maGradientStepCount = aCount;
+}
+
+void SvtGraphicFill::setGraphic( const Graphic& rGraphic )
+{
+ maFillGraphic = rGraphic;
+}
+
+SvStream& operator<<( SvStream& rOStm, const SvtGraphicFill& rClass )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 1 );
+
+ rClass.maPath.Write( rOStm );
+ rOStm << rClass.maFillColor;
+ rOStm << rClass.mfTransparency;
+ UINT16 nTmp = sal::static_int_cast<UINT16>( rClass.maFillRule );
+ rOStm << nTmp;
+ nTmp = sal::static_int_cast<UINT16>( rClass.maFillType );
+ rOStm << nTmp;
+ int i;
+ for(i=0; i<SvtGraphicFill::Transform::MatrixSize; ++i)
+ rOStm << rClass.maFillTransform.matrix[i];
+ nTmp = rClass.mbTiling;
+ rOStm << nTmp;
+ nTmp = sal::static_int_cast<UINT16>( rClass.maHatchType );
+ rOStm << nTmp;
+ rOStm << rClass.maHatchColor;
+ nTmp = sal::static_int_cast<UINT16>( rClass.maGradientType );
+ rOStm << nTmp;
+ rOStm << rClass.maGradient1stColor;
+ rOStm << rClass.maGradient2ndColor;
+ rOStm << rClass.maGradientStepCount;
+ rOStm << rClass.maFillGraphic;
+
+ return rOStm;
+}
+
+SvStream& operator>>( SvStream& rIStm, SvtGraphicFill& rClass )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+
+ rClass.maPath.Read( rIStm );
+ rIStm >> rClass.maFillColor;
+ rIStm >> rClass.mfTransparency;
+ UINT16 nTmp;
+ rIStm >> nTmp;
+ rClass.maFillRule = SvtGraphicFill::FillRule( nTmp );
+ rIStm >> nTmp;
+ rClass.maFillType = SvtGraphicFill::FillType( nTmp );
+ int i;
+ for(i=0; i<SvtGraphicFill::Transform::MatrixSize; ++i)
+ rIStm >> rClass.maFillTransform.matrix[i];
+ rIStm >> nTmp;
+ rClass.mbTiling = nTmp;
+ rIStm >> nTmp;
+ rClass.maHatchType = SvtGraphicFill::HatchType( nTmp );
+ rIStm >> rClass.maHatchColor;
+ rIStm >> nTmp;
+ rClass.maGradientType = SvtGraphicFill::GradientType( nTmp );
+ rIStm >> rClass.maGradient1stColor;
+ rIStm >> rClass.maGradient2ndColor;
+ rIStm >> rClass.maGradientStepCount;
+ rIStm >> rClass.maFillGraphic;
+
+ return rIStm;
+}
diff --git a/vcl/source/gdi/hatch.cxx b/vcl/source/gdi/hatch.cxx
new file mode 100644
index 000000000000..3a8b51bf3022
--- /dev/null
+++ b/vcl/source/gdi/hatch.cxx
@@ -0,0 +1,222 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/debug.hxx>
+#ifndef _SV_HATCX_HXX
+#include <vcl/hatch.hxx>
+#endif
+
+DBG_NAME( Hatch )
+
+// --------------
+// - ImplHatch -
+// --------------
+
+ImplHatch::ImplHatch() :
+ mnRefCount ( 1 ),
+ maColor ( COL_BLACK ),
+ meStyle ( HATCH_SINGLE ),
+ mnDistance ( 1 ),
+ mnAngle ( 0 )
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImplHatch::ImplHatch( const ImplHatch& rImplHatch ) :
+ mnRefCount ( 1 ),
+ maColor ( rImplHatch.maColor ),
+ meStyle ( rImplHatch.meStyle ),
+ mnDistance ( rImplHatch.mnDistance ),
+ mnAngle ( rImplHatch.mnAngle )
+{
+}
+
+// ---------
+// - Hatch -
+// ---------
+
+Hatch::Hatch()
+{
+ DBG_CTOR( Hatch, NULL );
+ mpImplHatch = new ImplHatch;
+}
+
+// -----------------------------------------------------------------------
+
+Hatch::Hatch( const Hatch& rHatch )
+{
+ DBG_CTOR( Hatch, NULL );
+ DBG_CHKOBJ( &rHatch, Hatch, NULL );
+ mpImplHatch = rHatch.mpImplHatch;
+ mpImplHatch->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+Hatch::Hatch( HatchStyle eStyle, const Color& rColor,
+ long nDistance, USHORT nAngle10 )
+{
+ DBG_CTOR( Hatch, NULL );
+ mpImplHatch = new ImplHatch;
+ mpImplHatch->maColor = rColor;
+ mpImplHatch->meStyle = eStyle;
+ mpImplHatch->mnDistance = nDistance;
+ mpImplHatch->mnAngle = nAngle10;
+}
+
+// -----------------------------------------------------------------------
+
+Hatch::~Hatch()
+{
+ DBG_DTOR( Hatch, NULL );
+ if( !( --mpImplHatch->mnRefCount ) )
+ delete mpImplHatch;
+}
+
+// -----------------------------------------------------------------------
+
+Hatch& Hatch::operator=( const Hatch& rHatch )
+{
+ DBG_CHKTHIS( Hatch, NULL );
+ DBG_CHKOBJ( &rHatch, Hatch, NULL );
+
+ rHatch.mpImplHatch->mnRefCount++;
+
+ if( !( --mpImplHatch->mnRefCount ) )
+ delete mpImplHatch;
+
+ mpImplHatch = rHatch.mpImplHatch;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Hatch::operator==( const Hatch& rHatch ) const
+{
+ DBG_CHKTHIS( Hatch, NULL );
+ DBG_CHKOBJ( &rHatch, Hatch, NULL );
+
+ return( mpImplHatch == rHatch.mpImplHatch ||
+ ( mpImplHatch->maColor == rHatch.mpImplHatch->maColor &&
+ mpImplHatch->meStyle == rHatch.mpImplHatch->meStyle &&
+ mpImplHatch->mnDistance == rHatch.mpImplHatch->mnDistance &&
+ mpImplHatch->mnAngle == rHatch.mpImplHatch->mnAngle ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Hatch::ImplMakeUnique()
+{
+ if( mpImplHatch->mnRefCount != 1 )
+ {
+ if( mpImplHatch->mnRefCount )
+ mpImplHatch->mnRefCount--;
+
+ mpImplHatch = new ImplHatch( *mpImplHatch );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Hatch::SetStyle( HatchStyle eStyle )
+{
+ DBG_CHKTHIS( Hatch, NULL );
+ ImplMakeUnique();
+ mpImplHatch->meStyle = eStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void Hatch::SetColor( const Color& rColor )
+{
+ DBG_CHKTHIS( Hatch, NULL );
+ ImplMakeUnique();
+ mpImplHatch->maColor = rColor;
+}
+
+// -----------------------------------------------------------------------
+
+void Hatch::SetDistance( long nDistance )
+{
+ DBG_CHKTHIS( Hatch, NULL );
+ ImplMakeUnique();
+ mpImplHatch->mnDistance = nDistance;
+}
+
+// -----------------------------------------------------------------------
+
+void Hatch::SetAngle( USHORT nAngle10 )
+{
+ DBG_CHKTHIS( Hatch, NULL );
+ ImplMakeUnique();
+ mpImplHatch->mnAngle = nAngle10;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, ImplHatch& rImplHatch )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+ UINT16 nTmp16;
+
+ rIStm >> nTmp16; rImplHatch.meStyle = (HatchStyle) nTmp16;
+ rIStm >> rImplHatch.maColor >> rImplHatch.mnDistance >> rImplHatch.mnAngle;
+
+ return rIStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const ImplHatch& rImplHatch )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 1 );
+
+ rOStm << (UINT16) rImplHatch.meStyle << rImplHatch.maColor;
+ rOStm << rImplHatch.mnDistance << rImplHatch.mnAngle;
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, Hatch& rHatch )
+{
+ rHatch.ImplMakeUnique();
+ return( rIStm >> *rHatch.mpImplHatch );
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Hatch& rHatch )
+{
+ return( rOStm << *rHatch.mpImplHatch );
+}
diff --git a/vcl/source/gdi/image.cxx b/vcl/source/gdi/image.cxx
new file mode 100644
index 000000000000..e79308b2664e
--- /dev/null
+++ b/vcl/source/gdi/image.cxx
@@ -0,0 +1,1029 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/scoped_array.hpp>
+
+#include <rtl/logfile.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <tools/rc.hxx>
+#ifndef _SV_RESMGR_HXX
+#include <tools/resmgr.hxx>
+#endif
+#include <vcl/settings.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#ifndef _SV_IMPIMAGETREE_H
+#include <vcl/impimagetree.hxx>
+#endif
+#include <vcl/image.h>
+#include <vcl/image.hxx>
+
+#if OSL_DEBUG_LEVEL > 0
+#include <rtl/strbuf.hxx>
+#endif
+
+DBG_NAME( Image )
+DBG_NAME( ImageList )
+
+#define IMAGE_FILE_VERSION 100
+
+using namespace ::com::sun::star;
+
+// ---------
+// - Image -
+// ---------
+
+Image::Image() :
+ mpImplData( NULL )
+{
+ DBG_CTOR( Image, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Image::Image( const ResId& rResId ) :
+ mpImplData( NULL )
+{
+ DBG_CTOR( Image, NULL );
+
+ rResId.SetRT( RSC_IMAGE );
+
+ ResMgr* pResMgr = rResId.GetResMgr();
+ if( pResMgr && pResMgr->GetResource( rResId ) )
+ {
+ pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
+
+ BitmapEx aBmpEx;
+ ULONG nObjMask = pResMgr->ReadLong();
+
+ if( nObjMask & RSC_IMAGE_IMAGEBITMAP )
+ {
+ aBmpEx = BitmapEx( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) );
+ pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
+ }
+
+ if( nObjMask & RSC_IMAGE_MASKBITMAP )
+ {
+ if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE )
+ {
+ const Bitmap aMaskBitmap( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) );
+ aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskBitmap );
+ }
+
+ pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
+ }
+
+ if( nObjMask & RSC_IMAGE_MASKCOLOR )
+ {
+ if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE )
+ {
+ const Color aMaskColor( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) );
+ aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskColor );
+ }
+
+ pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
+ }
+ if( ! aBmpEx.IsEmpty() )
+ ImplInit( aBmpEx );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Image::Image( const Image& rImage ) :
+ mpImplData( rImage.mpImplData )
+{
+ DBG_CTOR( Image, NULL );
+
+ if( mpImplData )
+ ++mpImplData->mnRefCount;
+}
+
+// -----------------------------------------------------------------------
+
+Image::Image( const BitmapEx& rBitmapEx ) :
+ mpImplData( NULL )
+{
+ DBG_CTOR( Image, NULL );
+
+ ImplInit( rBitmapEx );
+}
+
+// -----------------------------------------------------------------------
+
+Image::Image( const Bitmap& rBitmap ) :
+ mpImplData( NULL )
+{
+ DBG_CTOR( Image, NULL );
+
+ ImplInit( rBitmap );
+}
+
+// -----------------------------------------------------------------------
+
+Image::Image( const Bitmap& rBitmap, const Bitmap& rMaskBitmap ) :
+ mpImplData( NULL )
+{
+ DBG_CTOR( Image, NULL );
+
+ const BitmapEx aBmpEx( rBitmap, rMaskBitmap );
+
+ ImplInit( aBmpEx );
+}
+
+// -----------------------------------------------------------------------
+
+Image::Image( const Bitmap& rBitmap, const Color& rColor ) :
+ mpImplData( NULL )
+{
+ DBG_CTOR( Image, NULL );
+
+ const BitmapEx aBmpEx( rBitmap, rColor );
+
+ ImplInit( aBmpEx );
+}
+
+// -----------------------------------------------------------------------
+
+Image::Image( const uno::Reference< graphic::XGraphic >& rxGraphic ) :
+ mpImplData( NULL )
+{
+ DBG_CTOR( Image, NULL );
+
+ const Graphic aGraphic( rxGraphic );
+ ImplInit( aGraphic.GetBitmapEx() );
+}
+
+// -----------------------------------------------------------------------
+
+Image::~Image()
+{
+ DBG_DTOR( Image, NULL );
+
+ if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
+ delete mpImplData;
+}
+
+// -----------------------------------------------------------------------
+
+void Image::ImplInit( const BitmapEx& rBmpEx )
+{
+ if( !rBmpEx.IsEmpty() )
+ {
+ mpImplData = new ImplImage;
+ mpImplData->mnRefCount = 1;
+
+ if( rBmpEx.GetTransparentType() == TRANSPARENT_NONE )
+ {
+ mpImplData->meType = IMAGETYPE_BITMAP;
+ mpImplData->mpData = new Bitmap( rBmpEx.GetBitmap() );
+ }
+ else
+ {
+ mpImplData->meType = IMAGETYPE_IMAGE;
+ mpImplData->mpData = new ImplImageData( rBmpEx );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size Image::GetSizePixel() const
+{
+ DBG_CHKTHIS( Image, NULL );
+
+ Size aRet;
+
+ if( mpImplData )
+ {
+ switch( mpImplData->meType )
+ {
+ case IMAGETYPE_BITMAP:
+ aRet = static_cast< Bitmap* >( mpImplData->mpData )->GetSizePixel();
+ break;
+
+ case IMAGETYPE_IMAGE:
+ aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx.GetSizePixel();
+ break;
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+BitmapEx Image::GetBitmapEx() const
+{
+ DBG_CHKTHIS( Image, NULL );
+
+ BitmapEx aRet;
+
+ if( mpImplData )
+ {
+ switch( mpImplData->meType )
+ {
+ case IMAGETYPE_BITMAP:
+ aRet = *static_cast< Bitmap* >( mpImplData->mpData );
+ break;
+
+ case IMAGETYPE_IMAGE:
+ aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx;
+ break;
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+uno::Reference< graphic::XGraphic > Image::GetXGraphic() const
+{
+ const Graphic aGraphic( GetBitmapEx() );
+
+ return aGraphic.GetXGraphic();
+}
+
+// -----------------------------------------------------------------------
+
+Image Image::GetColorTransformedImage( ImageColorTransform eColorTransform ) const
+{
+ DBG_CHKTHIS( Image, NULL );
+
+ Image aRet;
+
+ if( IMAGECOLORTRANSFORM_HIGHCONTRAST == eColorTransform )
+ {
+ BitmapEx aBmpEx( GetBitmapEx() );
+
+ if( !aBmpEx.IsEmpty() )
+ {
+ Color* pSrcColors = NULL;
+ Color* pDstColors = NULL;
+ ULONG nColorCount = 0;
+
+ Image::GetColorTransformArrays( eColorTransform, pSrcColors, pDstColors, nColorCount );
+
+ if( nColorCount && pSrcColors && pDstColors )
+ {
+ aBmpEx.Replace( pSrcColors, pDstColors, nColorCount );
+ aRet = Image( aBmpEx );
+ }
+
+ delete[] pSrcColors;
+ delete[] pDstColors;
+ }
+ }
+ else if( IMAGECOLORTRANSFORM_MONOCHROME_BLACK == eColorTransform ||
+ IMAGECOLORTRANSFORM_MONOCHROME_WHITE == eColorTransform )
+ {
+ BitmapEx aBmpEx( GetBitmapEx() );
+
+ if( !aBmpEx.IsEmpty() )
+ aRet = Image( aBmpEx.GetColorTransformedBitmapEx( ( BmpColorMode )( eColorTransform ) ) );
+ }
+
+ if( !aRet )
+ aRet = *this;
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Image::Invert()
+{
+ BitmapEx aInvertedBmp( GetBitmapEx() );
+ aInvertedBmp.Invert();
+ *this = aInvertedBmp;
+}
+
+// -----------------------------------------------------------------------
+
+void Image::GetColorTransformArrays( ImageColorTransform eColorTransform,
+ Color*& rpSrcColor, Color*& rpDstColor, ULONG& rColorCount )
+{
+ if( IMAGECOLORTRANSFORM_HIGHCONTRAST == eColorTransform )
+ {
+ rpSrcColor = new Color[ 4 ];
+ rpDstColor = new Color[ 4 ];
+ rColorCount = 4;
+
+ rpSrcColor[ 0 ] = Color( COL_BLACK );
+ rpDstColor[ 0 ] = Color( COL_WHITE );
+
+ rpSrcColor[ 1 ] = Color( COL_WHITE );
+ rpDstColor[ 1 ] = Color( COL_BLACK );
+
+ rpSrcColor[ 2 ] = Color( COL_BLUE );
+ rpDstColor[ 2 ] = Color( COL_WHITE );
+
+ rpSrcColor[ 3 ] = Color( COL_LIGHTBLUE );
+ rpDstColor[ 3 ] = Color( COL_WHITE );
+ }
+ else
+ {
+ rpSrcColor = rpDstColor = NULL;
+ rColorCount = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Image& Image::operator=( const Image& rImage )
+{
+ DBG_CHKTHIS( Image, NULL );
+ DBG_CHKOBJ( &rImage, Image, NULL );
+
+ if( rImage.mpImplData )
+ ++rImage.mpImplData->mnRefCount;
+
+ if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
+ delete mpImplData;
+
+ mpImplData = rImage.mpImplData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Image::operator==( const Image& rImage ) const
+{
+ DBG_CHKTHIS( Image, NULL );
+ DBG_CHKOBJ( &rImage, Image, NULL );
+
+ bool bRet = false;
+
+ if( rImage.mpImplData == mpImplData )
+ bRet = true;
+ else if( !rImage.mpImplData || !mpImplData )
+ bRet = false;
+ else if( rImage.mpImplData->mpData == mpImplData->mpData )
+ bRet = true;
+ else if( rImage.mpImplData->meType == mpImplData->meType )
+ {
+ switch( mpImplData->meType )
+ {
+ case IMAGETYPE_BITMAP:
+ bRet = ( *static_cast< Bitmap* >( rImage.mpImplData->mpData ) == *static_cast< Bitmap* >( mpImplData->mpData ) );
+ break;
+
+ case IMAGETYPE_IMAGE:
+ bRet = static_cast< ImplImageData* >( rImage.mpImplData->mpData )->IsEqual( *static_cast< ImplImageData* >( mpImplData->mpData ) );
+ break;
+
+ default:
+ bRet = false;
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+// -------------
+// - ImageList -
+// -------------
+
+ImageList::ImageList( USHORT nInit, USHORT nGrow ) :
+ mpImplData( NULL ),
+ mnInitSize( nInit ),
+ mnGrowSize( nGrow )
+{
+ DBG_CTOR( ImageList, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+ImageList::ImageList( const ResId& rResId ) :
+ mpImplData( NULL ),
+ mnInitSize( 1 ),
+ mnGrowSize( 4 )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::ImageList( const ResId& rResId )" );
+
+ DBG_CTOR( ImageList, NULL );
+
+ rResId.SetRT( RSC_IMAGELIST );
+
+ ResMgr* pResMgr = rResId.GetResMgr();
+
+ if( pResMgr && pResMgr->GetResource( rResId ) )
+ {
+ pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
+
+ ULONG nObjMask = pResMgr->ReadLong();
+ const String aPrefix( pResMgr->ReadString() );
+ ::boost::scoped_ptr< Color > spMaskColor;
+
+ if( nObjMask & RSC_IMAGE_MASKCOLOR )
+ spMaskColor.reset( new Color( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) ) );
+
+ pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
+
+ if( nObjMask & RSC_IMAGELIST_IDLIST )
+ {
+ for( sal_Int32 i = 0, nCount = pResMgr->ReadLong(); i < nCount; ++i )
+ pResMgr->ReadLong();
+ }
+
+ sal_Int32 nCount = pResMgr->ReadLong();
+ ImplInit( static_cast< USHORT >( nCount ), Size() );
+
+ BitmapEx aEmpty;
+ for( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ rtl::OUString aName = pResMgr->ReadString();
+ USHORT nId = static_cast< USHORT >( pResMgr->ReadLong() );
+ mpImplData->AddImage( aName, nId, aEmpty );
+ }
+
+ if( nObjMask & RSC_IMAGELIST_IDCOUNT )
+ pResMgr->ReadShort();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImageList::ImageList( const ::std::vector< ::rtl::OUString >& rNameVector,
+ const ::rtl::OUString& rPrefix,
+ const Color* ) :
+ mpImplData( NULL ),
+ mnInitSize( 1 ),
+ mnGrowSize( 4 )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::ImageList(const vector< OUString >& ..." );
+
+ DBG_CTOR( ImageList, NULL );
+
+ ImplInit( sal::static_int_cast< USHORT >( rNameVector.size() ), Size() );
+
+ mpImplData->maPrefix = rPrefix;
+ for( sal_uInt32 i = 0; i < rNameVector.size(); ++i )
+ {
+// fprintf (stderr, "List %p [%d]: '%s'\n",
+// this, i, rtl::OUStringToOString( rNameVector[i], RTL_TEXTENCODING_UTF8 ).getStr() );
+ mpImplData->AddImage( rNameVector[ i ], static_cast< USHORT >( i ) + 1, BitmapEx() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImageList::ImageList( const ImageList& rImageList ) :
+ mpImplData( rImageList.mpImplData ),
+ mnInitSize( rImageList.mnInitSize ),
+ mnGrowSize( rImageList.mnGrowSize )
+{
+ DBG_CTOR( ImageList, NULL );
+
+ if( mpImplData )
+ ++mpImplData->mnRefCount;
+}
+
+// -----------------------------------------------------------------------
+
+ImageList::~ImageList()
+{
+ DBG_DTOR( ImageList, NULL );
+
+ if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
+ delete mpImplData;
+}
+
+void ImageList::ImplInit( USHORT nItems, const Size &rSize )
+{
+ mpImplData = new ImplImageList;
+ mpImplData->mnRefCount = 1;
+ mpImplData->maImages.reserve( nItems );
+ mpImplData->maImageSize = rSize;
+}
+
+// -----------------------------------------------------------------------
+
+void ImageAryData::Load(const rtl::OUString &rPrefix)
+{
+ static ImplImageTreeSingletonRef aImageTree;
+
+ ::rtl::OUString aSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
+
+ BitmapEx aBmpEx;
+
+// fprintf (stderr, "Attempt load of '%s'\n",
+// rtl::OUStringToOString( maName, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ rtl::OUString aFileName = rPrefix;
+ aFileName += maName;
+#if OSL_DEBUG_LEVEL > 0
+ bool bSuccess =
+#endif
+ aImageTree->loadImage( aFileName, aSymbolsStyle, maBitmapEx, true );
+#if OSL_DEBUG_LEVEL > 0
+ if ( !bSuccess )
+ {
+ ::rtl::OStringBuffer aMessage;
+ aMessage.append( "ImageAryData::Load: failed to load image '" );
+ aMessage.append( ::rtl::OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ).getStr() );
+ aMessage.append( "'" );
+ OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::ImplMakeUnique()
+{
+ if( mpImplData && mpImplData->mnRefCount > 1 )
+ {
+ --mpImplData->mnRefCount;
+ mpImplData = new ImplImageList( *mpImplData ) ;
+ }
+}
+
+// -----------------------------------------------------------------------
+// Rather a performance hazard:
+BitmapEx ImageList::GetAsHorizontalStrip() const
+{
+ Size aSize( mpImplData->maImageSize );
+ USHORT nCount = GetImageCount();
+ if( !nCount )
+ return BitmapEx();
+ aSize.Width() *= nCount;
+
+ // Load any stragglers
+ for (USHORT nIdx = 0; nIdx < nCount; nIdx++)
+ {
+ ImageAryData *pData = mpImplData->maImages[ nIdx ];
+ if( pData->IsLoadable() )
+ pData->Load( mpImplData->maPrefix );
+ }
+
+ BitmapEx aTempl = mpImplData->maImages[ 0 ]->maBitmapEx;
+ BitmapEx aResult;
+ Bitmap aPixels( aSize, aTempl.GetBitmap().GetBitCount() );
+ if( aTempl.IsAlpha() )
+ aResult = BitmapEx( aPixels, AlphaMask( aSize ) );
+ else if( aTempl.IsTransparent() )
+ aResult = BitmapEx( aPixels, Bitmap( aSize, aTempl.GetMask().GetBitCount() ) );
+ else
+ aResult = BitmapEx( aPixels );
+
+ Rectangle aSrcRect( Point( 0, 0 ), mpImplData->maImageSize );
+ for (USHORT nIdx = 0; nIdx < nCount; nIdx++)
+ {
+ Rectangle aDestRect( Point( nIdx * mpImplData->maImageSize.Width(), 0 ),
+ mpImplData->maImageSize );
+ ImageAryData *pData = mpImplData->maImages[ nIdx ];
+ aResult.CopyPixel( aDestRect, aSrcRect, &pData->maBitmapEx);
+ }
+
+ return aResult;
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::InsertFromHorizontalStrip( const BitmapEx &rBitmapEx,
+ const std::vector< rtl::OUString > &rNameVector )
+{
+ USHORT nItems = sal::static_int_cast< USHORT >( rNameVector.size() );
+
+// fprintf (stderr, "InsertFromHorizontalStrip (1) [%d items]\n", nItems);
+
+ if (!nItems)
+ return;
+
+ Size aSize( rBitmapEx.GetSizePixel() );
+ DBG_ASSERT (rBitmapEx.GetSizePixel().Width() % nItems == 0,
+ "ImageList::InsertFromHorizontalStrip - very odd size");
+ aSize.Width() /= nItems;
+ ImplInit( nItems, aSize );
+
+ for (USHORT nIdx = 0; nIdx < nItems; nIdx++)
+ {
+ BitmapEx aBitmap( rBitmapEx, Point( nIdx * aSize.Width(), 0 ), aSize );
+ mpImplData->AddImage( rNameVector[ nIdx ], nIdx + 1, aBitmap );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::InsertFromHorizontalBitmap( const ResId& rResId,
+ USHORT nCount,
+ const Color *pMaskColor,
+ const Color *pSearchColors,
+ const Color *pReplaceColors,
+ ULONG nColorCount)
+{
+ BitmapEx aBmpEx( rResId );
+ if (!aBmpEx.IsTransparent())
+ {
+ if( pMaskColor )
+ aBmpEx = BitmapEx( aBmpEx.GetBitmap(), *pMaskColor );
+ else
+ aBmpEx = BitmapEx( aBmpEx.GetBitmap() );
+ }
+ if ( nColorCount && pSearchColors && pReplaceColors )
+ aBmpEx.Replace( pSearchColors, pReplaceColors, nColorCount );
+
+ std::vector< rtl::OUString > aNames( nCount );
+ InsertFromHorizontalStrip( aBmpEx, aNames );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImageList::ImplGetImageId( const ::rtl::OUString& rImageName ) const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ ImageAryData *pImg = mpImplData->maNameHash[ rImageName ];
+ if( pImg )
+ return pImg->mnId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::AddImage( USHORT nId, const Image& rImage )
+{
+ DBG_CHKTHIS( ImageList, NULL );
+ DBG_CHKOBJ( &rImage, Image, NULL );
+ DBG_ASSERT( nId, "ImageList::AddImage(): ImageId == 0" );
+ DBG_ASSERT( GetImagePos( nId ) == IMAGELIST_IMAGE_NOTFOUND, "ImageList::AddImage() - ImageId already exists" );
+ DBG_ASSERT( rImage.mpImplData, "ImageList::AddImage(): Wrong Size" );
+ DBG_ASSERT( !mpImplData || (rImage.GetSizePixel() == mpImplData->maImageSize), "ImageList::AddImage(): Wrong Size" );
+
+ if( !mpImplData )
+ ImplInit( 0, rImage.GetSizePixel() );
+
+ mpImplData->AddImage( rtl::OUString(), nId, rImage.GetBitmapEx());
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::AddImage( const ::rtl::OUString& rImageName, const Image& rImage )
+{
+ DBG_ASSERT( GetImagePos( rImageName ) == IMAGELIST_IMAGE_NOTFOUND, "ImageList::AddImage() - ImageName already exists" );
+
+ if( !mpImplData )
+ ImplInit( 0, rImage.GetSizePixel() );
+
+ mpImplData->AddImage( rImageName, GetImageCount() + 1,
+ rImage.GetBitmapEx() );
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::ReplaceImage( USHORT nId, const Image& rImage )
+{
+ DBG_CHKTHIS( ImageList, NULL );
+ DBG_CHKOBJ( &rImage, Image, NULL );
+ DBG_ASSERT( GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND, "ImageList::ReplaceImage(): Unknown nId" );
+
+ RemoveImage( nId );
+ AddImage( nId, rImage );
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::ReplaceImage( const ::rtl::OUString& rImageName, const Image& rImage )
+{
+ const USHORT nId = ImplGetImageId( rImageName );
+
+ if( nId )
+ {
+ RemoveImage( nId );
+
+ if( !mpImplData )
+ ImplInit( 0, rImage.GetSizePixel() );
+ mpImplData->AddImage( rImageName, nId, rImage.GetBitmapEx());
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::ReplaceImage( USHORT nId, USHORT nReplaceId )
+{
+ DBG_CHKTHIS( ImageList, NULL );
+ DBG_ASSERT( GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND, "ImageList::ReplaceImage(): Unknown nId" );
+ DBG_ASSERT( GetImagePos( nReplaceId ) != IMAGELIST_IMAGE_NOTFOUND, "ImageList::ReplaceImage(): Unknown nReplaceId" );
+
+ ULONG nPosDest = GetImagePos( nId );
+ ULONG nPosSrc = GetImagePos( nReplaceId );
+ if( nPosDest != IMAGELIST_IMAGE_NOTFOUND &&
+ nPosSrc != IMAGELIST_IMAGE_NOTFOUND )
+ {
+ ImplMakeUnique();
+ mpImplData->maImages[nPosDest] = mpImplData->maImages[nPosSrc];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::ReplaceImage( const ::rtl::OUString& rImageName, const ::rtl::OUString& rReplaceName )
+{
+ const USHORT nId1 = ImplGetImageId( rImageName ), nId2 = ImplGetImageId( rReplaceName );
+
+ if( nId1 && nId2 )
+ ReplaceImage( nId1, nId2 );
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::RemoveImage( USHORT nId )
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); ++i )
+ {
+ if( mpImplData->maImages[ i ]->mnId == nId )
+ {
+ mpImplData->RemoveImage( static_cast< USHORT >( i ) );
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::RemoveImage( const ::rtl::OUString& rImageName )
+{
+ const USHORT nId = ImplGetImageId( rImageName );
+
+ if( nId )
+ RemoveImage( nId );
+}
+
+// -----------------------------------------------------------------------
+
+Image ImageList::GetImage( USHORT nId ) const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+// fprintf (stderr, "GetImage %d\n", nId);
+
+ Image aRet;
+
+ if( mpImplData )
+ {
+ std::vector<ImageAryData *>::iterator aIter;
+ for( aIter = mpImplData->maImages.begin();
+ aIter != mpImplData->maImages.end(); aIter++)
+ {
+ if ((*aIter)->mnId == nId)
+ {
+ if( (*aIter)->IsLoadable() )
+ (*aIter)->Load( mpImplData->maPrefix );
+
+ aRet = Image( (*aIter)->maBitmapEx );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+Image ImageList::GetImage( const ::rtl::OUString& rImageName ) const
+{
+// fprintf (stderr, "GetImage '%s'\n",
+// rtl::OUStringToOString( rImageName, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ if( mpImplData )
+ {
+ ImageAryData *pImg = mpImplData->maNameHash[ rImageName ];
+
+ if( pImg )
+ {
+ if( pImg->IsLoadable() )
+ pImg->Load( mpImplData->maPrefix );
+ return Image( pImg->maBitmapEx );
+ }
+ }
+// fprintf (stderr, "no such image\n");
+
+ return Image();
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::Clear()
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
+ delete mpImplData;
+
+ mpImplData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImageList::GetImageCount() const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ return mpImplData ? static_cast< USHORT >( mpImplData->maImages.size() ) : 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImageList::GetImagePos( USHORT nId ) const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ if( mpImplData && nId )
+ {
+ for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); ++i )
+ {
+ if (mpImplData->maImages[ i ]->mnId == nId)
+ return static_cast< USHORT >( i );
+ }
+ }
+
+ return IMAGELIST_IMAGE_NOTFOUND;
+}
+
+bool ImageList::HasImageAtPos( USHORT nId ) const
+{
+ return GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImageList::GetImagePos( const ::rtl::OUString& rImageName ) const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ if( mpImplData && rImageName.getLength() )
+ {
+ for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
+ {
+ if (mpImplData->maImages[i]->maName == rImageName)
+ return static_cast< USHORT >( i );
+ }
+ }
+
+ return IMAGELIST_IMAGE_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImageList::GetImageId( USHORT nPos ) const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ if( mpImplData && (nPos < GetImageCount()) )
+ return mpImplData->maImages[ nPos ]->mnId;
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::GetImageIds( ::std::vector< USHORT >& rIds ) const
+{
+ RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::GetImageIds" );
+
+ DBG_CHKTHIS( ImageList, NULL );
+
+ rIds = ::std::vector< USHORT >();
+
+ if( mpImplData )
+ {
+ for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
+ rIds.push_back( mpImplData->maImages[i]->mnId );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+::rtl::OUString ImageList::GetImageName( USHORT nPos ) const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ if( mpImplData && (nPos < GetImageCount()) )
+ return mpImplData->maImages[ nPos ]->maName;
+
+ return ::rtl::OUString();
+}
+
+// -----------------------------------------------------------------------
+
+void ImageList::GetImageNames( ::std::vector< ::rtl::OUString >& rNames ) const
+{
+ RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::GetImageNames" );
+
+ DBG_CHKTHIS( ImageList, NULL );
+
+ rNames = ::std::vector< ::rtl::OUString >();
+
+ if( mpImplData )
+ {
+ for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
+ {
+ const rtl::OUString& rName( mpImplData->maImages[ i ]->maName );
+ if( rName.getLength() != 0 )
+ rNames.push_back( rName );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size ImageList::GetImageSize() const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+
+ Size aRet;
+
+ if( mpImplData )
+ {
+ aRet = mpImplData->maImageSize;
+
+ // force load of 1st image to see - uncommon case.
+ if( aRet.Width() == 0 && aRet.Height() == 0 &&
+ !mpImplData->maImages.empty() )
+ {
+ Image aTmp = GetImage( mpImplData->maImages[ 0 ]->mnId );
+ aRet = mpImplData->maImageSize = aTmp.GetSizePixel();
+ }
+ }
+// fprintf (stderr, "GetImageSize returns %d, %d\n",
+// aRet.Width(), aRet.Height());
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+ImageList& ImageList::operator=( const ImageList& rImageList )
+{
+ DBG_CHKTHIS( ImageList, NULL );
+ DBG_CHKOBJ( &rImageList, ImageList, NULL );
+
+ if( rImageList.mpImplData )
+ ++rImageList.mpImplData->mnRefCount;
+
+ if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
+ delete mpImplData;
+
+ mpImplData = rImageList.mpImplData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImageList::operator==( const ImageList& rImageList ) const
+{
+ DBG_CHKTHIS( ImageList, NULL );
+ DBG_CHKOBJ( &rImageList, ImageList, NULL );
+
+ bool bRet = false;
+
+ if( rImageList.mpImplData == mpImplData )
+ bRet = true;
+ else if( !rImageList.mpImplData || !mpImplData )
+ bRet = false;
+ else if( rImageList.GetImageCount() == GetImageCount() &&
+ rImageList.mpImplData->maImageSize == mpImplData->maImageSize )
+ bRet = true; // strange semantic
+
+ return bRet;
+}
diff --git a/vcl/source/gdi/imagerepository.cxx b/vcl/source/gdi/imagerepository.cxx
new file mode 100644
index 000000000000..d97999311751
--- /dev/null
+++ b/vcl/source/gdi/imagerepository.cxx
@@ -0,0 +1,57 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/bitmapex.hxx>
+#include <vcl/imagerepository.hxx>
+#include <vcl/svapp.hxx>
+#ifndef _SV_IMPIMAGETREE_H
+#include "vcl/impimagetree.hxx"
+#endif
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ //====================================================================
+ //= ImageRepository
+ //====================================================================
+ //--------------------------------------------------------------------
+ bool ImageRepository::loadImage( const ::rtl::OUString& _rName, BitmapEx& _out_rImage, bool _bSearchLanguageDependent )
+ {
+ ::rtl::OUString sCurrentSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
+
+ ImplImageTreeSingletonRef aImplImageTree;
+ return aImplImageTree->loadImage( _rName, sCurrentSymbolsStyle, _out_rImage, _bSearchLanguageDependent );
+ }
+
+//........................................................................
+} // namespace vcl
+//........................................................................
+
diff --git a/vcl/source/gdi/impanmvw.cxx b/vcl/source/gdi/impanmvw.cxx
new file mode 100644
index 000000000000..7762087dc605
--- /dev/null
+++ b/vcl/source/gdi/impanmvw.cxx
@@ -0,0 +1,355 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "impanmvw.hxx"
+#include <vcl/virdev.hxx>
+#include <vcl/window.hxx>
+#include <vcl/salbtype.hxx>
+
+// ----------------
+// - ImplAnimView -
+// ----------------
+
+ImplAnimView::ImplAnimView( Animation* pParent, OutputDevice* pOut,
+ const Point& rPt, const Size& rSz,
+ ULONG nExtraData,
+ OutputDevice* pFirstFrameOutDev ) :
+ mpParent ( pParent ),
+ mpOut ( pFirstFrameOutDev ? pFirstFrameOutDev : pOut ),
+ mnExtraData ( nExtraData ),
+ maPt ( rPt ),
+ maSz ( rSz ),
+ maSzPix ( mpOut->LogicToPixel( maSz ) ),
+ maClip ( mpOut->GetClipRegion() ),
+ mpBackground ( new VirtualDevice ),
+ mpRestore ( new VirtualDevice ),
+ meLastDisposal ( DISPOSE_BACK ),
+ mbPause ( FALSE ),
+ mbMarked ( FALSE ),
+ mbHMirr ( maSz.Width() < 0L ),
+ mbVMirr ( maSz.Height() < 0L )
+{
+ mpParent->ImplIncAnimCount();
+
+ // mirrored horizontically?
+ if( mbHMirr )
+ {
+ maDispPt.X() = maPt.X() + maSz.Width() + 1L;
+ maDispSz.Width() = -maSz.Width();
+ maSzPix.Width() = -maSzPix.Width();
+ }
+ else
+ {
+ maDispPt.X() = maPt.X();
+ maDispSz.Width() = maSz.Width();
+ }
+
+ // mirrored vertically?
+ if( mbVMirr )
+ {
+ maDispPt.Y() = maPt.Y() + maSz.Height() + 1L;
+ maDispSz.Height() = -maSz.Height();
+ maSzPix.Height() = -maSzPix.Height();
+ }
+ else
+ {
+ maDispPt.Y() = maPt.Y();
+ maDispSz.Height() = maSz.Height();
+ }
+
+ // save background
+ mpBackground->SetOutputSizePixel( maSzPix );
+
+ if( mpOut->GetOutDevType() == OUTDEV_WINDOW )
+ {
+ MapMode aTempMap( mpOut->GetMapMode() );
+ aTempMap.SetOrigin( Point() );
+ mpBackground->SetMapMode( aTempMap );
+ ( (Window*) mpOut )->SaveBackground( maDispPt, maDispSz, Point(), *mpBackground );
+ mpBackground->SetMapMode( MapMode() );
+ }
+ else
+ mpBackground->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut );
+
+ // initial drawing to actual position
+ ImplDrawToPos( mpParent->ImplGetCurPos() );
+
+ // if first frame OutputDevice is set, update variables now for real OutputDevice
+ if( pFirstFrameOutDev )
+ maClip = ( mpOut = pOut )->GetClipRegion();
+}
+
+// ------------------------------------------------------------------------
+
+ImplAnimView::~ImplAnimView()
+{
+ delete mpBackground;
+ delete mpRestore;
+
+ mpParent->ImplDecAnimCount();
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImplAnimView::ImplMatches( OutputDevice* pOut, long nExtraData ) const
+{
+ BOOL bRet = FALSE;
+
+ if( nExtraData )
+ {
+ if( ( mnExtraData == nExtraData ) && ( !pOut || ( pOut == mpOut ) ) )
+ bRet = TRUE;
+ }
+ else if( !pOut || ( pOut == mpOut ) )
+ bRet = TRUE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplAnimView::ImplGetPosSize( const AnimationBitmap& rAnm, Point& rPosPix, Size& rSizePix )
+{
+ const Size& rAnmSize = mpParent->GetDisplaySizePixel();
+ Point aPt2( rAnm.aPosPix.X() + rAnm.aSizePix.Width() - 1L,
+ rAnm.aPosPix.Y() + rAnm.aSizePix.Height() - 1L );
+ double fFactX, fFactY;
+
+ // calculate x scaling
+ if( rAnmSize.Width() > 1L )
+ fFactX = (double) ( maSzPix.Width() - 1L ) / ( rAnmSize.Width() - 1L );
+ else
+ fFactX = 1.0;
+
+ // calculate y scaling
+ if( rAnmSize.Height() > 1L )
+ fFactY = (double) ( maSzPix.Height() - 1L ) / ( rAnmSize.Height() - 1L );
+ else
+ fFactY = 1.0;
+
+ rPosPix.X() = FRound( rAnm.aPosPix.X() * fFactX );
+ rPosPix.Y() = FRound( rAnm.aPosPix.Y() * fFactY );
+
+ aPt2.X() = FRound( aPt2.X() * fFactX );
+ aPt2.Y() = FRound( aPt2.Y() * fFactY );
+
+ rSizePix.Width() = aPt2.X() - rPosPix.X() + 1L;
+ rSizePix.Height() = aPt2.Y() - rPosPix.Y() + 1L;
+
+ // mirrored horizontically?
+ if( mbHMirr )
+ rPosPix.X() = maSzPix.Width() - 1L - aPt2.X();
+
+ // mirrored vertically?
+ if( mbVMirr )
+ rPosPix.Y() = maSzPix.Height() - 1L - aPt2.Y();
+}
+
+// ------------------------------------------------------------------------
+
+void ImplAnimView::ImplDrawToPos( ULONG nPos )
+{
+ VirtualDevice aVDev;
+ Region* pOldClip = !maClip.IsNull() ? new Region( mpOut->GetClipRegion() ) : NULL;
+
+ aVDev.SetOutputSizePixel( maSzPix, FALSE );
+ nPos = Min( nPos, (ULONG) mpParent->Count() - 1UL );
+
+ for( ULONG i = 0UL; i <= nPos; i++ )
+ ImplDraw( i, &aVDev );
+
+ if( pOldClip )
+ mpOut->SetClipRegion( maClip );
+
+ mpOut->DrawOutDev( maDispPt, maDispSz, Point(), maSzPix, aVDev );
+
+ if( pOldClip )
+ {
+ mpOut->SetClipRegion( *pOldClip );
+ delete pOldClip;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImplAnimView::ImplDraw( ULONG nPos )
+{
+ ImplDraw( nPos, NULL );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplAnimView::ImplDraw( ULONG nPos, VirtualDevice* pVDev )
+{
+ Rectangle aOutRect( mpOut->PixelToLogic( Point() ), mpOut->GetOutputSize() );
+
+ // check, if output lies out of display
+ if( aOutRect.Intersection( Rectangle( maDispPt, maDispSz ) ).IsEmpty() )
+ ImplSetMarked( TRUE );
+ else if( !mbPause )
+ {
+ VirtualDevice* pDev;
+ Point aPosPix;
+ Point aBmpPosPix;
+ Size aSizePix;
+ Size aBmpSizePix;
+ const ULONG nLastPos = mpParent->Count() - 1;
+ const AnimationBitmap& rAnm = mpParent->Get( (USHORT) ( mnActPos = Min( nPos, nLastPos ) ) );
+
+ ImplGetPosSize( rAnm, aPosPix, aSizePix );
+
+ // mirrored horizontically?
+ if( mbHMirr )
+ {
+ aBmpPosPix.X() = aPosPix.X() + aSizePix.Width() - 1L;
+ aBmpSizePix.Width() = -aSizePix.Width();
+ }
+ else
+ {
+ aBmpPosPix.X() = aPosPix.X();
+ aBmpSizePix.Width() = aSizePix.Width();
+ }
+
+ // mirrored vertically?
+ if( mbVMirr )
+ {
+ aBmpPosPix.Y() = aPosPix.Y() + aSizePix.Height() - 1L;
+ aBmpSizePix.Height() = -aSizePix.Height();
+ }
+ else
+ {
+ aBmpPosPix.Y() = aPosPix.Y();
+ aBmpSizePix.Height() = aSizePix.Height();
+ }
+
+ // get output device
+ if( !pVDev )
+ {
+ pDev = new VirtualDevice;
+ pDev->SetOutputSizePixel( maSzPix, FALSE );
+ pDev->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut );
+ }
+ else
+ pDev = pVDev;
+
+ // restore background after each run
+ if( !nPos )
+ {
+ meLastDisposal = DISPOSE_BACK;
+ maRestPt = Point();
+ maRestSz = maSzPix;
+ }
+
+ // restore
+ if( ( DISPOSE_NOT != meLastDisposal ) && maRestSz.Width() && maRestSz.Height() )
+ {
+ if( DISPOSE_BACK == meLastDisposal )
+ pDev->DrawOutDev( maRestPt, maRestSz, maRestPt, maRestSz, *mpBackground );
+ else
+ pDev->DrawOutDev( maRestPt, maRestSz, Point(), maRestSz, *mpRestore );
+ }
+
+ meLastDisposal = rAnm.eDisposal;
+ maRestPt = aPosPix;
+ maRestSz = aSizePix;
+
+ // Was muessen wir beim naechsten Mal restaurieren ?
+ // ==> ggf. in eine Bitmap stecken, ansonsten SaveBitmap
+ // aus Speichergruenden loeschen
+ if( ( meLastDisposal == DISPOSE_BACK ) || ( meLastDisposal == DISPOSE_NOT ) )
+ mpRestore->SetOutputSizePixel( Size( 1, 1 ), FALSE );
+ else
+ {
+ mpRestore->SetOutputSizePixel( maRestSz, FALSE );
+ mpRestore->DrawOutDev( Point(), maRestSz, aPosPix, aSizePix, *pDev );
+ }
+
+ pDev->DrawBitmapEx( aBmpPosPix, aBmpSizePix, rAnm.aBmpEx );
+
+ if( !pVDev )
+ {
+ Region* pOldClip = !maClip.IsNull() ? new Region( mpOut->GetClipRegion() ) : NULL;
+
+ if( pOldClip )
+ mpOut->SetClipRegion( maClip );
+
+ mpOut->DrawOutDev( maDispPt, maDispSz, Point(), maSzPix, *pDev );
+
+ if( pOldClip )
+ {
+ mpOut->SetClipRegion( *pOldClip );
+ delete pOldClip;
+ }
+
+ delete pDev;
+
+ if( mpOut->GetOutDevType() == OUTDEV_WINDOW )
+ ( (Window*) mpOut )->Sync();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImplAnimView::ImplRepaint()
+{
+ const BOOL bOldPause = mbPause;
+
+ if( mpOut->GetOutDevType() == OUTDEV_WINDOW )
+ {
+ MapMode aTempMap( mpOut->GetMapMode() );
+ aTempMap.SetOrigin( Point() );
+ mpBackground->SetMapMode( aTempMap );
+ ( (Window*) mpOut )->SaveBackground( maDispPt, maDispSz, Point(), *mpBackground );
+ mpBackground->SetMapMode( MapMode() );
+ }
+ else
+ mpBackground->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut );
+
+ mbPause = FALSE;
+ ImplDrawToPos( mnActPos );
+ mbPause = bOldPause;
+}
+
+// ------------------------------------------------------------------------
+
+AInfo* ImplAnimView::ImplCreateAInfo() const
+{
+ AInfo* pAInfo = new AInfo;
+
+ pAInfo->aStartOrg = maPt;
+ pAInfo->aStartSize = maSz;
+ pAInfo->pOutDev = mpOut;
+ pAInfo->pViewData = (void*) this;
+ pAInfo->nExtraData = mnExtraData;
+ pAInfo->bPause = mbPause;
+
+ return pAInfo;
+}
diff --git a/vcl/source/gdi/impanmvw.hxx b/vcl/source/gdi/impanmvw.hxx
new file mode 100644
index 000000000000..69403c0f6928
--- /dev/null
+++ b/vcl/source/gdi/impanmvw.hxx
@@ -0,0 +1,96 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_IMPANMVW_HXX
+#define _SV_IMPANMVW_HXX
+
+#include <vcl/animate.hxx>
+
+// ----------------
+// - ImplAnimView -
+// ----------------
+
+class Animation;
+class OutputDevice;
+class VirtualDevice;
+struct AnimationBitmap;
+
+class ImplAnimView
+{
+private:
+
+ Animation* mpParent;
+ OutputDevice* mpOut;
+ long mnExtraData;
+ Point maPt;
+ Point maDispPt;
+ Point maRestPt;
+ Size maSz;
+ Size maSzPix;
+ Size maDispSz;
+ Size maRestSz;
+ MapMode maMap;
+ Region maClip;
+ VirtualDevice* mpBackground;
+ VirtualDevice* mpRestore;
+ ULONG mnActPos;
+ Disposal meLastDisposal;
+ BOOL mbPause;
+ BOOL mbFirst;
+ BOOL mbMarked;
+ BOOL mbHMirr;
+ BOOL mbVMirr;
+
+ void ImplGetPosSize( const AnimationBitmap& rAnm, Point& rPosPix, Size& rSizePix );
+ void ImplDraw( ULONG nPos, VirtualDevice* pVDev );
+
+public:
+
+ ImplAnimView( Animation* pParent, OutputDevice* pOut,
+ const Point& rPt, const Size& rSz, ULONG nExtraData,
+ OutputDevice* pFirstFrameOutDev = NULL );
+ ~ImplAnimView();
+
+ BOOL ImplMatches( OutputDevice* pOut, long nExtraData ) const;
+ void ImplDrawToPos( ULONG nPos );
+ void ImplDraw( ULONG nPos );
+ void ImplRepaint();
+ AInfo* ImplCreateAInfo() const;
+
+ const Point& ImplGetOutPos() const { return maPt; }
+
+ const Size& ImplGetOutSize() const { return maSz; }
+ const Size& ImplGetOutSizePix() const { return maSzPix; }
+
+ void ImplPause( BOOL bPause ) { mbPause = bPause; }
+ BOOL ImplIsPause() const { return mbPause; }
+
+ void ImplSetMarked( BOOL bMarked ) { mbMarked = bMarked; }
+ BOOL ImplIsMarked() const { return mbMarked; }
+};
+
+#endif
diff --git a/vcl/source/gdi/impbmp.cxx b/vcl/source/gdi/impbmp.cxx
new file mode 100644
index 000000000000..3e328b7db7a4
--- /dev/null
+++ b/vcl/source/gdi/impbmp.cxx
@@ -0,0 +1,134 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salbmp.hxx>
+#include <tools/debug.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/salinst.hxx>
+
+// --------------
+// - ImpBitmap -
+// --------------
+
+ImpBitmap::ImpBitmap() :
+ mnRefCount ( 1UL ),
+ mnChecksum ( 0UL ),
+ mpSalBitmap ( ImplGetSVData()->mpDefInst->CreateSalBitmap() ),
+ maSourceSize( 0, 0 )
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImpBitmap::~ImpBitmap()
+{
+ delete mpSalBitmap;
+}
+
+// -----------------------------------------------------------------------
+void ImpBitmap::ImplSetSalBitmap( SalBitmap* pBitmap )
+{
+ delete mpSalBitmap, mpSalBitmap = pBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImpBitmap::ImplCreate( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal )
+{
+ maSourceSize = rSize;
+ return mpSalBitmap->Create( rSize, nBitCount, rPal );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImpBitmap::ImplCreate( const ImpBitmap& rImpBitmap )
+{
+ maSourceSize = rImpBitmap.maSourceSize;
+ mnChecksum = rImpBitmap.mnChecksum;
+ return mpSalBitmap->Create( *rImpBitmap.mpSalBitmap );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImpBitmap::ImplCreate( const ImpBitmap& rImpBitmap, SalGraphics* pGraphics )
+{
+ return mpSalBitmap->Create( *rImpBitmap.mpSalBitmap, pGraphics );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImpBitmap::ImplCreate( const ImpBitmap& rImpBitmap, USHORT nNewBitCount )
+{
+ return mpSalBitmap->Create( *rImpBitmap.mpSalBitmap, nNewBitCount );
+}
+
+// -----------------------------------------------------------------------
+
+void ImpBitmap::ImplDestroy()
+{
+ mpSalBitmap->Destroy();
+}
+
+// -----------------------------------------------------------------------
+
+Size ImpBitmap::ImplGetSize() const
+{
+ return mpSalBitmap->GetSize();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImpBitmap::ImplGetBitCount() const
+{
+ USHORT nBitCount = mpSalBitmap->GetBitCount();
+ return( ( nBitCount <= 1 ) ? 1 : ( nBitCount <= 4 ) ? 4 : ( nBitCount <= 8 ) ? 8 : 24 );
+}
+
+// -----------------------------------------------------------------------
+
+BitmapBuffer* ImpBitmap::ImplAcquireBuffer( BOOL bReadOnly )
+{
+ return mpSalBitmap->AcquireBuffer( bReadOnly );
+}
+
+// -----------------------------------------------------------------------
+
+void ImpBitmap::ImplReleaseBuffer( BitmapBuffer* pBuffer, BOOL bReadOnly )
+{
+ mpSalBitmap->ReleaseBuffer( pBuffer, bReadOnly );
+
+ if( !bReadOnly )
+ mnChecksum = 0;
+}
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
new file mode 100644
index 000000000000..397a5d6b704a
--- /dev/null
+++ b/vcl/source/gdi/impgraph.cxx
@@ -0,0 +1,1677 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/vcompat.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <ucbhelper/content.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#ifndef _UNTOOLS_TEMPFILE_HXX
+#include <unotools/tempfile.hxx>
+#endif
+#include <vcl/outdev.hxx>
+#include <vcl/virdev.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <vcl/impgraph.hxx>
+#include <vcl/gfxlink.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/metaact.hxx>
+#include <com/sun/star/ucb/CommandAbortedException.hpp>
+
+// -----------
+// - Defines -
+// -----------
+
+#define GRAPHIC_MAXPARTLEN 256000L
+#define GRAPHIC_MTFTOBMP_MAXEXT 2048
+#define GRAPHIC_STREAMBUFSIZE 8192UL
+
+#define SYS_WINMETAFILE 0x00000003L
+#define SYS_WNTMETAFILE 0x00000004L
+#define SYS_OS2METAFILE 0x00000005L
+#define SYS_MACMETAFILE 0x00000006L
+
+#define GRAPHIC_FORMAT_50 static_cast<sal_uInt32>(COMPAT_FORMAT( 'G', 'R', 'F', '5' ))
+#define NATIVE_FORMAT_50 static_cast<sal_uInt32>(COMPAT_FORMAT( 'N', 'A', 'T', '5' ))
+
+// ---------------
+// - ImpSwapFile -
+// ---------------
+
+struct ImpSwapFile
+{
+ INetURLObject aSwapURL;
+ ULONG nRefCount;
+};
+
+// -----------------
+// - Graphicreader -
+// -----------------
+
+class ReaderData
+{
+public:
+ Size maPreviewSize;
+};
+
+GraphicReader::~GraphicReader()
+{
+ delete mpReaderData;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL GraphicReader::IsPreviewModeEnabled() const
+{
+ if( !mpReaderData )
+ return FALSE;
+ if( mpReaderData->maPreviewSize.Width() )
+ return TRUE;
+ if( mpReaderData->maPreviewSize.Height() )
+ return TRUE;
+ return FALSE;
+}
+
+// ------------------------------------------------------------------------
+
+void GraphicReader::DisablePreviewMode()
+{
+ if( mpReaderData )
+ mpReaderData->maPreviewSize = Size( 0, 0 );
+}
+
+// ------------------------------------------------------------------------
+
+void GraphicReader::SetPreviewSize( const Size& rSize )
+{
+ if( !mpReaderData )
+ mpReaderData = new ReaderData;
+ mpReaderData->maPreviewSize = rSize;
+}
+
+// ------------------------------------------------------------------------
+
+Size GraphicReader::GetPreviewSize() const
+{
+ Size aSize( 0, 0 );
+ if( mpReaderData )
+ aSize = mpReaderData->maPreviewSize;
+ return aSize;
+}
+
+// --------------
+// - ImpGraphic -
+// --------------
+
+ImpGraphic::ImpGraphic() :
+ mpAnimation ( NULL ),
+ mpContext ( NULL ),
+ mpSwapFile ( NULL ),
+ mpGfxLink ( NULL ),
+ meType ( GRAPHIC_NONE ),
+ mnDocFilePos ( 0UL ),
+ mnSizeBytes ( 0UL ),
+ mnRefCount ( 1UL ),
+ mbSwapOut ( FALSE ),
+ mbSwapUnderway ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------------
+
+ImpGraphic::ImpGraphic( const ImpGraphic& rImpGraphic ) :
+ maMetaFile ( rImpGraphic.maMetaFile ),
+ maEx ( rImpGraphic.maEx ),
+ mpContext ( NULL ),
+ mpSwapFile ( rImpGraphic.mpSwapFile ),
+ meType ( rImpGraphic.meType ),
+ maDocFileURLStr ( rImpGraphic.maDocFileURLStr ),
+ mnDocFilePos ( rImpGraphic.mnDocFilePos ),
+ mnSizeBytes ( rImpGraphic.mnSizeBytes ),
+ mnRefCount ( 1UL ),
+ mbSwapOut ( rImpGraphic.mbSwapOut ),
+ mbSwapUnderway ( FALSE )
+{
+ if( mpSwapFile )
+ mpSwapFile->nRefCount++;
+
+ if( rImpGraphic.mpGfxLink )
+ mpGfxLink = new GfxLink( *rImpGraphic.mpGfxLink );
+ else
+ mpGfxLink = NULL;
+
+ if( rImpGraphic.mpAnimation )
+ {
+ mpAnimation = new Animation( *rImpGraphic.mpAnimation );
+ maEx = mpAnimation->GetBitmapEx();
+ }
+ else
+ mpAnimation = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+ImpGraphic::ImpGraphic( const Bitmap& rBitmap ) :
+ maEx ( rBitmap ),
+ mpAnimation ( NULL ),
+ mpContext ( NULL ),
+ mpSwapFile ( NULL ),
+ mpGfxLink ( NULL ),
+ meType ( !rBitmap ? GRAPHIC_NONE : GRAPHIC_BITMAP ),
+ mnDocFilePos ( 0UL ),
+ mnSizeBytes ( 0UL ),
+ mnRefCount ( 1UL ),
+ mbSwapOut ( FALSE ),
+ mbSwapUnderway ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------------
+
+ImpGraphic::ImpGraphic( const BitmapEx& rBitmapEx ) :
+ maEx ( rBitmapEx ),
+ mpAnimation ( NULL ),
+ mpContext ( NULL ),
+ mpSwapFile ( NULL ),
+ mpGfxLink ( NULL ),
+ meType ( !rBitmapEx ? GRAPHIC_NONE : GRAPHIC_BITMAP ),
+ mnDocFilePos ( 0UL ),
+ mnSizeBytes ( 0UL ),
+ mnRefCount ( 1UL ),
+ mbSwapOut ( FALSE ),
+ mbSwapUnderway ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------------
+
+ImpGraphic::ImpGraphic( const Animation& rAnimation ) :
+ maEx ( rAnimation.GetBitmapEx() ),
+ mpAnimation ( new Animation( rAnimation ) ),
+ mpContext ( NULL ),
+ mpSwapFile ( NULL ),
+ mpGfxLink ( NULL ),
+ meType ( GRAPHIC_BITMAP ),
+ mnDocFilePos ( 0UL ),
+ mnSizeBytes ( 0UL ),
+ mnRefCount ( 1UL ),
+ mbSwapOut ( FALSE ),
+ mbSwapUnderway ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------------
+
+ImpGraphic::ImpGraphic( const GDIMetaFile& rMtf ) :
+ maMetaFile ( rMtf ),
+ mpAnimation ( NULL ),
+ mpContext ( NULL ),
+ mpSwapFile ( NULL ),
+ mpGfxLink ( NULL ),
+ meType ( GRAPHIC_GDIMETAFILE ),
+ mnDocFilePos ( 0UL ),
+ mnSizeBytes ( 0UL ),
+ mnRefCount ( 1UL ),
+ mbSwapOut ( FALSE ),
+ mbSwapUnderway ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------------
+
+ImpGraphic::~ImpGraphic()
+{
+ ImplClear();
+
+ if( (ULONG) mpContext > 1UL )
+ delete mpContext;
+}
+
+// ------------------------------------------------------------------------
+
+ImpGraphic& ImpGraphic::operator=( const ImpGraphic& rImpGraphic )
+{
+ if( &rImpGraphic != this )
+ {
+ if( !mbSwapUnderway )
+ ImplClear();
+
+ maMetaFile = rImpGraphic.maMetaFile;
+ meType = rImpGraphic.meType;
+ mnSizeBytes = rImpGraphic.mnSizeBytes;
+
+ delete mpAnimation;
+
+ if ( rImpGraphic.mpAnimation )
+ {
+ mpAnimation = new Animation( *rImpGraphic.mpAnimation );
+ maEx = mpAnimation->GetBitmapEx();
+ }
+ else
+ {
+ mpAnimation = NULL;
+ maEx = rImpGraphic.maEx;
+ }
+
+ if( !mbSwapUnderway )
+ {
+ maDocFileURLStr = rImpGraphic.maDocFileURLStr;
+ mnDocFilePos = rImpGraphic.mnDocFilePos;
+ mbSwapOut = rImpGraphic.mbSwapOut;
+ mpSwapFile = rImpGraphic.mpSwapFile;
+
+ if( mpSwapFile )
+ mpSwapFile->nRefCount++;
+ }
+
+ delete mpGfxLink;
+
+ if( rImpGraphic.mpGfxLink )
+ mpGfxLink = new GfxLink( *rImpGraphic.mpGfxLink );
+ else
+ mpGfxLink = NULL;
+ }
+
+ return *this;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::operator==( const ImpGraphic& rImpGraphic ) const
+{
+ BOOL bRet = FALSE;
+
+ if( this == &rImpGraphic )
+ bRet = TRUE;
+ else if( !ImplIsSwapOut() && ( rImpGraphic.meType == meType ) )
+ {
+ switch( meType )
+ {
+ case( GRAPHIC_NONE ):
+ bRet = TRUE;
+ break;
+
+ case( GRAPHIC_GDIMETAFILE ):
+ {
+ if( rImpGraphic.maMetaFile == maMetaFile )
+ bRet = TRUE;
+ }
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ {
+ if( mpAnimation )
+ {
+ if( rImpGraphic.mpAnimation && ( *rImpGraphic.mpAnimation == *mpAnimation ) )
+ bRet = TRUE;
+ }
+ else if( !rImpGraphic.mpAnimation && ( rImpGraphic.maEx == maEx ) )
+ bRet = TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplClearGraphics( BOOL bCreateSwapInfo )
+{
+ if( bCreateSwapInfo && !ImplIsSwapOut() )
+ {
+ maSwapInfo.maPrefMapMode = ImplGetPrefMapMode();
+ maSwapInfo.maPrefSize = ImplGetPrefSize();
+ }
+
+ maEx.Clear();
+ maMetaFile.Clear();
+
+ if( mpAnimation )
+ {
+ mpAnimation->Clear();
+ delete mpAnimation;
+ mpAnimation = NULL;
+ }
+
+ if( mpGfxLink )
+ {
+ delete mpGfxLink;
+ mpGfxLink = NULL;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplClear()
+{
+ if( mpSwapFile )
+ {
+ if( mpSwapFile->nRefCount > 1 )
+ mpSwapFile->nRefCount--;
+ else
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( mpSwapFile->aSwapURL.GetMainURL( INetURLObject::NO_DECODE ),
+ ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() );
+
+ aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ),
+ ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) );
+ }
+ catch( const ::com::sun::star::ucb::ContentCreationException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::RuntimeException& )
+ {
+ }
+ catch( const ::com::sun::star::ucb::CommandAbortedException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+
+ delete mpSwapFile;
+ }
+
+ mpSwapFile = NULL;
+ }
+
+ mbSwapOut = FALSE;
+ mnDocFilePos = 0UL;
+ maDocFileURLStr.Erase();
+
+ // cleanup
+ ImplClearGraphics( FALSE );
+ meType = GRAPHIC_NONE;
+ mnSizeBytes = 0;
+}
+
+// ------------------------------------------------------------------------
+
+GraphicType ImpGraphic::ImplGetType() const
+{
+ return meType;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplSetDefaultType()
+{
+ ImplClear();
+ meType = GRAPHIC_DEFAULT;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplIsSupportedGraphic() const
+{
+ return( meType != GRAPHIC_NONE );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplIsTransparent() const
+{
+ BOOL bRet;
+
+ if( meType == GRAPHIC_BITMAP )
+ bRet = ( mpAnimation ? mpAnimation->IsTransparent() : maEx.IsTransparent() );
+ else
+ bRet = TRUE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplIsAlpha() const
+{
+ BOOL bRet;
+
+ if( meType == GRAPHIC_BITMAP )
+ bRet = ( NULL == mpAnimation ) && maEx.IsAlpha();
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplIsAnimated() const
+{
+ return( mpAnimation != NULL );
+}
+
+// ------------------------------------------------------------------------
+
+Bitmap ImpGraphic::ImplGetBitmap(const GraphicConversionParameters& rParameters) const
+{
+ Bitmap aRetBmp;
+
+ if( meType == GRAPHIC_BITMAP )
+ {
+ const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx );
+ const Color aReplaceColor( COL_WHITE );
+
+ aRetBmp = rRetBmpEx.GetBitmap( &aReplaceColor );
+
+ if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height())
+ aRetBmp.Scale(rParameters.getSizePixel());
+ }
+ else if( ( meType != GRAPHIC_DEFAULT ) && ImplIsSupportedGraphic() )
+ {
+ // use corner points of graphic to determine the pixel
+ // extent of the graphic (rounding errors are possible else)
+ VirtualDevice aVDev;
+ const Point aNullPt;
+ const Point aTLPix( aVDev.LogicToPixel( aNullPt, maMetaFile.GetPrefMapMode() ) );
+ const Point aBRPix( aVDev.LogicToPixel( Point( maMetaFile.GetPrefSize().Width() - 1, maMetaFile.GetPrefSize().Height() - 1 ), maMetaFile.GetPrefMapMode() ) );
+ Size aDrawSize( aVDev.LogicToPixel( maMetaFile.GetPrefSize(), maMetaFile.GetPrefMapMode() ) );
+ Size aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
+
+ if(rParameters.getSizePixel().Width() && rParameters.getSizePixel().Height())
+ {
+ aDrawSize.Width() = FRound((double)rParameters.getSizePixel().Width() *
+ (double)aDrawSize.Width() / (double)aSizePix.Width());
+ aDrawSize.Height() = FRound((double)rParameters.getSizePixel().Height() *
+ (double)aDrawSize.Height() / (double)aSizePix.Height());
+
+ aSizePix = rParameters.getSizePixel();
+ }
+
+ if( aSizePix.Width() && aSizePix.Height() && !rParameters.getUnlimitedSize()
+ && (aSizePix.Width() > GRAPHIC_MTFTOBMP_MAXEXT || aSizePix.Height() > GRAPHIC_MTFTOBMP_MAXEXT))
+ {
+ const Size aOldSizePix( aSizePix );
+ double fWH = (double) aSizePix.Width() / aSizePix.Height();
+
+ if( fWH <= 1.0 )
+ aSizePix.Width() = FRound( GRAPHIC_MTFTOBMP_MAXEXT * fWH ), aSizePix.Height() = GRAPHIC_MTFTOBMP_MAXEXT;
+ else
+ aSizePix.Width() = GRAPHIC_MTFTOBMP_MAXEXT, aSizePix.Height() = FRound( GRAPHIC_MTFTOBMP_MAXEXT / fWH );
+
+ aDrawSize.Width() = FRound( ( (double) aDrawSize.Width() * aSizePix.Width() ) / aOldSizePix.Width() );
+ aDrawSize.Height() = FRound( ( (double) aDrawSize.Height() * aSizePix.Height() ) / aOldSizePix.Height() );
+ }
+
+ if( aVDev.SetOutputSizePixel( aSizePix ) )
+ {
+ if(rParameters.getAntiAliase())
+ {
+ aVDev.SetAntialiasing(aVDev.GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW);
+ }
+
+ if(rParameters.getSnapHorVerLines())
+ {
+ aVDev.SetAntialiasing(aVDev.GetAntialiasing() | ANTIALIASING_PIXELSNAPHAIRLINE);
+ }
+
+ ImplDraw( &aVDev, aNullPt, aDrawSize );
+ aRetBmp = aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() );
+ }
+ }
+
+ if( !!aRetBmp )
+ {
+ aRetBmp.SetPrefMapMode( ImplGetPrefMapMode() );
+ aRetBmp.SetPrefSize( ImplGetPrefSize() );
+ }
+
+ return aRetBmp;
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx ImpGraphic::ImplGetBitmapEx(const GraphicConversionParameters& rParameters) const
+{
+ BitmapEx aRetBmpEx;
+
+ if( meType == GRAPHIC_BITMAP )
+ {
+ aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx );
+
+ if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height())
+ aRetBmpEx.Scale(rParameters.getSizePixel());
+ }
+ else if( ( meType != GRAPHIC_DEFAULT ) && ImplIsSupportedGraphic() )
+ {
+ const ImpGraphic aMonoMask( maMetaFile.GetMonochromeMtf( COL_BLACK ) );
+ aRetBmpEx = BitmapEx(ImplGetBitmap(rParameters), aMonoMask.ImplGetBitmap(rParameters));
+ }
+
+ return aRetBmpEx;
+}
+
+// ------------------------------------------------------------------------
+
+Animation ImpGraphic::ImplGetAnimation() const
+{
+ Animation aAnimation;
+
+ if( mpAnimation )
+ aAnimation = *mpAnimation;
+
+ return aAnimation;
+}
+
+// ------------------------------------------------------------------------
+
+const GDIMetaFile& ImpGraphic::ImplGetGDIMetaFile() const
+{
+ return maMetaFile;
+}
+
+// ------------------------------------------------------------------------
+
+Size ImpGraphic::ImplGetPrefSize() const
+{
+ Size aSize;
+
+ if( ImplIsSwapOut() )
+ aSize = maSwapInfo.maPrefSize;
+ else
+ {
+ switch( meType )
+ {
+ case( GRAPHIC_NONE ):
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ {
+ aSize = maEx.GetPrefSize();
+
+ if( !aSize.Width() || !aSize.Height() )
+ aSize = maEx.GetSizePixel();
+ }
+ break;
+
+ default:
+ {
+ if( ImplIsSupportedGraphic() )
+ aSize = maMetaFile.GetPrefSize();
+ }
+ break;
+ }
+ }
+
+ return aSize;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize )
+{
+ switch( meType )
+ {
+ case( GRAPHIC_NONE ):
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ // #108077# Push through pref size to animation object,
+ // will be lost on copy otherwise
+ if( ImplIsAnimated() )
+ const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize( rPrefSize );
+
+ maEx.SetPrefSize( rPrefSize );
+ break;
+
+ default:
+ {
+ if( ImplIsSupportedGraphic() )
+ maMetaFile.SetPrefSize( rPrefSize );
+ }
+ break;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+MapMode ImpGraphic::ImplGetPrefMapMode() const
+{
+ MapMode aMapMode;
+
+ if( ImplIsSwapOut() )
+ aMapMode = maSwapInfo.maPrefMapMode;
+ else
+ {
+ switch( meType )
+ {
+ case( GRAPHIC_NONE ):
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ {
+ const Size aSize( maEx.GetPrefSize() );
+
+ if ( aSize.Width() && aSize.Height() )
+ aMapMode = maEx.GetPrefMapMode();
+ }
+ break;
+
+ default:
+ {
+ if( ImplIsSupportedGraphic() )
+ return maMetaFile.GetPrefMapMode();
+ }
+ break;
+ }
+ }
+
+ return aMapMode;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplSetPrefMapMode( const MapMode& rPrefMapMode )
+{
+ switch( meType )
+ {
+ case( GRAPHIC_NONE ):
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ // #108077# Push through pref mapmode to animation object,
+ // will be lost on copy otherwise
+ if( ImplIsAnimated() )
+ const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefMapMode( rPrefMapMode );
+
+ maEx.SetPrefMapMode( rPrefMapMode );
+ break;
+
+ default:
+ {
+ if( ImplIsSupportedGraphic() )
+ maMetaFile.SetPrefMapMode( rPrefMapMode );
+ }
+ break;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ImpGraphic::ImplGetSizeBytes() const
+{
+ if( 0 == mnSizeBytes )
+ {
+ if( meType == GRAPHIC_BITMAP )
+ {
+ mnSizeBytes = mpAnimation ? mpAnimation->GetSizeBytes() : maEx.GetSizeBytes();
+ }
+ else if( meType == GRAPHIC_GDIMETAFILE )
+ {
+ mnSizeBytes = maMetaFile.GetSizeBytes();
+ }
+ }
+
+ return( mnSizeBytes );
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplDraw( OutputDevice* pOutDev, const Point& rDestPt ) const
+{
+ if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
+ {
+ switch( meType )
+ {
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ {
+ if ( mpAnimation )
+ mpAnimation->Draw( pOutDev, rDestPt );
+ else
+ maEx.Draw( pOutDev, rDestPt );
+ }
+ break;
+
+ default:
+ ImplDraw( pOutDev, rDestPt, maMetaFile.GetPrefSize() );
+ break;
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplDraw( OutputDevice* pOutDev,
+ const Point& rDestPt, const Size& rDestSize ) const
+{
+ if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
+ {
+ switch( meType )
+ {
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ {
+ if( mpAnimation )
+ mpAnimation->Draw( pOutDev, rDestPt, rDestSize );
+ else
+ maEx.Draw( pOutDev, rDestPt, rDestSize );
+ }
+ break;
+
+ default:
+ {
+ ( (ImpGraphic*) this )->maMetaFile.WindStart();
+ ( (ImpGraphic*) this )->maMetaFile.Play( pOutDev, rDestPt, rDestSize );
+ ( (ImpGraphic*) this )->maMetaFile.WindStart();
+ }
+ break;
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev,
+ const Point& rDestPt,
+ long nExtraData,
+ OutputDevice* pFirstFrameOutDev )
+{
+ if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation )
+ mpAnimation->Start( pOutDev, rDestPt, nExtraData, pFirstFrameOutDev );
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, const Point& rDestPt,
+ const Size& rDestSize, long nExtraData,
+ OutputDevice* pFirstFrameOutDev )
+{
+ if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation )
+ mpAnimation->Start( pOutDev, rDestPt, rDestSize, nExtraData, pFirstFrameOutDev );
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplStopAnimation( OutputDevice* pOutDev, long nExtraData )
+{
+ if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation )
+ mpAnimation->Stop( pOutDev, nExtraData );
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplSetAnimationNotifyHdl( const Link& rLink )
+{
+ if( mpAnimation )
+ mpAnimation->SetNotifyHdl( rLink );
+}
+
+// ------------------------------------------------------------------------
+
+Link ImpGraphic::ImplGetAnimationNotifyHdl() const
+{
+ Link aLink;
+
+ if( mpAnimation )
+ aLink = mpAnimation->GetNotifyHdl();
+
+ return aLink;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ImpGraphic::ImplGetAnimationLoopCount() const
+{
+ return( mpAnimation ? mpAnimation->GetLoopCount() : 0UL );
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplResetAnimationLoopCount()
+{
+ if( mpAnimation )
+ mpAnimation->ResetLoopCount();
+}
+
+// ------------------------------------------------------------------------
+
+List* ImpGraphic::ImplGetAnimationInfoList() const
+{
+ return( mpAnimation ? mpAnimation->GetAInfoList() : NULL );
+}
+
+// ------------------------------------------------------------------------
+
+GraphicReader* ImpGraphic::ImplGetContext()
+{
+ return mpContext;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplSetContext( GraphicReader* pReader )
+{
+ mpContext = pReader;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplSetDocFileName( const String& rName, ULONG nFilePos )
+{
+ const INetURLObject aURL( rName );
+
+ DBG_ASSERT( !rName.Len() || ( aURL.GetProtocol() != INET_PROT_NOT_VALID ), "Graphic::SetDocFileName(...): invalid URL" );
+
+ maDocFileURLStr = aURL.GetMainURL( INetURLObject::NO_DECODE );
+ mnDocFilePos = nFilePos;
+}
+
+// ------------------------------------------------------------------------
+
+const String& ImpGraphic::ImplGetDocFileName() const
+{
+ return maDocFileURLStr;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ImpGraphic::ImplGetDocFilePos() const
+{
+ return mnDocFilePos;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplReadEmbedded( SvStream& rIStm, BOOL bSwap )
+{
+ MapMode aMapMode;
+ Size aSize;
+ const ULONG nStartPos = rIStm.Tell();
+ sal_uInt32 nId;
+ ULONG nHeaderLen;
+ long nType;
+ long nLen;
+ const USHORT nOldFormat = rIStm.GetNumberFormatInt();
+ BOOL bRet = FALSE;
+
+ if( !mbSwapUnderway )
+ {
+ const String aTempURLStr( maDocFileURLStr );
+ const ULONG nTempPos = mnDocFilePos;
+
+ ImplClear();
+
+ maDocFileURLStr = aTempURLStr;
+ mnDocFilePos = nTempPos;
+ }
+
+ rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+ rIStm >> nId;
+
+ // check version
+ if( GRAPHIC_FORMAT_50 == nId )
+ {
+ // read new style header
+ VersionCompat* pCompat = new VersionCompat( rIStm, STREAM_READ );
+
+ rIStm >> nType;
+ rIStm >> nLen;
+ rIStm >> aSize;
+ rIStm >> aMapMode;
+
+ delete pCompat;
+ }
+ else
+ {
+ // read old style header
+ long nWidth, nHeight;
+ long nMapMode, nScaleNumX, nScaleDenomX;
+ long nScaleNumY, nScaleDenomY, nOffsX, nOffsY;
+
+ rIStm.SeekRel( -4L );
+
+ rIStm >> nType >> nLen >> nWidth >> nHeight;
+ rIStm >> nMapMode >> nScaleNumX >> nScaleDenomX >> nScaleNumY;
+ rIStm >> nScaleDenomY >> nOffsX >> nOffsY;
+
+ // swapped
+ if( nType > 100L )
+ {
+ nType = SWAPLONG( nType );
+ nLen = SWAPLONG( nLen );
+ nWidth = SWAPLONG( nWidth );
+ nHeight = SWAPLONG( nHeight );
+ nMapMode = SWAPLONG( nMapMode );
+ nScaleNumX = SWAPLONG( nScaleNumX );
+ nScaleDenomX = SWAPLONG( nScaleDenomX );
+ nScaleNumY = SWAPLONG( nScaleNumY );
+ nScaleDenomY = SWAPLONG( nScaleDenomY );
+ nOffsX = SWAPLONG( nOffsX );
+ nOffsY = SWAPLONG( nOffsY );
+ }
+
+ aSize = Size( nWidth, nHeight );
+ aMapMode = MapMode( (MapUnit) nMapMode, Point( nOffsX, nOffsY ),
+ Fraction( nScaleNumX, nScaleDenomX ),
+ Fraction( nScaleNumY, nScaleDenomY ) );
+ }
+
+ nHeaderLen = rIStm.Tell() - nStartPos;
+ meType = (GraphicType) nType;
+
+ if( meType )
+ {
+ if( meType == GRAPHIC_BITMAP )
+ {
+ maEx.aBitmapSize = aSize;
+
+ if( aMapMode != MapMode() )
+ {
+ maEx.SetPrefMapMode( aMapMode );
+ maEx.SetPrefSize( aSize );
+ }
+ }
+ else
+ {
+ maMetaFile.SetPrefMapMode( aMapMode );
+ maMetaFile.SetPrefSize( aSize );
+ }
+
+ if( bSwap )
+ {
+ if( maDocFileURLStr.Len() )
+ {
+ rIStm.Seek( nStartPos + nHeaderLen + nLen );
+ bRet = mbSwapOut = TRUE;
+ }
+ else
+ {
+ ::utl::TempFile aTempFile;
+ const INetURLObject aTmpURL( aTempFile.GetURL() );
+
+ if( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() )
+ {
+ SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READWRITE | STREAM_SHARE_DENYWRITE );
+
+ if( pOStm )
+ {
+ ULONG nFullLen = nHeaderLen + nLen;
+ ULONG nPartLen = Min( nFullLen, (ULONG) GRAPHIC_MAXPARTLEN );
+ BYTE* pBuffer = (BYTE*) rtl_allocateMemory( nPartLen );
+
+ pOStm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ if( pBuffer )
+ {
+ rIStm.Seek( nStartPos );
+
+ while( nFullLen )
+ {
+ rIStm.Read( (char*) pBuffer, nPartLen );
+ pOStm->Write( (char*) pBuffer, nPartLen );
+
+ nFullLen -= nPartLen;
+
+ if( nFullLen < GRAPHIC_MAXPARTLEN )
+ nPartLen = nFullLen;
+ }
+
+ rtl_freeMemory( pBuffer );
+ ULONG nReadErr = rIStm.GetError(), nWriteErr = pOStm->GetError();
+ delete pOStm, pOStm = NULL;
+
+ if( !nReadErr && !nWriteErr )
+ {
+ bRet = mbSwapOut = TRUE;
+ mpSwapFile = new ImpSwapFile;
+ mpSwapFile->nRefCount = 1;
+ mpSwapFile->aSwapURL = aTmpURL;
+ }
+ else
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ),
+ ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() );
+
+ aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ),
+ ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) );
+ }
+ catch( const ::com::sun::star::ucb::ContentCreationException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::RuntimeException& )
+ {
+ }
+ catch( const ::com::sun::star::ucb::CommandAbortedException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+ }
+ }
+
+ delete pOStm;
+ }
+ }
+ }
+ }
+ else if( meType == GRAPHIC_BITMAP || meType == GRAPHIC_GDIMETAFILE )
+ {
+ rIStm >> *this;
+ bRet = ( rIStm.GetError() == 0UL );
+ }
+ else if( meType >= SYS_WINMETAFILE && meType <= SYS_MACMETAFILE )
+ {
+ Graphic aSysGraphic;
+ ULONG nCvtType;
+
+ switch( sal::static_int_cast<ULONG>(meType) )
+ {
+ case( SYS_WINMETAFILE ):
+ case( SYS_WNTMETAFILE ): nCvtType = CVT_WMF; break;
+ case( SYS_OS2METAFILE ): nCvtType = CVT_MET; break;
+ case( SYS_MACMETAFILE ): nCvtType = CVT_PCT; break;
+
+ default:
+ nCvtType = CVT_UNKNOWN;
+ break;
+ }
+
+ if( nType && GraphicConverter::Import( rIStm, aSysGraphic, nCvtType ) == ERRCODE_NONE )
+ {
+ *this = ImpGraphic( aSysGraphic.GetGDIMetaFile() );
+ bRet = ( rIStm.GetError() == 0UL );
+ }
+ else
+ meType = GRAPHIC_DEFAULT;
+ }
+
+ if( bRet )
+ {
+ ImplSetPrefMapMode( aMapMode );
+ ImplSetPrefSize( aSize );
+ }
+ }
+ else
+ bRet = TRUE;
+
+ rIStm.SetNumberFormatInt( nOldFormat );
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplWriteEmbedded( SvStream& rOStm )
+{
+ BOOL bRet = FALSE;
+
+ if( ( meType != GRAPHIC_NONE ) && ( meType != GRAPHIC_DEFAULT ) && !ImplIsSwapOut() )
+ {
+ const MapMode aMapMode( ImplGetPrefMapMode() );
+ const Size aSize( ImplGetPrefSize() );
+ const USHORT nOldFormat = rOStm.GetNumberFormatInt();
+ ULONG nDataFieldPos;
+
+ rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ // write correct version ( old style/new style header )
+ if( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 )
+ {
+ // write ID for new format (5.0)
+ rOStm << GRAPHIC_FORMAT_50;
+
+ // write new style header
+ VersionCompat* pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 );
+
+ rOStm << (long) meType;
+
+ // data size is updated later
+ nDataFieldPos = rOStm.Tell();
+ rOStm << (long) 0;
+
+ rOStm << aSize;
+ rOStm << aMapMode;
+
+ delete pCompat;
+ }
+ else
+ {
+ // write old style (<=4.0) header
+ rOStm << (long) meType;
+
+ // data size is updated later
+ nDataFieldPos = rOStm.Tell();
+ rOStm << (long) 0;
+
+ rOStm << (long) aSize.Width();
+ rOStm << (long) aSize.Height();
+ rOStm << (long) aMapMode.GetMapUnit();
+ rOStm << (long) aMapMode.GetScaleX().GetNumerator();
+ rOStm << (long) aMapMode.GetScaleX().GetDenominator();
+ rOStm << (long) aMapMode.GetScaleY().GetNumerator();
+ rOStm << (long) aMapMode.GetScaleY().GetDenominator();
+ rOStm << (long) aMapMode.GetOrigin().X();
+ rOStm << (long) aMapMode.GetOrigin().Y();
+ }
+
+ // write data block
+ if( !rOStm.GetError() )
+ {
+ const ULONG nDataStart = rOStm.Tell();
+
+ if( ImplIsSupportedGraphic() )
+ rOStm << *this;
+
+ if( !rOStm.GetError() )
+ {
+ const ULONG nStmPos2 = rOStm.Tell();
+ rOStm.Seek( nDataFieldPos );
+ rOStm << (long) ( nStmPos2 - nDataStart );
+ rOStm.Seek( nStmPos2 );
+ bRet = TRUE;
+ }
+ }
+
+ rOStm.SetNumberFormatInt( nOldFormat );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplSwapOut()
+{
+ BOOL bRet = FALSE;
+
+ if( !ImplIsSwapOut() )
+ {
+ if( !maDocFileURLStr.Len() )
+ {
+ ::utl::TempFile aTempFile;
+ const INetURLObject aTmpURL( aTempFile.GetURL() );
+
+ if( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() )
+ {
+ SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READWRITE | STREAM_SHARE_DENYWRITE );
+
+ if( pOStm )
+ {
+ pOStm->SetVersion( SOFFICE_FILEFORMAT_50 );
+ pOStm->SetCompressMode( COMPRESSMODE_NATIVE );
+
+ if( ( bRet = ImplSwapOut( pOStm ) ) == TRUE )
+ {
+ mpSwapFile = new ImpSwapFile;
+ mpSwapFile->nRefCount = 1;
+ mpSwapFile->aSwapURL = aTmpURL;
+ }
+ else
+ {
+ delete pOStm, pOStm = NULL;
+
+ try
+ {
+ ::ucbhelper::Content aCnt( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ),
+ ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() );
+
+ aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ),
+ ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) );
+ }
+ catch( const ::com::sun::star::ucb::ContentCreationException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::RuntimeException& )
+ {
+ }
+ catch( const ::com::sun::star::ucb::CommandAbortedException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+ }
+
+ delete pOStm;
+ }
+ }
+ }
+ else
+ {
+ ImplClearGraphics( TRUE );
+ bRet = mbSwapOut = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplSwapOut( SvStream* pOStm )
+{
+ BOOL bRet = FALSE;
+
+ if( pOStm )
+ {
+ pOStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE );
+
+ if( !pOStm->GetError() && ImplWriteEmbedded( *pOStm ) )
+ {
+ pOStm->Flush();
+
+ if( !pOStm->GetError() )
+ {
+ ImplClearGraphics( TRUE );
+ bRet = mbSwapOut = TRUE;
+ }
+ }
+ }
+ else
+ {
+ ImplClearGraphics( TRUE );
+ bRet = mbSwapOut = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplSwapIn()
+{
+ BOOL bRet = FALSE;
+
+ if( ImplIsSwapOut() )
+ {
+ String aSwapURL;
+
+ if( mpSwapFile )
+ aSwapURL = mpSwapFile->aSwapURL.GetMainURL( INetURLObject::NO_DECODE );
+ else
+ aSwapURL = maDocFileURLStr;
+
+ if( aSwapURL.Len() )
+ {
+ SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( aSwapURL, STREAM_READWRITE | STREAM_SHARE_DENYWRITE );
+
+ if( pIStm )
+ {
+ pIStm->SetVersion( SOFFICE_FILEFORMAT_50 );
+ pIStm->SetCompressMode( COMPRESSMODE_NATIVE );
+
+ if( !mpSwapFile )
+ pIStm->Seek( mnDocFilePos );
+
+ bRet = ImplSwapIn( pIStm );
+ delete pIStm;
+
+ if( mpSwapFile )
+ {
+ if( mpSwapFile->nRefCount > 1 )
+ mpSwapFile->nRefCount--;
+ else
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( aSwapURL,
+ ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() );
+
+ aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ),
+ ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) );
+ }
+ catch( const ::com::sun::star::ucb::ContentCreationException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::RuntimeException& )
+ {
+ }
+ catch( const ::com::sun::star::ucb::CommandAbortedException& )
+ {
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+
+ delete mpSwapFile;
+ }
+
+ mpSwapFile = NULL;
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplSwapIn( SvStream* pIStm )
+{
+ BOOL bRet = FALSE;
+
+ if( pIStm )
+ {
+ pIStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE );
+
+ if( !pIStm->GetError() )
+ {
+ mbSwapUnderway = TRUE;
+ bRet = ImplReadEmbedded( *pIStm );
+ mbSwapUnderway = FALSE;
+
+ if( !bRet )
+ ImplClear();
+ else
+ mbSwapOut = FALSE;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplIsSwapOut() const
+{
+ return mbSwapOut;
+}
+
+// ------------------------------------------------------------------------
+
+void ImpGraphic::ImplSetLink( const GfxLink& rGfxLink )
+{
+ delete mpGfxLink;
+ mpGfxLink = new GfxLink( rGfxLink );
+
+ if( mpGfxLink->IsNative() )
+ mpGfxLink->SwapOut();
+}
+
+// ------------------------------------------------------------------------
+
+GfxLink ImpGraphic::ImplGetLink()
+{
+ return( mpGfxLink ? *mpGfxLink : GfxLink() );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplIsLink() const
+{
+ return ( mpGfxLink != NULL ) ? TRUE : FALSE;
+}
+
+// ------------------------------------------------------------------------
+
+ULONG ImpGraphic::ImplGetChecksum() const
+{
+ ULONG nRet = 0;
+
+ if( ImplIsSupportedGraphic() && !ImplIsSwapOut() )
+ {
+ switch( meType )
+ {
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case( GRAPHIC_BITMAP ):
+ {
+ if( mpAnimation )
+ nRet = mpAnimation->GetChecksum();
+ else
+ nRet = maEx.GetChecksum();
+ }
+ break;
+
+ default:
+ nRet = maMetaFile.GetChecksum();
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL ImpGraphic::ImplExportNative( SvStream& rOStm ) const
+{
+ BOOL bResult = FALSE;
+
+ if( !rOStm.GetError() )
+ {
+ if( !ImplIsSwapOut() )
+ {
+ if( mpGfxLink && mpGfxLink->IsNative() )
+ bResult = mpGfxLink->ExportNative( rOStm );
+ else
+ {
+ rOStm << *this;
+ bResult = ( rOStm.GetError() == ERRCODE_NONE );
+ }
+ }
+ else
+ rOStm.SetError( SVSTREAM_GENERALERROR );
+ }
+
+ return bResult;
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, ImpGraphic& rImpGraphic )
+{
+ if( !rIStm.GetError() )
+ {
+ const ULONG nStmPos1 = rIStm.Tell();
+ sal_uInt32 nTmp;
+
+ if ( !rImpGraphic.mbSwapUnderway )
+ rImpGraphic.ImplClear();
+
+ // read Id
+ rIStm >> nTmp;
+
+ // if there is no more data, avoid further expensive
+ // reading which will create VDevs and other stuff, just to
+ // read nothing. CAUTION: Eof is only true AFTER reading another
+ // byte, a speciality of SvMemoryStream (!)
+ if(!rIStm.GetError() && !rIStm.IsEof())
+ {
+ if( NATIVE_FORMAT_50 == nTmp )
+ {
+ Graphic aGraphic;
+ GfxLink aLink;
+ VersionCompat* pCompat;
+
+ // read compat info
+ pCompat = new VersionCompat( rIStm, STREAM_READ );
+ delete pCompat;
+
+ rIStm >> aLink;
+
+ // set dummy link to avoid creation of additional link after filtering;
+ // we set a default link to avoid unnecessary swapping of native data
+ aGraphic.SetLink( GfxLink() );
+
+ if( !rIStm.GetError() && aLink.LoadNative( aGraphic ) )
+ {
+ // set link only, if no other link was set
+ const BOOL bSetLink = ( rImpGraphic.mpGfxLink == NULL );
+
+ // assign graphic
+ rImpGraphic = *aGraphic.ImplGetImpGraphic();
+
+ if( aLink.IsPrefMapModeValid() )
+ rImpGraphic.ImplSetPrefMapMode( aLink.GetPrefMapMode() );
+
+ if( aLink.IsPrefSizeValid() )
+ rImpGraphic.ImplSetPrefSize( aLink.GetPrefSize() );
+
+ if( bSetLink )
+ rImpGraphic.ImplSetLink( aLink );
+ }
+ else
+ {
+ rIStm.Seek( nStmPos1 );
+ rIStm.SetError( ERRCODE_IO_WRONGFORMAT );
+ }
+ }
+ else
+ {
+ BitmapEx aBmpEx;
+ const USHORT nOldFormat = rIStm.GetNumberFormatInt();
+
+ rIStm.SeekRel( -4 );
+ rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+ rIStm >> aBmpEx;
+
+ if( !rIStm.GetError() )
+ {
+ UINT32 nMagic1(0), nMagic2(0);
+ ULONG nActPos = rIStm.Tell();
+
+ rIStm >> nMagic1 >> nMagic2;
+ rIStm.Seek( nActPos );
+
+ rImpGraphic = ImpGraphic( aBmpEx );
+
+ if( !rIStm.GetError() && ( 0x5344414e == nMagic1 ) && ( 0x494d4931 == nMagic2 ) )
+ {
+ delete rImpGraphic.mpAnimation;
+ rImpGraphic.mpAnimation = new Animation;
+ rIStm >> *rImpGraphic.mpAnimation;
+
+ // #108077# manually set loaded BmpEx to Animation
+ // (which skips loading its BmpEx if already done)
+ rImpGraphic.mpAnimation->SetBitmapEx(aBmpEx);
+ }
+ else
+ rIStm.ResetError();
+ }
+ else
+ {
+ GDIMetaFile aMtf;
+
+ rIStm.Seek( nStmPos1 );
+ rIStm.ResetError();
+ rIStm >> aMtf;
+
+ if( !rIStm.GetError() )
+ rImpGraphic = aMtf;
+ else
+ rIStm.Seek( nStmPos1 );
+ }
+
+ rIStm.SetNumberFormatInt( nOldFormat );
+ }
+ }
+ }
+
+ return rIStm;
+}
+
+// ------------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const ImpGraphic& rImpGraphic )
+{
+ if( !rOStm.GetError() )
+ {
+ if( !rImpGraphic.ImplIsSwapOut() )
+ {
+ if( ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) &&
+ ( rOStm.GetCompressMode() & COMPRESSMODE_NATIVE ) &&
+ rImpGraphic.mpGfxLink && rImpGraphic.mpGfxLink->IsNative() )
+ {
+ VersionCompat* pCompat;
+
+ // native format
+ rOStm << NATIVE_FORMAT_50;
+
+ // write compat info
+ pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 );
+ delete pCompat;
+
+ rImpGraphic.mpGfxLink->SetPrefMapMode( rImpGraphic.ImplGetPrefMapMode() );
+ rImpGraphic.mpGfxLink->SetPrefSize( rImpGraphic.ImplGetPrefSize() );
+ rOStm << *rImpGraphic.mpGfxLink;
+ }
+ else
+ {
+ // own format
+ const USHORT nOldFormat = rOStm.GetNumberFormatInt();
+ rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+
+ switch( rImpGraphic.ImplGetType() )
+ {
+ case( GRAPHIC_NONE ):
+ case( GRAPHIC_DEFAULT ):
+ break;
+
+ case GRAPHIC_BITMAP:
+ {
+ if ( rImpGraphic.ImplIsAnimated() )
+ rOStm << *rImpGraphic.mpAnimation;
+ else
+ rOStm << rImpGraphic.maEx;
+ }
+ break;
+
+ default:
+ {
+ if( rImpGraphic.ImplIsSupportedGraphic() )
+ rOStm << rImpGraphic.maMetaFile;
+ }
+ break;
+ }
+
+ rOStm.SetNumberFormatInt( nOldFormat );
+ }
+ }
+ else
+ rOStm.SetError( SVSTREAM_GENERALERROR );
+ }
+
+ return rOStm;
+}
diff --git a/vcl/source/gdi/impimage.cxx b/vcl/source/gdi/impimage.cxx
new file mode 100644
index 000000000000..476ac3ca44a9
--- /dev/null
+++ b/vcl/source/gdi/impimage.cxx
@@ -0,0 +1,634 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/outdev.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/alpha.hxx>
+#include <vcl/window.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/image.h>
+#include <vcl/image.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define IMPSYSIMAGEITEM_MASK ( 0x01 )
+#define IMPSYSIMAGEITEM_ALPHA ( 0x02 )
+#define DISA_ALL ( 0xffff )
+
+// ----------------
+// - ImageAryData -
+// ----------------
+
+ImageAryData::ImageAryData() :
+ maName(),
+ mnId( 0 ),
+ maBitmapEx()
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImageAryData::ImageAryData( const ImageAryData& rData ) :
+ maName( rData.maName ),
+ mnId( rData.mnId ),
+ maBitmapEx( rData.maBitmapEx )
+{
+}
+
+ImageAryData::ImageAryData( const rtl::OUString &aName,
+ USHORT nId, const BitmapEx &aBitmap )
+ : maName( aName ), mnId( nId ), maBitmapEx( aBitmap )
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImageAryData::~ImageAryData()
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImageAryData& ImageAryData::operator=( const ImageAryData& rData )
+{
+ maName = rData.maName;
+ mnId = rData.mnId;
+ maBitmapEx = rData.maBitmapEx;
+
+ return *this;
+}
+
+// -----------------
+// - ImplImageList -
+// -----------------
+
+ImplImageList::ImplImageList()
+{
+}
+
+ImplImageList::ImplImageList( const ImplImageList &aSrc ) :
+ maPrefix( aSrc.maPrefix ),
+ maImageSize( aSrc.maImageSize ),
+ mnRefCount( 1 )
+{
+ maImages.reserve( aSrc.maImages.size() );
+ for ( ImageAryDataVec::const_iterator aIt = aSrc.maImages.begin(), aEnd = aSrc.maImages.end(); aIt != aEnd; ++aIt )
+ {
+ ImageAryData* pAryData = new ImageAryData( **aIt );
+ maImages.push_back( pAryData );
+ if( pAryData->maName.getLength() )
+ maNameHash [ pAryData->maName ] = pAryData;
+ }
+}
+
+ImplImageList::~ImplImageList()
+{
+ for ( ImageAryDataVec::iterator aIt = maImages.begin(), aEnd = maImages.end(); aIt != aEnd; ++aIt )
+ delete *aIt;
+}
+
+void ImplImageList::AddImage( const ::rtl::OUString &aName,
+ USHORT nId, const BitmapEx &aBitmapEx )
+{
+ ImageAryData *pImg = new ImageAryData( aName, nId, aBitmapEx );
+ maImages.push_back( pImg );
+ if( aName.getLength() )
+ maNameHash [ aName ] = pImg;
+}
+
+void ImplImageList::RemoveImage( USHORT nPos )
+{
+ ImageAryData *pImg = maImages[ nPos ];
+ if( pImg->maName.getLength() )
+ maNameHash.erase( pImg->maName );
+ maImages.erase( maImages.begin() + nPos );
+}
+
+USHORT ImplImageList::GetImageCount() const
+{
+ return sal::static_int_cast< USHORT >( maImages.size() );
+}
+
+// -----------------
+// - ImplImageData -
+// -----------------
+
+ImplImageData::ImplImageData( const BitmapEx& rBmpEx ) :
+ mpImageBitmap( NULL ),
+ maBmpEx( rBmpEx )
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImplImageData::~ImplImageData()
+{
+ delete mpImageBitmap;
+}
+
+// -----------------
+// - ImplImageData -
+// -----------------
+
+BOOL ImplImageData::IsEqual( const ImplImageData& rData )
+{
+ return( maBmpEx == rData.maBmpEx );
+}
+
+// -------------
+// - ImplImage -
+// -------------
+
+ImplImage::ImplImage()
+{
+}
+
+// ------------------------------------------------------------------------------
+
+ImplImage::~ImplImage()
+{
+ switch( meType )
+ {
+ case IMAGETYPE_BITMAP:
+ delete static_cast< Bitmap* >( mpData );
+ break;
+
+ case IMAGETYPE_IMAGE:
+ delete static_cast< ImplImageData* >( mpData );
+ break;
+ }
+}
+
+// ----------------
+// - ImplImageBmp -
+// ----------------
+
+ImplImageBmp::ImplImageBmp() :
+ mpDisplayBmp( NULL ),
+ mpInfoAry( NULL ),
+ mnSize( 0 )
+{
+}
+
+// -------------
+// - ImplImage -
+// -------------
+
+ImplImageBmp::~ImplImageBmp()
+{
+ delete[] mpInfoAry;
+ delete mpDisplayBmp;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Create( long nItemWidth, long nItemHeight, USHORT nInitSize )
+{
+ const Size aTotalSize( nInitSize * nItemWidth, nItemHeight );
+
+ maBmpEx = Bitmap( aTotalSize, 24 );
+ maDisabledBmpEx.SetEmpty();
+
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+
+ maSize = Size( nItemWidth, nItemHeight );
+ mnSize = nInitSize;
+
+ delete[] mpInfoAry;
+ mpInfoAry = new BYTE[ mnSize ];
+ memset( mpInfoAry, 0, mnSize );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Create( const BitmapEx& rBmpEx, long nItemWidth, long nItemHeight, USHORT nInitSize )
+{
+ maBmpEx = rBmpEx;
+ maDisabledBmpEx.SetEmpty();
+
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+
+ maSize = Size( nItemWidth, nItemHeight );
+ mnSize = nInitSize;
+
+ delete[] mpInfoAry;
+ mpInfoAry = new BYTE[ mnSize ];
+ memset( mpInfoAry,
+ rBmpEx.IsAlpha() ? IMPSYSIMAGEITEM_ALPHA : ( rBmpEx.IsTransparent() ? IMPSYSIMAGEITEM_MASK : 0 ),
+ mnSize );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Expand( USHORT nGrowSize )
+{
+ const ULONG nDX = nGrowSize * maSize.Width();
+ const USHORT nOldSize = mnSize;
+ BYTE* pNewAry = new BYTE[ mnSize = sal::static_int_cast<USHORT>(mnSize+nGrowSize) ];
+
+ maBmpEx.Expand( nDX, 0UL );
+
+ if( !maDisabledBmpEx.IsEmpty() )
+ maDisabledBmpEx.Expand( nDX, 0UL );
+
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+
+ memset( pNewAry, 0, mnSize );
+ memcpy( pNewAry, mpInfoAry, nOldSize );
+ delete[] mpInfoAry;
+ mpInfoAry = pNewAry;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Invert()
+{
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+
+ maBmpEx.Invert();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Replace( USHORT nPos, USHORT nSrcPos )
+{
+ const Point aSrcPos( nSrcPos * maSize.Width(), 0L ), aPos( nPos * maSize.Width(), 0L );
+ const Rectangle aSrcRect( aSrcPos, maSize );
+ const Rectangle aDstRect( aPos, maSize );
+
+ maBmpEx.CopyPixel( aDstRect, aSrcRect );
+
+ if( !maDisabledBmpEx.IsEmpty() )
+ maDisabledBmpEx.CopyPixel( aDstRect, aSrcRect );
+
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+
+ mpInfoAry[ nPos ] = mpInfoAry[ nSrcPos ];
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Replace( USHORT nPos, const ImplImageBmp& rImageBmp, USHORT nSrcPos )
+{
+ const Point aSrcPos( nSrcPos * maSize.Width(), 0L ), aPos( nPos * maSize.Width(), 0L );
+ const Rectangle aSrcRect( aSrcPos, maSize );
+ const Rectangle aDstRect( aPos, maSize );
+
+ maBmpEx.CopyPixel( aDstRect, aSrcRect, &rImageBmp.maBmpEx );
+
+ ImplUpdateDisabledBmpEx( nPos );
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+
+ mpInfoAry[ nPos ] = rImageBmp.mpInfoAry[ nSrcPos ];
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Replace( USHORT nPos, const BitmapEx& rBmpEx )
+{
+ const Point aNullPos, aPos( nPos * maSize.Width(), 0L );
+ const Rectangle aSrcRect( aNullPos, maSize );
+ const Rectangle aDstRect( aPos, maSize );
+
+ maBmpEx.CopyPixel( aDstRect, aSrcRect, &rBmpEx );
+
+ ImplUpdateDisabledBmpEx( nPos );
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+
+ mpInfoAry[ nPos ] &= ~( IMPSYSIMAGEITEM_MASK | IMPSYSIMAGEITEM_ALPHA );
+ mpInfoAry[ nPos ] |= ( rBmpEx.IsAlpha() ? IMPSYSIMAGEITEM_ALPHA : ( rBmpEx.IsTransparent() ? IMPSYSIMAGEITEM_MASK : 0 ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::ReplaceColors( const Color* pSrcColors, const Color* pDstColors, ULONG nColorCount )
+{
+ maBmpEx.Replace( pSrcColors, pDstColors, nColorCount );
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::ColorTransform( BmpColorMode eColorMode )
+{
+ maBmpEx = maBmpEx.GetColorTransformedBitmapEx( eColorMode );
+ delete mpDisplayBmp;
+ mpDisplayBmp = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+BitmapEx ImplImageBmp::GetBitmapEx( USHORT nPosCount, USHORT* pPosAry ) const
+{
+ const Bitmap aNewBmp( Size( nPosCount * maSize.Width(), maSize.Height() ), maBmpEx.GetBitmap().GetBitCount() );
+ BitmapEx aRet;
+ if( maBmpEx.IsAlpha() )
+ {
+ // initialize target bitmap with an empty alpha mask
+ // which allows for using an optimized copypixel later on (see AlphaMask::CopyPixel)
+ // that avoids palette lookups
+ AlphaMask aAlpha( Size( nPosCount * maSize.Width(), maSize.Height() ) );
+ aRet = BitmapEx( aNewBmp, aAlpha );
+ }
+ else
+ aRet = BitmapEx( aNewBmp );
+
+ for( USHORT i = 0; i < nPosCount; i++ )
+ {
+ const Point aSrcPos( pPosAry[ i ] * maSize.Width(), 0L );
+ const Point aPos( i * maSize.Width(), 0L );
+ const Rectangle aSrcRect( aSrcPos, maSize );
+ const Rectangle aDstRect( aPos, maSize );
+
+ aRet.CopyPixel( aDstRect, aSrcRect, &maBmpEx );
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::Draw( USHORT nPos, OutputDevice* pOutDev,
+ const Point& rPos, USHORT nStyle,
+ const Size* pSize )
+{
+ if( pOutDev->IsDeviceOutputNecessary() )
+ {
+ const Point aSrcPos( nPos * maSize.Width(), 0 );
+ Size aOutSize;
+
+ aOutSize = ( pSize ? *pSize : pOutDev->PixelToLogic( maSize ) );
+
+ if( nStyle & IMAGE_DRAW_DISABLE )
+ {
+ ImplUpdateDisabledBmpEx( nPos);
+ pOutDev->DrawBitmapEx( rPos, aOutSize, aSrcPos, maSize, maDisabledBmpEx );
+ }
+ else
+ {
+ if( nStyle & ( IMAGE_DRAW_COLORTRANSFORM |
+ IMAGE_DRAW_MONOCHROME_BLACK | IMAGE_DRAW_MONOCHROME_WHITE |
+ IMAGE_DRAW_HIGHLIGHT | IMAGE_DRAW_DEACTIVE | IMAGE_DRAW_SEMITRANSPARENT ) )
+ {
+ BitmapEx aTmpBmpEx;
+ const Rectangle aCropRect( aSrcPos, maSize );
+
+ if( mpInfoAry[ nPos ] & ( IMPSYSIMAGEITEM_MASK | IMPSYSIMAGEITEM_ALPHA ) )
+ aTmpBmpEx = maBmpEx;
+ else
+ aTmpBmpEx = maBmpEx.GetBitmap();
+
+ aTmpBmpEx.Crop( aCropRect );
+
+ if( nStyle & ( IMAGE_DRAW_COLORTRANSFORM | IMAGE_DRAW_MONOCHROME_BLACK | IMAGE_DRAW_MONOCHROME_WHITE ) )
+ {
+ const BmpColorMode eMode = ( nStyle & IMAGE_DRAW_COLORTRANSFORM ) ? BMP_COLOR_HIGHCONTRAST :
+ ( ( nStyle & IMAGE_DRAW_MONOCHROME_BLACK ) ? BMP_COLOR_MONOCHROME_BLACK : BMP_COLOR_MONOCHROME_WHITE );
+
+ aTmpBmpEx = aTmpBmpEx.GetColorTransformedBitmapEx( eMode );
+ }
+
+ Bitmap aTmpBmp( aTmpBmpEx.GetBitmap() );
+
+ if( nStyle & ( IMAGE_DRAW_HIGHLIGHT | IMAGE_DRAW_DEACTIVE ) )
+ {
+ BitmapWriteAccess* pAcc = aTmpBmp.AcquireWriteAccess();
+
+ if( pAcc )
+ {
+ const StyleSettings& rSettings = pOutDev->GetSettings().GetStyleSettings();
+ Color aColor;
+ BitmapColor aCol;
+ const long nW = pAcc->Width();
+ const long nH = pAcc->Height();
+ BYTE* pMapR = new BYTE[ 256 ];
+ BYTE* pMapG = new BYTE[ 256 ];
+ BYTE* pMapB = new BYTE[ 256 ];
+ long nX, nY;
+
+ if( nStyle & IMAGE_DRAW_HIGHLIGHT )
+ aColor = rSettings.GetHighlightColor();
+ else
+ aColor = rSettings.GetDeactiveColor();
+
+ const BYTE cR = aColor.GetRed();
+ const BYTE cG = aColor.GetGreen();
+ const BYTE cB = aColor.GetBlue();
+
+ for( nX = 0L; nX < 256L; nX++ )
+ {
+ pMapR[ nX ] = (BYTE) ( ( ( nY = ( nX + cR ) >> 1 ) > 255 ) ? 255 : nY );
+ pMapG[ nX ] = (BYTE) ( ( ( nY = ( nX + cG ) >> 1 ) > 255 ) ? 255 : nY );
+ pMapB[ nX ] = (BYTE) ( ( ( nY = ( nX + cB ) >> 1 ) > 255 ) ? 255 : nY );
+ }
+
+ if( pAcc->HasPalette() )
+ {
+ for( USHORT i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
+ {
+ const BitmapColor& rCol = pAcc->GetPaletteColor( i );
+ aCol.SetRed( pMapR[ rCol.GetRed() ] );
+ aCol.SetGreen( pMapG[ rCol.GetGreen() ] );
+ aCol.SetBlue( pMapB[ rCol.GetBlue() ] );
+ pAcc->SetPaletteColor( i, aCol );
+ }
+ }
+ else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
+ {
+ for( nY = 0L; nY < nH; nY++ )
+ {
+ Scanline pScan = pAcc->GetScanline( nY );
+
+ for( nX = 0L; nX < nW; nX++ )
+ {
+ *pScan = pMapB[ *pScan ]; pScan++;
+ *pScan = pMapG[ *pScan ]; pScan++;
+ *pScan = pMapR[ *pScan ]; pScan++;
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0L; nY < nH; nY++ )
+ {
+ for( nX = 0L; nX < nW; nX++ )
+ {
+ aCol = pAcc->GetPixel( nY, nX );
+ aCol.SetRed( pMapR[ aCol.GetRed() ] );
+ aCol.SetGreen( pMapG[ aCol.GetGreen() ] );
+ aCol.SetBlue( pMapB[ aCol.GetBlue() ] );
+ pAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+ }
+
+ delete[] pMapR;
+ delete[] pMapG;
+ delete[] pMapB;
+ aTmpBmp.ReleaseAccess( pAcc );
+ }
+ }
+
+ if( nStyle & IMAGE_DRAW_SEMITRANSPARENT )
+ {
+ if( aTmpBmpEx.IsTransparent() )
+ {
+ Bitmap aAlphaBmp( aTmpBmpEx.GetAlpha().GetBitmap() );
+
+ aAlphaBmp.Adjust( 50 );
+ aTmpBmpEx = BitmapEx( aTmpBmp, AlphaMask( aAlphaBmp ) );
+ }
+ else
+ {
+ BYTE cErase = 128;
+ aTmpBmpEx = BitmapEx( aTmpBmp, AlphaMask( aTmpBmp.GetSizePixel(), &cErase ) );
+ }
+ }
+ else
+ {
+ if( aTmpBmpEx.IsAlpha() )
+ aTmpBmpEx = BitmapEx( aTmpBmp, aTmpBmpEx.GetAlpha() );
+ else if( aTmpBmpEx.IsAlpha() )
+ aTmpBmpEx = BitmapEx( aTmpBmp, aTmpBmpEx.GetMask() );
+ }
+
+ pOutDev->DrawBitmapEx( rPos, aOutSize, aTmpBmpEx );
+ }
+ else
+ {
+ const BitmapEx* pOutputBmp;
+
+ if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
+ {
+ ImplUpdateDisplayBmp( pOutDev );
+ pOutputBmp = mpDisplayBmp;
+ }
+ else
+ pOutputBmp = &maBmpEx;
+
+ if( pOutputBmp )
+ pOutDev->DrawBitmapEx( rPos, aOutSize, aSrcPos, maSize, *pOutputBmp );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::ImplUpdateDisplayBmp( OutputDevice*
+#if defined WIN || defined WNT
+pOutDev
+#endif
+)
+{
+ if( !mpDisplayBmp && !maBmpEx.IsEmpty() )
+ {
+#if defined WIN || defined WNT
+ if( maBmpEx.IsAlpha() )
+ mpDisplayBmp = new BitmapEx( maBmpEx );
+ else
+ {
+ const Bitmap aBmp( maBmpEx.GetBitmap().CreateDisplayBitmap( pOutDev ) );
+
+ if( maBmpEx.IsTransparent() )
+ mpDisplayBmp = new BitmapEx( aBmp, maBmpEx.GetMask().CreateDisplayBitmap( pOutDev ) );
+ else
+ mpDisplayBmp = new BitmapEx( aBmp );
+ }
+#else
+ mpDisplayBmp = new BitmapEx( maBmpEx );
+#endif
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplImageBmp::ImplUpdateDisabledBmpEx( int nPos )
+{
+ const Size aTotalSize( maBmpEx.GetSizePixel() );
+
+ if( maDisabledBmpEx.IsEmpty() )
+ {
+ Bitmap aGrey( aTotalSize, 8, &Bitmap::GetGreyPalette( 256 ) );
+ AlphaMask aGreyAlphaMask( aTotalSize );
+
+ maDisabledBmpEx = BitmapEx( aGrey, aGreyAlphaMask );
+ nPos = -1;
+ }
+
+ Bitmap aBmp( maBmpEx.GetBitmap() );
+ BitmapReadAccess* pBmp( aBmp.AcquireReadAccess() );
+ AlphaMask aBmpAlphaMask( maBmpEx.GetAlpha() );
+ BitmapReadAccess* pBmpAlphaMask( aBmpAlphaMask.AcquireReadAccess() );
+ Bitmap aGrey( maDisabledBmpEx.GetBitmap() );
+ BitmapWriteAccess* pGrey( aGrey.AcquireWriteAccess() );
+ AlphaMask aGreyAlphaMask( maDisabledBmpEx.GetAlpha() );
+ BitmapWriteAccess* pGreyAlphaMask( aGreyAlphaMask.AcquireWriteAccess() );
+
+ if( pBmp && pBmpAlphaMask && pGrey && pGreyAlphaMask )
+ {
+ BitmapColor aGreyVal( 0 );
+ BitmapColor aGreyAlphaMaskVal( 0 );
+ const Point aPos( ( nPos < 0 ) ? 0 : ( nPos * maSize.Width() ), 0 );
+ const int nLeft = aPos.X(), nRight = nLeft + ( ( nPos < 0 ) ? aTotalSize.Width() : maSize.Width() );
+ const int nTop = aPos.Y(), nBottom = nTop + maSize.Height();
+
+ for( int nY = nTop; nY < nBottom; ++nY )
+ {
+ for( int nX = nLeft; nX < nRight; ++nX )
+ {
+ aGreyVal.SetIndex( pBmp->GetLuminance( nY, nX ) );
+ pGrey->SetPixel( nY, nX, aGreyVal );
+
+ const BitmapColor aBmpAlphaMaskVal( pBmpAlphaMask->GetPixel( nY, nX ) );
+
+ aGreyAlphaMaskVal.SetIndex( static_cast< sal_uInt8 >( ::std::min( aBmpAlphaMaskVal.GetIndex() + 178ul, 255ul ) ) );
+ pGreyAlphaMask->SetPixel( nY, nX, aGreyAlphaMaskVal );
+ }
+ }
+ }
+
+ aBmp.ReleaseAccess( pBmp );
+ aBmpAlphaMask.ReleaseAccess( pBmpAlphaMask );
+ aGrey.ReleaseAccess( pGrey );
+ aGreyAlphaMask.ReleaseAccess( pGreyAlphaMask );
+
+ maDisabledBmpEx = BitmapEx( aGrey, aGreyAlphaMask );
+}
diff --git a/vcl/source/gdi/impimagetree.cxx b/vcl/source/gdi/impimagetree.cxx
new file mode 100644
index 000000000000..03e4c1dbbb2a
--- /dev/null
+++ b/vcl/source/gdi/impimagetree.cxx
@@ -0,0 +1,352 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ***********************************************************************/
+
+#include "precompiled_vcl.hxx"
+#include "sal/config.h"
+
+#include <list>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <hash_map>
+
+#include "com/sun/star/container/XNameAccess.hpp"
+#include "com/sun/star/io/XInputStream.hpp"
+#include "com/sun/star/lang/Locale.hpp"
+#include "com/sun/star/uno/Any.hxx"
+#include "com/sun/star/uno/Exception.hpp"
+#include "com/sun/star/uno/Reference.hxx"
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include "com/sun/star/uno/Sequence.hxx"
+#include "comphelper/processfactory.hxx"
+#include "osl/file.hxx"
+#include "osl/diagnose.h"
+#include "rtl/bootstrap.hxx"
+#include "rtl/string.h"
+#include "rtl/textenc.h"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/ustring.h"
+#include "rtl/ustring.hxx"
+#include "sal/types.h"
+#include "tools/stream.hxx"
+#include "tools/urlobj.hxx"
+#include "vcl/bitmapex.hxx"
+#include "vcl/impimagetree.hxx"
+#include "vcl/pngread.hxx"
+#include "vcl/settings.hxx"
+#include "vcl/svapp.hxx"
+
+namespace {
+
+namespace css = com::sun::star;
+
+rtl::OUString createPath(
+ rtl::OUString const & name, sal_Int32 pos, rtl::OUString const & locale)
+{
+ rtl::OUStringBuffer b(name.copy(0, pos + 1));
+ b.append(locale);
+ b.append(name.copy(pos));
+ return b.makeStringAndClear();
+}
+
+std::auto_ptr< SvStream > wrapStream(
+ css::uno::Reference< css::io::XInputStream > const & stream)
+{
+ // This could use SvInputStream instead if that did not have a broken
+ // SeekPos implementation for an XInputStream that is not also XSeekable
+ // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
+ // l. 593):
+ OSL_ASSERT(stream.is());
+ std::auto_ptr< SvStream > s(new SvMemoryStream);
+ for (;;) {
+ css::uno::Sequence< sal_Int8 > data;
+ sal_Int32 const size = 30000;
+ sal_Int32 n = stream->readBytes(data, size);
+ s->Write(data.getConstArray(), n);
+ if (n < size) {
+ break;
+ }
+ }
+ s->Seek(0);
+ return s;
+}
+
+void loadFromStream(
+ css::uno::Reference< css::io::XInputStream > const & stream,
+ rtl::OUString const & path, BitmapEx & bitmap)
+{
+ std::auto_ptr< SvStream > s(wrapStream(stream));
+ if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png")))
+ {
+ vcl::PNGReader aPNGReader( *s );
+ aPNGReader.SetIgnoreGammaChunk( sal_True );
+ bitmap = aPNGReader.Read();
+ } else {
+ *s >> bitmap;
+ }
+}
+
+}
+
+ImplImageTree::ImplImageTree() {}
+
+ImplImageTree::~ImplImageTree() {}
+
+bool ImplImageTree::checkStyle(rtl::OUString const & style)
+{
+ bool exists;
+
+ // using cache because setStyle is an expensive operation
+ // setStyle calls resetZips => closes any opened zip files with icons, cleans the icon cache, ...
+ if (checkStyleCacheLookup(style, exists)) {
+ return exists;
+ }
+
+ setStyle(style);
+
+ exists = false;
+ const rtl::OUString sBrandURLSuffix(RTL_CONSTASCII_USTRINGPARAM("_brand.zip"));
+ for (Zips::iterator i(m_zips.begin()); i != m_zips.end() && !exists;) {
+ ::rtl::OUString aZipURL = i->first;
+ sal_Int32 nFromIndex = aZipURL.getLength() - sBrandURLSuffix.getLength();
+ // skip brand-specific icon themes; they are incomplete and thus not useful for this check
+ if (nFromIndex < 0 || !aZipURL.match(sBrandURLSuffix, nFromIndex)) {
+ osl::File aZip(aZipURL);
+ if (aZip.open(OpenFlag_Read) == ::osl::FileBase::E_None) {
+ aZip.close();
+ exists = true;
+ }
+ }
+ ++i;
+ }
+ m_checkStyleCache[style] = exists;
+ return exists;
+}
+
+bool ImplImageTree::loadImage(
+ rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
+ bool localized)
+{
+ setStyle(style);
+ if (iconCacheLookup(name, localized, bitmap)) {
+ return true;
+ }
+ if (!bitmap.IsEmpty()) {
+ bitmap.SetEmpty();
+ }
+ std::vector< rtl::OUString > paths;
+ paths.push_back(name);
+ if (localized) {
+ sal_Int32 pos = name.lastIndexOf('/');
+ if (pos != -1) {
+ css::lang::Locale const & loc =
+ Application::GetSettings().GetUILocale();
+ paths.push_back(createPath(name, pos, loc.Language));
+ if (loc.Country.getLength() != 0) {
+ rtl::OUStringBuffer b(loc.Language);
+ b.append(sal_Unicode('-'));
+ b.append(loc.Country);
+ rtl::OUString p(createPath(name, pos, b.makeStringAndClear()));
+ paths.push_back(p);
+ if (loc.Variant.getLength() != 0) {
+ b.append(p);
+ b.append(sal_Unicode('-'));
+ b.append(loc.Variant);
+ paths.push_back(
+ createPath(name, pos, b.makeStringAndClear()));
+ }
+ }
+ }
+ }
+ bool found = false;
+ try {
+ found = find(paths, bitmap);
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (css::uno::Exception & e) {
+ OSL_TRACE(
+ "ImplImageTree::loadImage exception \"%s\"",
+ rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ if (found) {
+ m_iconCache[name.intern()] = std::make_pair(localized, bitmap);
+ }
+ return found;
+}
+
+void ImplImageTree::shutDown() {
+ m_style = rtl::OUString();
+ // for safety; empty m_style means "not initialized"
+ m_zips.clear();
+ m_iconCache.clear();
+ m_checkStyleCache.clear();
+}
+
+void ImplImageTree::setStyle(rtl::OUString const & style) {
+ OSL_ASSERT(style.getLength() != 0); // empty m_style means "not initialized"
+ if (style != m_style) {
+ m_style = style;
+ resetZips();
+ m_iconCache.clear();
+ }
+}
+
+void ImplImageTree::resetZips() {
+ m_zips.clear();
+ {
+ rtl::OUString url(
+ RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program/edition/images.zip"));
+ rtl::Bootstrap::expandMacros(url);
+ INetURLObject u(url);
+ OSL_ASSERT(!u.HasError());
+ m_zips.push_back(
+ std::make_pair(
+ u.GetMainURL(INetURLObject::NO_DECODE),
+ css::uno::Reference< css::container::XNameAccess >()));
+ }
+ {
+ rtl::OUString url(
+ RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/share/config"));
+ rtl::Bootstrap::expandMacros(url);
+ INetURLObject u(url);
+ OSL_ASSERT(!u.HasError());
+ rtl::OUStringBuffer b;
+ b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
+ b.append(m_style);
+ b.appendAscii(RTL_CONSTASCII_STRINGPARAM("_brand.zip"));
+ bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
+ OSL_ASSERT(ok); (void) ok;
+ m_zips.push_back(
+ std::make_pair(
+ u.GetMainURL(INetURLObject::NO_DECODE),
+ css::uno::Reference< css::container::XNameAccess >()));
+ }
+ {
+ rtl::OUString url(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "$BRAND_BASE_DIR/share/config/images_brand.zip"));
+ rtl::Bootstrap::expandMacros(url);
+ m_zips.push_back(
+ std::make_pair(
+ url, css::uno::Reference< css::container::XNameAccess >()));
+ }
+ {
+ rtl::OUString url(
+ RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/config"));
+ rtl::Bootstrap::expandMacros(url);
+ INetURLObject u(url);
+ OSL_ASSERT(!u.HasError());
+ rtl::OUStringBuffer b;
+ b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
+ b.append(m_style);
+ b.appendAscii(RTL_CONSTASCII_STRINGPARAM(".zip"));
+ bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
+ OSL_ASSERT(ok); (void) ok;
+ m_zips.push_back(
+ std::make_pair(
+ u.GetMainURL(INetURLObject::NO_DECODE),
+ css::uno::Reference< css::container::XNameAccess >()));
+ }
+ if ( m_style.equals(::rtl::OUString::createFromAscii("default")) )
+ {
+ rtl::OUString url(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "$OOO_BASE_DIR/share/config/images.zip"));
+ rtl::Bootstrap::expandMacros(url);
+ m_zips.push_back(
+ std::make_pair(
+ url, css::uno::Reference< css::container::XNameAccess >()));
+ }
+}
+
+bool ImplImageTree::checkStyleCacheLookup(
+ rtl::OUString const & style, bool &exists)
+{
+ CheckStyleCache::iterator i(m_checkStyleCache.find(style));
+ if (i != m_checkStyleCache.end()) {
+ exists = i->second;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool ImplImageTree::iconCacheLookup(
+ rtl::OUString const & name, bool localized, BitmapEx & bitmap)
+{
+ IconCache::iterator i(m_iconCache.find(name));
+ if (i != m_iconCache.end() && i->second.first == localized) {
+ bitmap = i->second.second;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool ImplImageTree::find(
+ std::vector< rtl::OUString > const & paths, BitmapEx & bitmap)
+{
+ for (Zips::iterator i(m_zips.begin()); i != m_zips.end();) {
+ if (!i->second.is()) {
+ css::uno::Sequence< css::uno::Any > args(1);
+ args[0] <<= i->first;
+ try {
+ i->second.set(
+ comphelper::createProcessComponentWithArguments(
+ rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.packages.zip.ZipFileAccess")),
+ args),
+ css::uno::UNO_QUERY_THROW);
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (css::uno::Exception & e) {
+ OSL_TRACE(
+ "ImplImageTree::find exception \"%s\"",
+ rtl::OUStringToOString(
+ e.Message, RTL_TEXTENCODING_UTF8).getStr());
+ i = m_zips.erase(i);
+ continue;
+ }
+ }
+ for (std::vector< rtl::OUString >::const_reverse_iterator j(
+ paths.rbegin());
+ j != paths.rend(); ++j)
+ {
+ if (i->second->hasByName(*j)) {
+ css::uno::Reference< css::io::XInputStream > s;
+ bool ok = i->second->getByName(*j) >>= s;
+ OSL_ASSERT(ok); (void) ok;
+ loadFromStream(s, *j, bitmap);
+ return true;
+ }
+ }
+ ++i;
+ }
+ return false;
+}
diff --git a/vcl/source/gdi/impprn.cxx b/vcl/source/gdi/impprn.cxx
new file mode 100644
index 000000000000..5224286cdad1
--- /dev/null
+++ b/vcl/source/gdi/impprn.cxx
@@ -0,0 +1,584 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define _SPOOLPRINTER_EXT
+#include "tools/queue.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/metaact.hxx"
+#include "vcl/gdimtf.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/impprn.hxx"
+#include "vcl/jobset.h"
+
+#include "vcl/svdata.hxx"
+#include "vcl/salprn.hxx"
+
+// -----------
+// - Defines -
+// -----------
+
+#define OPTIMAL_BMP_RESOLUTION 300
+#define NORMAL_BMP_RESOLUTION 200
+
+// =======================================================================
+
+struct QueuePage
+{
+ GDIMetaFile* mpMtf;
+ JobSetup* mpSetup;
+ USHORT mnPage;
+ BOOL mbEndJob;
+
+ QueuePage() { mpMtf = NULL; mpSetup = NULL; }
+ ~QueuePage() { delete mpMtf; if ( mpSetup ) delete mpSetup; }
+};
+
+// =======================================================================
+
+ImplQPrinter::ImplQPrinter( Printer* pParent ) :
+ Printer( pParent->GetName() ),
+ mpParent( pParent ),
+ mbAborted( false ),
+ mbUserCopy( false ),
+ mbDestroyAllowed( true ),
+ mbDestroyed( false ),
+ mnMaxBmpDPIX( mnDPIX ),
+ mnMaxBmpDPIY( mnDPIY ),
+ mnCurCopyCount( 0 )
+{
+ SetSelfAsQueuePrinter( TRUE );
+ SetPrinterProps( pParent );
+ SetPageQueueSize( 0 );
+ mnCopyCount = pParent->mnCopyCount;
+ mbCollateCopy = pParent->mbCollateCopy;
+}
+
+// -----------------------------------------------------------------------
+
+ImplQPrinter::~ImplQPrinter()
+{
+ for( std::vector< QueuePage* >::iterator it = maQueue.begin();
+ it != maQueue.end(); ++it )
+ delete (*it);
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplQPrinter::Destroy()
+{
+ if( mbDestroyAllowed )
+ delete this;
+ else
+ mbDestroyed = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplQPrinter::ImplPrintMtf( GDIMetaFile& rPrtMtf, long nMaxBmpDPIX, long nMaxBmpDPIY )
+{
+ for( MetaAction* pAct = rPrtMtf.FirstAction(); pAct && !mbAborted; pAct = rPrtMtf.NextAction() )
+ {
+ const ULONG nType = pAct->GetType();
+ sal_Bool bExecuted = sal_False;
+
+ if( nType == META_COMMENT_ACTION )
+ {
+ // search for special comments ( ..._BEGIN/..._END )
+ MetaCommentAction* pComment = (MetaCommentAction*) pAct;
+
+ if( pComment->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL )
+ {
+ pAct = rPrtMtf.NextAction();
+
+ // if next action is a GradientEx action, execute this and
+ // skip actions until a XGRAD_SEQ_END comment is found
+ if( pAct && ( pAct->GetType() == META_GRADIENTEX_ACTION ) )
+ {
+ MetaGradientExAction* pGradientExAction = (MetaGradientExAction*) pAct;
+ DrawGradientEx( this, pGradientExAction->GetPolyPolygon(), pGradientExAction->GetGradient() );
+
+ // seek to end of this comment
+ do
+ {
+ pAct = rPrtMtf.NextAction();
+ }
+ while( pAct &&
+ ( ( pAct->GetType() != META_COMMENT_ACTION ) ||
+ ( ( (MetaCommentAction*) pAct )->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) != COMPARE_EQUAL ) ) );
+
+ bExecuted = sal_True;
+ }
+ }
+ else if( pComment->GetComment().CompareIgnoreCaseToAscii( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) == COMPARE_EQUAL )
+ {
+ pAct = rPrtMtf.NextAction();
+
+ if( pAct && ( pAct->GetType() == META_BMPSCALE_ACTION ) )
+ {
+ // execute action here to avoid DPI processing of bitmap;
+ pAct->Execute( this );
+
+#ifdef VERBOSE_DEBUG
+ Push();
+ SetLineColor(COL_RED);
+ SetFillColor();
+ DrawRect( Rectangle(
+ static_cast<MetaBmpScaleAction*>(pAct)->GetPoint(),
+ static_cast<MetaBmpScaleAction*>(pAct)->GetSize()) );
+ Pop();
+#endif
+
+ // seek to end of this comment
+ do
+ {
+ pAct = rPrtMtf.NextAction();
+ }
+ while( pAct &&
+ ( ( pAct->GetType() != META_COMMENT_ACTION ) ||
+ ( ( (MetaCommentAction*) pAct )->GetComment().CompareIgnoreCaseToAscii( "PRNSPOOL_TRANSPARENTBITMAP_END" ) != COMPARE_EQUAL ) ) );
+
+ bExecuted = sal_True;
+ }
+ }
+ }
+ else if( nType == META_GRADIENT_ACTION )
+ {
+ MetaGradientAction* pGradientAction = (MetaGradientAction*) pAct;
+ DrawGradientEx( this, pGradientAction->GetRect(), pGradientAction->GetGradient() );
+ bExecuted = sal_True;
+ }
+ else if( nType == META_BMPSCALE_ACTION )
+ {
+ MetaBmpScaleAction* pBmpScaleAction = (MetaBmpScaleAction*) pAct;
+ const Bitmap& rBmp = pBmpScaleAction->GetBitmap();
+
+ DrawBitmap( pBmpScaleAction->GetPoint(), pBmpScaleAction->GetSize(),
+ GetDownsampledBitmap( pBmpScaleAction->GetSize(),
+ Point(), rBmp.GetSizePixel(),
+ rBmp, nMaxBmpDPIX, nMaxBmpDPIY ) );
+
+ bExecuted = sal_True;
+ }
+ else if( nType == META_BMPSCALEPART_ACTION )
+ {
+ MetaBmpScalePartAction* pBmpScalePartAction = (MetaBmpScalePartAction*) pAct;
+ const Bitmap& rBmp = pBmpScalePartAction->GetBitmap();
+
+ DrawBitmap( pBmpScalePartAction->GetDestPoint(), pBmpScalePartAction->GetDestSize(),
+ GetDownsampledBitmap( pBmpScalePartAction->GetDestSize(),
+ pBmpScalePartAction->GetSrcPoint(), pBmpScalePartAction->GetSrcSize(),
+ rBmp, nMaxBmpDPIX, nMaxBmpDPIY ) );
+
+ bExecuted = sal_True;
+ }
+ else if( nType == META_BMPEXSCALE_ACTION )
+ {
+ MetaBmpExScaleAction* pBmpExScaleAction = (MetaBmpExScaleAction*) pAct;
+ const BitmapEx& rBmpEx = pBmpExScaleAction->GetBitmapEx();
+
+ DrawBitmapEx( pBmpExScaleAction->GetPoint(), pBmpExScaleAction->GetSize(),
+ GetDownsampledBitmapEx( pBmpExScaleAction->GetSize(),
+ Point(), rBmpEx.GetSizePixel(),
+ rBmpEx, nMaxBmpDPIX, nMaxBmpDPIY ) );
+
+ bExecuted = sal_True;
+ }
+ else if( nType == META_BMPEXSCALEPART_ACTION )
+ {
+ MetaBmpExScalePartAction* pBmpExScalePartAction = (MetaBmpExScalePartAction*) pAct;
+ const BitmapEx& rBmpEx = pBmpExScalePartAction->GetBitmapEx();
+
+ DrawBitmapEx( pBmpExScalePartAction->GetDestPoint(), pBmpExScalePartAction->GetDestSize(),
+ GetDownsampledBitmapEx( pBmpExScalePartAction->GetDestSize(),
+ pBmpExScalePartAction->GetSrcPoint(), pBmpExScalePartAction->GetSrcSize(),
+ rBmpEx, nMaxBmpDPIX, nMaxBmpDPIY ) );
+
+ bExecuted = sal_True;
+ }
+ else if( nType == META_TRANSPARENT_ACTION )
+ {
+ MetaTransparentAction* pTransAct = static_cast<MetaTransparentAction*>(pAct);
+ USHORT nTransparency( pTransAct->GetTransparence() );
+
+ // #i10613# Respect transparency for draw color
+ if( nTransparency )
+ {
+ Push( PUSH_LINECOLOR|PUSH_FILLCOLOR );
+
+ // assume white background for alpha blending
+ Color aLineColor( GetLineColor() );
+ aLineColor.SetRed( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetRed()) / 100L ) );
+ aLineColor.SetGreen( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetGreen()) / 100L ) );
+ aLineColor.SetBlue( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetBlue()) / 100L ) );
+ SetLineColor( aLineColor );
+
+ Color aFillColor( GetFillColor() );
+ aFillColor.SetRed( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetRed()) / 100L ) );
+ aFillColor.SetGreen( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetGreen()) / 100L ) );
+ aFillColor.SetBlue( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetBlue()) / 100L ) );
+ SetFillColor( aFillColor );
+ }
+
+ DrawPolyPolygon( pTransAct->GetPolyPolygon() );
+
+ if( nTransparency )
+ Pop();
+
+ bExecuted = sal_True;
+ }
+ else if( nType == META_FLOATTRANSPARENT_ACTION )
+ {
+ MetaFloatTransparentAction* pFloatAction = (MetaFloatTransparentAction*) pAct;
+ GDIMetaFile& rMtf = (GDIMetaFile&) pFloatAction->GetGDIMetaFile();
+ MapMode aDrawMap( rMtf.GetPrefMapMode() );
+ Point aDestPoint( LogicToPixel( pFloatAction->GetPoint() ) );
+ Size aDestSize( LogicToPixel( pFloatAction->GetSize() ) );
+
+ if( aDestSize.Width() && aDestSize.Height() )
+ {
+ Size aTmpPrefSize( LogicToPixel( rMtf.GetPrefSize(), aDrawMap ) );
+
+ if( !aTmpPrefSize.Width() )
+ aTmpPrefSize.Width() = aDestSize.Width();
+
+ if( !aTmpPrefSize.Height() )
+ aTmpPrefSize.Height() = aDestSize.Height();
+
+ Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() );
+ Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() );
+
+ aDrawMap.SetScaleX( aScaleX *= aDrawMap.GetScaleX() );
+ aDrawMap.SetScaleY( aScaleY *= aDrawMap.GetScaleY() );
+ aDrawMap.SetOrigin( PixelToLogic( aDestPoint, aDrawMap ) );
+
+ Push();
+ SetMapMode( aDrawMap );
+ ImplPrintMtf( rMtf, nMaxBmpDPIX, nMaxBmpDPIY );
+ Pop();
+ }
+
+ bExecuted = sal_True;
+ }
+
+ if( !bExecuted && pAct )
+ pAct->Execute( this );
+
+ if( ! ImplGetSVData()->maGDIData.mbPrinterPullModel )
+ Application::Reschedule();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplQPrinter::PrePrintPage( QueuePage* pPage )
+{
+ mnRestoreDrawMode = GetDrawMode();
+ mnMaxBmpDPIX = mnDPIX;
+ mnMaxBmpDPIY = mnDPIY;
+
+ const PrinterOptions& rPrinterOptions = GetPrinterOptions();
+
+ if( rPrinterOptions.IsReduceBitmaps() )
+ {
+ // calculate maximum resolution for bitmap graphics
+ if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() )
+ {
+ mnMaxBmpDPIX = Min( (long) OPTIMAL_BMP_RESOLUTION, mnMaxBmpDPIX );
+ mnMaxBmpDPIY = Min( (long) OPTIMAL_BMP_RESOLUTION, mnMaxBmpDPIY );
+ }
+ else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() )
+ {
+ mnMaxBmpDPIX = Min( (long) NORMAL_BMP_RESOLUTION, mnMaxBmpDPIX );
+ mnMaxBmpDPIY = Min( (long) NORMAL_BMP_RESOLUTION, mnMaxBmpDPIY );
+ }
+ else
+ {
+ mnMaxBmpDPIX = Min( (long) rPrinterOptions.GetReducedBitmapResolution(), mnMaxBmpDPIX );
+ mnMaxBmpDPIY = Min( (long) rPrinterOptions.GetReducedBitmapResolution(), mnMaxBmpDPIY );
+ }
+ }
+
+ // convert to greysacles
+ if( rPrinterOptions.IsConvertToGreyscales() )
+ {
+ SetDrawMode( GetDrawMode() | ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT |
+ DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) );
+ }
+
+ // disable transparency output
+ if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
+ {
+ SetDrawMode( GetDrawMode() | DRAWMODE_NOTRANSPARENCY );
+ }
+
+ maCurPageMetaFile = GDIMetaFile();
+ RemoveTransparenciesFromMetaFile( *pPage->mpMtf, maCurPageMetaFile, mnMaxBmpDPIX, mnMaxBmpDPIY,
+ rPrinterOptions.IsReduceTransparency(),
+ rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO,
+ rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency()
+ );
+}
+
+void ImplQPrinter::PostPrintPage()
+{
+ SetDrawMode( mnRestoreDrawMode );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplQPrinter::PrintPage( unsigned int nPage )
+{
+ if( nPage >= maQueue.size() )
+ return;
+ mnCurCopyCount = (mbUserCopy && !mbCollateCopy) ? mnCopyCount : 1;
+ QueuePage* pActPage = maQueue[nPage];
+ PrePrintPage( pActPage );
+ if ( pActPage->mpSetup )
+ SetJobSetup( *pActPage->mpSetup );
+
+ StartPage();
+ ImplPrintMtf( maCurPageMetaFile, mnMaxBmpDPIX, mnMaxBmpDPIY );
+ EndPage();
+
+ mnCurCopyCount--;
+ if( mnCurCopyCount == 0 )
+ PostPrintPage();
+}
+
+// -----------------------------------------------------------------------
+
+ImplJobSetup* ImplQPrinter::GetPageSetup( unsigned int nPage ) const
+{
+ return nPage >= maQueue.size() ? NULL :
+ ( maQueue[nPage]->mpSetup ? maQueue[nPage]->mpSetup->ImplGetData() : NULL );
+}
+
+// -----------------------------------------------------------------------
+ULONG ImplQPrinter::GetPrintPageCount() const
+{
+ ULONG nPageCount = maQueue.size() * ((mbUserCopy && !mbCollateCopy) ? mnCopyCount : 1);
+ return nPageCount;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplQPrinter, ImplPrintHdl, Timer*, EMPTYARG )
+{
+ // Ist Drucken abgebrochen wurden?
+ if( !IsPrinting() || ( mpParent->IsJobActive() && ( maQueue.size() < (ULONG)mpParent->GetPageQueueSize() ) ) )
+ return 0;
+
+ // Druck-Job zuende?
+ QueuePage* pActPage = maQueue.front();
+ maQueue.erase( maQueue.begin() );
+
+
+ vcl::DeletionListener aDel( this );
+ if ( pActPage->mbEndJob )
+ {
+ maTimer.Stop();
+ delete pActPage;
+ if( ! EndJob() )
+ mpParent->Error();
+ if( ! aDel.isDeleted() )
+ mpParent->ImplEndPrint();
+ }
+ else
+ {
+ mbDestroyAllowed = FALSE;
+
+ PrePrintPage( pActPage );
+
+ USHORT nCopyCount = 1;
+ if( mbUserCopy && !mbCollateCopy )
+ nCopyCount = mnCopyCount;
+
+ for ( USHORT i = 0; i < nCopyCount; i++ )
+ {
+ if ( pActPage->mpSetup )
+ {
+ SetJobSetup( *pActPage->mpSetup );
+ if ( mbAborted )
+ break;
+ }
+
+ StartPage();
+
+ if ( mbAborted )
+ break;
+
+ ImplPrintMtf( maCurPageMetaFile, mnMaxBmpDPIX, mnMaxBmpDPIY );
+
+ if( !mbAborted )
+ EndPage();
+ else
+ break;
+ }
+
+ PostPrintPage();
+
+ delete pActPage;
+ mbDestroyAllowed = TRUE;
+
+ if( mbDestroyed )
+ Destroy();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplQPrinter::StartQueuePrint()
+{
+ if( ! ImplGetSVData()->maGDIData.mbPrinterPullModel )
+ {
+ maTimer.SetTimeout( 50 );
+ maTimer.SetTimeoutHdl( LINK( this, ImplQPrinter, ImplPrintHdl ) );
+ maTimer.Start();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplQPrinter::EndQueuePrint()
+{
+ if( ImplGetSVData()->maGDIData.mbPrinterPullModel )
+ {
+ DBG_ASSERT( mpPrinter, "no SalPrinter in ImplQPrinter" );
+ if( mpPrinter )
+ {
+ #if 0
+ mpPrinter->StartJob( mbPrintFile ? &maPrintFile : NULL,
+ Application::GetDisplayName(),
+ maJobSetup.ImplGetConstData(),
+ this );
+ #endif
+ EndJob();
+ mpParent->ImplEndPrint();
+ }
+ }
+ else
+ {
+ QueuePage* pQueuePage = new QueuePage;
+ pQueuePage->mbEndJob = TRUE;
+ maQueue.push_back( pQueuePage );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplQPrinter::GetPaperRanges( std::vector< ULONG >& o_rRanges, bool i_bIncludeOrientationChanges ) const
+{
+ bool bRet = false;
+
+ if( ImplGetSVData()->maGDIData.mbPrinterPullModel )
+ {
+ bRet = true;
+ o_rRanges.clear();
+
+ if( ! maQueue.empty() )
+ {
+ ULONG nCurPage = 0;
+
+ // get first job data
+ const ImplJobSetup* pLastFormat = NULL;
+ if( maQueue.front()->mpSetup )
+ pLastFormat = maQueue.front()->mpSetup->ImplGetConstData();
+
+ // begin first range
+ o_rRanges.push_back( 0 );
+ for( std::vector< QueuePage* >::const_iterator it = maQueue.begin();
+ it != maQueue.end(); ++it, ++nCurPage )
+ {
+ const ImplJobSetup* pNewSetup = (*it)->mpSetup ? (*it)->mpSetup->ImplGetConstData() : NULL;
+ if( pNewSetup && pNewSetup != pLastFormat )
+ {
+ bool bChange = false;
+ if( pLastFormat == NULL )
+ {
+ bChange = true;
+ }
+ else if( ! i_bIncludeOrientationChanges &&
+ pNewSetup->meOrientation != pLastFormat->meOrientation )
+ {
+ bChange = true;
+ }
+ else if( pNewSetup->mePaperFormat != pLastFormat->mePaperFormat ||
+ ( pNewSetup->mePaperFormat == PAPER_USER &&
+ ( pNewSetup->mnPaperWidth != pLastFormat->mnPaperWidth ||
+ pNewSetup->mnPaperHeight != pLastFormat->mnPaperHeight ) ) )
+ {
+ bChange = true;
+ }
+ else if( pNewSetup->mnPaperBin != pLastFormat->mnPaperBin )
+ {
+ bChange = true;
+ }
+ if( bChange )
+ {
+ o_rRanges.push_back( nCurPage );
+ pLastFormat = pNewSetup;
+ }
+ }
+ }
+
+ o_rRanges.push_back( nCurPage );
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplQPrinter::AbortQueuePrint()
+{
+ maTimer.Stop();
+ mbAborted = TRUE;
+ AbortJob();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplQPrinter::AddQueuePage( GDIMetaFile* pPage, USHORT nPage, BOOL bNewJobSetup )
+{
+ QueuePage* pQueuePage = new QueuePage;
+ pQueuePage->mpMtf = pPage;
+ pQueuePage->mnPage = nPage;
+ pQueuePage->mbEndJob = FALSE;
+ // ensure that the first page has a valid setup, this is needed
+ // in GetPaperRanges (used in pullmodel)
+ // caution: this depends on mnCurPage in Printer being
+ // 0: not printing 1: after StartJob, 2 after first EndPage, 3+ at following EndPage calls
+ if ( bNewJobSetup || (nPage == 2 && ImplGetSVData()->maGDIData.mbPrinterPullModel) )
+ pQueuePage->mpSetup = new JobSetup( mpParent->GetJobSetup() );
+ maQueue.push_back( pQueuePage );
+}
diff --git a/vcl/source/gdi/impvect.cxx b/vcl/source/gdi/impvect.cxx
new file mode 100644
index 000000000000..0846f5567200
--- /dev/null
+++ b/vcl/source/gdi/impvect.cxx
@@ -0,0 +1,1204 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdlib.h>
+#include <vcl/bmpacc.hxx>
+#include <tools/poly.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/virdev.hxx>
+#ifndef _SV_VECTORIZ_HXX
+#include <impvect.hxx>
+#endif
+
+// -----------
+// - Defines -
+// -----------
+
+#define VECT_POLY_MAX 8192
+
+// -----------------------------------------------------------------------------
+
+#define VECT_FREE_INDEX 0
+#define VECT_CONT_INDEX 1
+#define VECT_DONE_INDEX 2
+
+// -----------------------------------------------------------------------------
+
+#define VECT_POLY_INLINE_INNER 1UL
+#define VECT_POLY_INLINE_OUTER 2UL
+#define VECT_POLY_OUTLINE_INNER 4UL
+#define VECT_POLY_OUTLINE_OUTER 8UL
+
+// -----------------------------------------------------------------------------
+
+#define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4L)+1L)+5L;
+#define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1)
+#define VECT_PROGRESS( _def_pProgress, _def_nVal ) if(_def_pProgress&&_def_pProgress->IsSet())(_def_pProgress->Call((void*)_def_nVal));
+
+// -----------
+// - statics -
+// -----------
+
+struct ChainMove { long nDX; long nDY; };
+
+static ChainMove aImplMove[ 8 ] = {
+ { 1L, 0L },
+ { 0L, -1L },
+ { -1L, 0L },
+ { 0L, 1L },
+ { 1L, -1L },
+ { -1, -1L },
+ { -1L, 1L },
+ { 1L, 1L }
+ };
+
+static ChainMove aImplMoveInner[ 8 ] = {
+ { 0L, 1L },
+ { 1L, 0L },
+ { 0L, -1L },
+ { -1L, 0L },
+ { 0L, 1L },
+ { 1L, 0L },
+ { 0L, -1L },
+ { -1L, 0L }
+ };
+
+static ChainMove aImplMoveOuter[ 8 ] = {
+ { 0L, -1L },
+ { -1L, 0L },
+ { 0L, 1L },
+ { 1L, 0L },
+ { -1L, 0L },
+ { 0L, 1L },
+ { 1L, 0L },
+ { 0L, -1L }
+ };
+
+// ----------------
+// - ImplColorSet -
+// ----------------
+
+struct ImplColorSet
+{
+ BitmapColor maColor;
+ USHORT mnIndex;
+ BOOL mbSet;
+
+ BOOL operator<( const ImplColorSet& rSet ) const;
+ BOOL operator>( const ImplColorSet& rSet ) const;
+};
+
+// ----------------------------------------------------------------------------
+
+inline BOOL ImplColorSet::operator<( const ImplColorSet& rSet ) const
+{
+ return( mbSet && ( !rSet.mbSet || ( maColor.GetLuminance() > rSet.maColor.GetLuminance() ) ) );
+}
+
+// ----------------------------------------------------------------------------
+
+inline BOOL ImplColorSet::operator>( const ImplColorSet& rSet ) const
+{
+ return( !mbSet || ( rSet.mbSet && maColor.GetLuminance() < rSet.maColor.GetLuminance() ) );
+}
+
+// ----------------------------------------------------------------------------
+
+extern "C" int __LOADONCALLAPI ImplColorSetCmpFnc( const void* p1, const void* p2 )
+{
+ ImplColorSet* pSet1 = (ImplColorSet*) p1;
+ ImplColorSet* pSet2 = (ImplColorSet*) p2;
+ int nRet;
+
+ if( pSet1->mbSet && pSet2->mbSet )
+ {
+ const BYTE cLum1 = pSet1->maColor.GetLuminance();
+ const BYTE cLum2 = pSet2->maColor.GetLuminance();
+ nRet = ( ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 ) );
+ }
+ else if( pSet1->mbSet )
+ nRet = -1;
+ else if( pSet2->mbSet )
+ nRet = 1;
+ else
+ nRet = 0;
+
+ return nRet;
+}
+
+// ------------------
+// - ImplPointArray -
+// ------------------
+
+class ImplPointArray
+{
+ Point* mpArray;
+ ULONG mnSize;
+ ULONG mnRealSize;
+
+public:
+
+ ImplPointArray();
+ ~ImplPointArray();
+
+ void ImplSetSize( ULONG nSize );
+
+ ULONG ImplGetRealSize() const { return mnRealSize; }
+ void ImplSetRealSize( ULONG nRealSize ) { mnRealSize = nRealSize; }
+
+ inline Point& operator[]( ULONG nPos );
+ inline const Point& operator[]( ULONG nPos ) const;
+
+ void ImplCreatePoly( Polygon& rPoly ) const;
+};
+
+// -----------------------------------------------------------------------------
+
+ImplPointArray::ImplPointArray() :
+ mpArray ( NULL ),
+ mnSize ( 0UL ),
+ mnRealSize ( 0UL )
+
+{
+}
+
+// -----------------------------------------------------------------------------
+
+ImplPointArray::~ImplPointArray()
+{
+ if( mpArray )
+ rtl_freeMemory( mpArray );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplPointArray::ImplSetSize( ULONG nSize )
+{
+ const ULONG nTotal = nSize * sizeof( Point );
+
+ mnSize = nSize;
+ mnRealSize = 0UL;
+
+ if( mpArray )
+ rtl_freeMemory( mpArray );
+
+ mpArray = (Point*) rtl_allocateMemory( nTotal );
+ memset( (HPBYTE) mpArray, 0, nTotal );
+}
+
+// -----------------------------------------------------------------------------
+
+inline Point& ImplPointArray::operator[]( ULONG nPos )
+{
+ DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" );
+ return mpArray[ nPos ];
+}
+
+// -----------------------------------------------------------------------------
+
+inline const Point& ImplPointArray::operator[]( ULONG nPos ) const
+{
+ DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" );
+ return mpArray[ nPos ];
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplPointArray::ImplCreatePoly( Polygon& rPoly ) const
+{
+ rPoly = Polygon( sal::static_int_cast<USHORT>(mnRealSize), mpArray );
+}
+
+// ---------------
+// - ImplVectMap -
+// ---------------
+
+class ImplVectMap
+{
+private:
+
+ Scanline mpBuf;
+ Scanline* mpScan;
+ long mnWidth;
+ long mnHeight;
+
+ ImplVectMap() {};
+
+public:
+
+ ImplVectMap( long nWidth, long nHeight );
+ ~ImplVectMap();
+
+ inline long Width() const { return mnWidth; }
+ inline long Height() const { return mnHeight; }
+
+ inline void Set( long nY, long nX, BYTE cVal );
+ inline BYTE Get( long nY, long nX ) const;
+
+ inline BOOL IsFree( long nY, long nX ) const;
+ inline BOOL IsCont( long nY, long nX ) const;
+ inline BOOL IsDone( long nY, long nX ) const;
+
+};
+
+// -----------------------------------------------------------------------------
+
+ImplVectMap::ImplVectMap( long nWidth, long nHeight ) :
+ mnWidth ( nWidth ),
+ mnHeight( nHeight )
+{
+ const long nWidthAl = ( nWidth >> 2L ) + 1L;
+ const long nSize = nWidthAl * nHeight;
+ Scanline pTmp = mpBuf = (Scanline) rtl_allocateMemory( nSize );
+
+ memset( mpBuf, 0, nSize );
+ mpScan = (Scanline*) rtl_allocateMemory( nHeight * sizeof( Scanline ) );
+
+ for( long nY = 0L; nY < nHeight; pTmp += nWidthAl )
+ mpScan[ nY++ ] = pTmp;
+}
+
+// -----------------------------------------------------------------------------
+
+
+ImplVectMap::~ImplVectMap()
+{
+ rtl_freeMemory( mpBuf );
+ rtl_freeMemory( mpScan );
+}
+
+// -----------------------------------------------------------------------------
+
+inline void ImplVectMap::Set( long nY, long nX, BYTE cVal )
+{
+ const BYTE cShift = sal::static_int_cast<BYTE>(6 - ( ( nX & 3 ) << 1 ));
+ ( ( mpScan[ nY ][ nX >> 2 ] ) &= ~( 3 << cShift ) ) |= ( cVal << cShift );
+}
+
+// -----------------------------------------------------------------------------
+
+inline BYTE ImplVectMap::Get( long nY, long nX ) const
+{
+ return sal::static_int_cast<BYTE>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 );
+}
+
+// -----------------------------------------------------------------------------
+
+inline BOOL ImplVectMap::IsFree( long nY, long nX ) const
+{
+ return( VECT_FREE_INDEX == Get( nY, nX ) );
+}
+
+// -----------------------------------------------------------------------------
+
+inline BOOL ImplVectMap::IsCont( long nY, long nX ) const
+{
+ return( VECT_CONT_INDEX == Get( nY, nX ) );
+}
+
+// -----------------------------------------------------------------------------
+
+inline BOOL ImplVectMap::IsDone( long nY, long nX ) const
+{
+ return( VECT_DONE_INDEX == Get( nY, nX ) );
+}
+
+// -------------
+// - ImplChain -
+// -------------
+
+class ImplChain
+{
+private:
+
+ Polygon maPoly;
+ Point maStartPt;
+ ULONG mnArraySize;
+ ULONG mnCount;
+ long mnResize;
+ BYTE* mpCodes;
+
+ void ImplGetSpace();
+
+ void ImplCreate();
+ void ImplCreateInner();
+ void ImplCreateOuter();
+ void ImplPostProcess( const ImplPointArray& rArr );
+
+public:
+
+ ImplChain( ULONG nInitCount = 1024UL, long nResize = -1L );
+ ~ImplChain();
+
+ void ImplBeginAdd( const Point& rStartPt );
+ inline void ImplAdd( BYTE nCode );
+ void ImplEndAdd( ULONG nTypeFlag );
+
+ const Polygon& ImplGetPoly() { return maPoly; }
+};
+
+// -----------------------------------------------------------------------------
+
+ImplChain::ImplChain( ULONG nInitCount, long nResize ) :
+ mnArraySize ( nInitCount ),
+ mnCount ( 0UL ),
+ mnResize ( nResize )
+{
+ DBG_ASSERT( nInitCount && nResize, "ImplChain::ImplChain(): invalid parameters!" );
+ mpCodes = new BYTE[ mnArraySize ];
+}
+
+// -----------------------------------------------------------------------------
+
+ImplChain::~ImplChain()
+{
+ delete[] mpCodes;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplChain::ImplGetSpace()
+{
+ const ULONG nOldArraySize = mnArraySize;
+ BYTE* pNewCodes;
+
+ mnArraySize = ( mnResize < 0L ) ? ( mnArraySize << 1UL ) : ( mnArraySize + (ULONG) mnResize );
+ pNewCodes = new BYTE[ mnArraySize ];
+ memcpy( pNewCodes, mpCodes, nOldArraySize );
+ delete[] mpCodes;
+ mpCodes = pNewCodes;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplChain::ImplBeginAdd( const Point& rStartPt )
+{
+ maPoly = Polygon();
+ maStartPt = rStartPt;
+ mnCount = 0UL;
+}
+
+// -----------------------------------------------------------------------------
+
+inline void ImplChain::ImplAdd( BYTE nCode )
+{
+ if( mnCount == mnArraySize )
+ ImplGetSpace();
+
+ mpCodes[ mnCount++ ] = nCode;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplChain::ImplEndAdd( ULONG nFlag )
+{
+ if( mnCount )
+ {
+ ImplPointArray aArr;
+
+ if( nFlag & VECT_POLY_INLINE_INNER )
+ {
+ long nFirstX, nFirstY;
+ long nLastX, nLastY;
+
+ nFirstX = nLastX = maStartPt.X();
+ nFirstY = nLastY = maStartPt.Y();
+ aArr.ImplSetSize( mnCount << 1 );
+
+ USHORT i, nPolyPos;
+ for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
+ {
+ const BYTE cMove = mpCodes[ i ];
+ const BYTE cNextMove = mpCodes[ i + 1 ];
+ const ChainMove& rMove = aImplMove[ cMove ];
+ const ChainMove& rMoveInner = aImplMoveInner[ cMove ];
+// Point& rPt = aArr[ nPolyPos ];
+ BOOL bDone = TRUE;
+
+ nLastX += rMove.nDX;
+ nLastY += rMove.nDY;
+
+ if( cMove < 4 )
+ {
+ if( ( cMove == 0 && cNextMove == 3 ) ||
+ ( cMove == 3 && cNextMove == 2 ) ||
+ ( cMove == 2 && cNextMove == 1 ) ||
+ ( cMove == 1 && cNextMove == 0 ) )
+ {
+ }
+ else if( cMove == 2 && cNextMove == 3 )
+ {
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+ }
+ else if( cMove == 3 && cNextMove == 0 )
+ {
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+ }
+ else if( cMove == 0 && cNextMove == 1 )
+ {
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+ }
+ else if( cMove == 1 && cNextMove == 2 )
+ {
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+ }
+ else
+ bDone = FALSE;
+ }
+ else if( cMove == 7 && cNextMove == 0 )
+ {
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+ }
+ else if( cMove == 4 && cNextMove == 1 )
+ {
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+ }
+ else
+ bDone = FALSE;
+
+ if( !bDone )
+ {
+ aArr[ nPolyPos ].X() = nLastX + rMoveInner.nDX;
+ aArr[ nPolyPos++ ].Y() = nLastY + rMoveInner.nDY;
+ }
+ }
+
+ aArr[ nPolyPos ].X() = nFirstX + 1L;
+ aArr[ nPolyPos++ ].Y() = nFirstY + 1L;
+ aArr.ImplSetRealSize( nPolyPos );
+ }
+ else if( nFlag & VECT_POLY_INLINE_OUTER )
+ {
+ long nFirstX, nFirstY;
+ long nLastX, nLastY;
+
+ nFirstX = nLastX = maStartPt.X();
+ nFirstY = nLastY = maStartPt.Y();
+ aArr.ImplSetSize( mnCount << 1 );
+
+ USHORT i, nPolyPos;
+ for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
+ {
+ const BYTE cMove = mpCodes[ i ];
+ const BYTE cNextMove = mpCodes[ i + 1 ];
+ const ChainMove& rMove = aImplMove[ cMove ];
+ const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ];
+// Point& rPt = aArr[ nPolyPos ];
+ BOOL bDone = TRUE;
+
+ nLastX += rMove.nDX;
+ nLastY += rMove.nDY;
+
+ if( cMove < 4 )
+ {
+ if( ( cMove == 0 && cNextMove == 1 ) ||
+ ( cMove == 1 && cNextMove == 2 ) ||
+ ( cMove == 2 && cNextMove == 3 ) ||
+ ( cMove == 3 && cNextMove == 0 ) )
+ {
+ }
+ else if( cMove == 0 && cNextMove == 3 )
+ {
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+ }
+ else if( cMove == 3 && cNextMove == 2 )
+ {
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+ }
+ else if( cMove == 2 && cNextMove == 1 )
+ {
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+ }
+ else if( cMove == 1 && cNextMove == 0 )
+ {
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+
+ aArr[ nPolyPos ].X() = nLastX - 1;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+ }
+ else
+ bDone = FALSE;
+ }
+ else if( cMove == 7 && cNextMove == 3 )
+ {
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY - 1;
+
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+ }
+ else if( cMove == 6 && cNextMove == 2 )
+ {
+ aArr[ nPolyPos ].X() = nLastX + 1;
+ aArr[ nPolyPos++ ].Y() = nLastY;
+
+ aArr[ nPolyPos ].X() = nLastX;
+ aArr[ nPolyPos++ ].Y() = nLastY + 1;
+ }
+ else
+ bDone = FALSE;
+
+ if( !bDone )
+ {
+ aArr[ nPolyPos ].X() = nLastX + rMoveOuter.nDX;
+ aArr[ nPolyPos++ ].Y() = nLastY + rMoveOuter.nDY;
+ }
+ }
+
+ aArr[ nPolyPos ].X() = nFirstX - 1L;
+ aArr[ nPolyPos++ ].Y() = nFirstY - 1L;
+ aArr.ImplSetRealSize( nPolyPos );
+ }
+ else
+ {
+ long nLastX = maStartPt.X(), nLastY = maStartPt.Y();
+
+ aArr.ImplSetSize( mnCount + 1 );
+ aArr[ 0 ] = Point( nLastX, nLastY );
+
+ for( ULONG i = 0; i < mnCount; )
+ {
+ const ChainMove& rMove = aImplMove[ mpCodes[ i ] ];
+ aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY );
+ }
+
+ aArr.ImplSetRealSize( mnCount + 1 );
+ }
+
+ ImplPostProcess( aArr );
+ }
+ else
+ maPoly.SetSize( 0 );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplChain::ImplPostProcess( const ImplPointArray& rArr )
+{
+ ImplPointArray aNewArr1;
+ ImplPointArray aNewArr2;
+ Point* pLast;
+ Point* pLeast;
+ ULONG nNewPos;
+ ULONG nCount = rArr.ImplGetRealSize();
+ ULONG n;
+
+ // pass 1
+ aNewArr1.ImplSetSize( nCount );
+ pLast = &( aNewArr1[ 0 ] );
+ pLast->X() = BACK_MAP( rArr[ 0 ].X() );
+ pLast->Y() = BACK_MAP( rArr[ 0 ].Y() );
+
+ for( n = nNewPos = 1; n < nCount; )
+ {
+ const Point& rPt = rArr[ n++ ];
+ const long nX = BACK_MAP( rPt.X() );
+ const long nY = BACK_MAP( rPt.Y() );
+
+ if( nX != pLast->X() || nY != pLast->Y() )
+ {
+ pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
+ pLeast->X() = nX;
+ pLeast->Y() = nY;
+ }
+ }
+
+ aNewArr1.ImplSetRealSize( nCount = nNewPos );
+
+ // pass 2
+ aNewArr2.ImplSetSize( nCount );
+ pLast = &( aNewArr2[ 0 ] );
+ *pLast = aNewArr1[ 0 ];
+
+ for( n = nNewPos = 1; n < nCount; )
+ {
+ pLeast = &( aNewArr1[ n++ ] );
+
+ if( pLeast->X() == pLast->X() )
+ {
+ while( n < nCount && aNewArr1[ n ].X() == pLast->X() )
+ pLeast = &( aNewArr1[ n++ ] );
+ }
+ else if( pLeast->Y() == pLast->Y() )
+ {
+ while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() )
+ pLeast = &( aNewArr1[ n++ ] );
+ }
+
+ aNewArr2[ nNewPos++ ] = *( pLast = pLeast );
+ }
+
+ aNewArr2.ImplSetRealSize( nNewPos );
+ aNewArr2.ImplCreatePoly( maPoly );
+}
+
+// ------------------
+// - ImplVectorizer -
+// ------------------
+
+ImplVectorizer::ImplVectorizer()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+ImplVectorizer::~ImplVectorizer()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL ImplVectorizer::ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
+ BYTE cReduce, ULONG nFlags, const Link* pProgress )
+{
+ BOOL bRet = FALSE;
+
+ VECT_PROGRESS( pProgress, 0 );
+
+ Bitmap* pBmp = new Bitmap( rColorBmp );
+ BitmapReadAccess* pRAcc = pBmp->AcquireReadAccess();
+
+ if( pRAcc )
+ {
+ PolyPolygon aPolyPoly;
+ double fPercent = 0.0;
+ double fPercentStep_2 = 0.0;
+ const long nWidth = pRAcc->Width();
+ const long nHeight = pRAcc->Height();
+ const USHORT nColorCount = pRAcc->GetPaletteEntryCount();
+ USHORT n;
+ ImplColorSet* pColorSet = (ImplColorSet*) new BYTE[ 256 * sizeof( ImplColorSet ) ];
+
+ memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) );
+ rMtf.Clear();
+
+ // get used palette colors and sort them from light to dark colors
+ for( n = 0; n < nColorCount; n++ )
+ {
+ pColorSet[ n ].mnIndex = n;
+ pColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
+ }
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pColorSet[ pRAcc->GetPixel( nY, nX ).GetIndex() ].mbSet = 1;
+
+ qsort( pColorSet, 256, sizeof( ImplColorSet ), ImplColorSetCmpFnc );
+
+ for( n = 0; n < 256; n++ )
+ if( !pColorSet[ n ].mbSet )
+ break;
+
+ if( n )
+ fPercentStep_2 = 45.0 / n;
+
+ VECT_PROGRESS( pProgress, FRound( fPercent += 10.0 ) );
+
+ for( USHORT i = 0; i < n; i++ )
+ {
+ const BitmapColor aBmpCol( pRAcc->GetPaletteColor( pColorSet[ i ].mnIndex ) );
+ const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
+// const BYTE cLum = aFindColor.GetLuminance();
+ ImplVectMap* pMap = ImplExpand( pRAcc, aFindColor );
+
+ VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
+
+ if( pMap )
+ {
+ aPolyPoly.Clear();
+ ImplCalculate( pMap, aPolyPoly, cReduce, nFlags );
+ delete pMap;
+
+ if( aPolyPoly.Count() )
+ {
+ ImplLimitPolyPoly( aPolyPoly );
+
+ if( nFlags & BMP_VECTORIZE_REDUCE_EDGES )
+ aPolyPoly.Optimize( POLY_OPTIMIZE_EDGES );
+
+ if( aPolyPoly.Count() )
+ {
+ rMtf.AddAction( new MetaLineColorAction( aFindColor, TRUE ) );
+ rMtf.AddAction( new MetaFillColorAction( aFindColor, TRUE ) );
+ rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
+ }
+ }
+ }
+
+ VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) );
+ }
+
+ delete[] (BYTE*) pColorSet;
+
+ if( rMtf.GetActionCount() )
+ {
+ MapMode aMap( MAP_100TH_MM );
+ VirtualDevice aVDev;
+ const Size aLogSize1( aVDev.PixelToLogic( Size( 1, 1 ), aMap ) );
+
+ rMtf.SetPrefMapMode( aMap );
+ rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
+ rMtf.Move( 1, 1 );
+ rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
+ bRet = TRUE;
+ }
+ }
+
+ pBmp->ReleaseAccess( pRAcc );
+ delete pBmp;
+ VECT_PROGRESS( pProgress, 100 );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL ImplVectorizer::ImplVectorize( const Bitmap& rMonoBmp,
+ PolyPolygon& rPolyPoly,
+ ULONG nFlags, const Link* pProgress )
+{
+ Bitmap* pBmp = new Bitmap( rMonoBmp );
+ BitmapReadAccess* pRAcc;
+ ImplVectMap* pMap;
+ BOOL bRet = FALSE;
+
+ VECT_PROGRESS( pProgress, 10 );
+
+ if( pBmp->GetBitCount() > 1 )
+ pBmp->Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+
+ VECT_PROGRESS( pProgress, 30 );
+
+ pRAcc = pBmp->AcquireReadAccess();
+ pMap = ImplExpand( pRAcc, COL_BLACK );
+ pBmp->ReleaseAccess( pRAcc );
+ delete pBmp;
+
+ VECT_PROGRESS( pProgress, 60 );
+
+ if( pMap )
+ {
+ rPolyPoly.Clear();
+ ImplCalculate( pMap, rPolyPoly, 0, nFlags );
+ delete pMap;
+ ImplLimitPolyPoly( rPolyPoly );
+
+ if( nFlags & BMP_VECTORIZE_REDUCE_EDGES )
+ rPolyPoly.Optimize( POLY_OPTIMIZE_EDGES );
+
+ // #i14895#:setting the correct direction for polygons
+ // that represent holes and non-holes; non-hole polygons
+ // need to have a right orientation, holes need to have a
+ // left orientation in order to be treated correctly by
+ // several external tools like Flash viewers
+ sal_Int32 nFirstPoly = -1;
+ sal_uInt16 nCurPoly( 0 ), nCount( rPolyPoly.Count() );
+
+ for( ; nCurPoly < nCount; ++nCurPoly )
+ {
+ const Polygon& rPoly = rPolyPoly.GetObject( nCurPoly );
+ const sal_uInt16 nSize( rPoly.GetSize() );
+ sal_uInt16 nDepth( 0 ), i( 0 );
+ const bool bRight( rPoly.IsRightOrientated() );
+
+ for( ; i < nCount; ++i )
+ if( ( i != nCurPoly ) && rPolyPoly.GetObject( i ).IsInside( rPoly[ 0 ] ) )
+ ++nDepth;
+
+ const bool bHole( ( nDepth & 0x0001 ) == 1 );
+
+ if( nSize && ( ( !bRight && !bHole ) || ( bRight && bHole ) ) )
+ {
+ Polygon aNewPoly( nSize );
+ sal_uInt16 nPrim( 0 ), nSec( nSize - 1 );
+
+ if( rPoly.HasFlags() )
+ {
+ while( nPrim < nSize )
+ {
+ aNewPoly.SetPoint( rPoly.GetPoint( nSec ), nPrim );
+ aNewPoly.SetFlags( nPrim++, rPoly.GetFlags( nSec-- ) );
+ }
+ }
+ else
+ while( nPrim < nSize )
+ aNewPoly.SetPoint( rPoly.GetPoint( nSec-- ), nPrim++ );
+
+ rPolyPoly.Replace( aNewPoly, nCurPoly );
+ }
+
+ if( ( 0 == nDepth ) && ( -1 == nFirstPoly ) )
+ nFirstPoly = nCurPoly;
+ }
+
+ // put outmost polygon to the front
+ if( nFirstPoly > 0 )
+ {
+ const Polygon aFirst( rPolyPoly.GetObject( static_cast< USHORT >( nFirstPoly ) ) );
+
+ rPolyPoly.Remove( static_cast< USHORT >( nFirstPoly ) );
+ rPolyPoly.Insert( aFirst, 0 );
+ }
+
+ bRet = TRUE;
+ }
+
+ VECT_PROGRESS( pProgress, 100 );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplVectorizer::ImplLimitPolyPoly( PolyPolygon& rPolyPoly )
+{
+ if( rPolyPoly.Count() > VECT_POLY_MAX )
+ {
+ PolyPolygon aNewPolyPoly;
+ long nReduce = 0;
+ USHORT nNewCount;
+
+ do
+ {
+ aNewPolyPoly.Clear();
+ nReduce++;
+
+ for( USHORT i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
+ {
+ const Rectangle aBound( rPolyPoly[ i ].GetBoundRect() );
+
+ if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce )
+ {
+ if( rPolyPoly[ i ].GetSize() )
+ aNewPolyPoly.Insert( rPolyPoly[ i ] );
+ }
+ }
+
+ nNewCount = aNewPolyPoly.Count();
+ }
+ while( nNewCount > VECT_POLY_MAX );
+
+ rPolyPoly = aNewPolyPoly;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+ImplVectMap* ImplVectorizer::ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor )
+{
+ ImplVectMap* pMap = NULL;
+
+ if( pRAcc && pRAcc->Width() && pRAcc->Height() )
+ {
+ const long nOldWidth = pRAcc->Width();
+ const long nOldHeight = pRAcc->Height();
+ const long nNewWidth = ( nOldWidth << 2L ) + 4L;
+ const long nNewHeight = ( nOldHeight << 2L ) + 4L;
+ const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) );
+ long* pMapIn = new long[ Max( nOldWidth, nOldHeight ) ];
+ long* pMapOut = new long[ Max( nOldWidth, nOldHeight ) ];
+ long nX, nY, nTmpX, nTmpY;
+
+ pMap = new ImplVectMap( nNewWidth, nNewHeight );
+
+ for( nX = 0L; nX < nOldWidth; nX++ )
+ VECT_MAP( pMapIn, pMapOut, nX );
+
+ for( nY = 0L, nTmpY = 5L; nY < nOldHeight; nY++, nTmpY += 4L )
+ {
+ for( nX = 0L; nX < nOldWidth; )
+ {
+ if( pRAcc->GetPixel( nY, nX ) == aTest )
+ {
+ nTmpX = pMapIn[ nX++ ];
+ nTmpY -= 3L;
+
+ pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
+ pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
+ pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
+
+ while( nX < nOldWidth && pRAcc->GetPixel( nY, nX ) == aTest )
+ nX++;
+
+ nTmpX = pMapOut[ nX - 1L ];
+ nTmpY -= 3L;
+
+ pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
+ pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
+ pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
+ }
+ else
+ nX++;
+ }
+ }
+
+ for( nY = 0L; nY < nOldHeight; nY++ )
+ VECT_MAP( pMapIn, pMapOut, nY );
+
+ for( nX = 0L, nTmpX = 5L; nX < nOldWidth; nX++, nTmpX += 4L )
+ {
+ for( nY = 0L; nY < nOldHeight; )
+ {
+ if( pRAcc->GetPixel( nY, nX ) == aTest )
+ {
+ nTmpX -= 3L;
+ nTmpY = pMapIn[ nY++ ];
+
+ pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
+
+ while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
+ nY++;
+
+ nTmpX -= 3L;
+ nTmpY = pMapOut[ nY - 1L ];
+
+ pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
+ pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
+ }
+ else
+ nY++;
+ }
+ }
+
+ // cleanup
+ delete[] pMapIn;
+ delete[] pMapOut;
+ }
+
+ return pMap;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplVectorizer::ImplCalculate( ImplVectMap* pMap, PolyPolygon& rPolyPoly, BYTE cReduce, ULONG nFlags )
+{
+ const long nWidth = pMap->Width(), nHeight= pMap->Height();
+
+ for( long nY = 0L; nY < nHeight; nY++ )
+ {
+ long nX = 0L;
+ BOOL bInner = TRUE;
+
+ while( nX < nWidth )
+ {
+ // skip free
+ while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
+ nX++;
+
+ if( nX == nWidth )
+ break;
+
+ if( pMap->IsCont( nY, nX ) )
+ {
+ // new contour
+ ImplChain aChain;
+ const Point aStartPt( nX++, nY );
+
+ // get chain code
+ aChain.ImplBeginAdd( aStartPt );
+ ImplGetChain( pMap, aStartPt, aChain );
+
+ if( nFlags & BMP_VECTORIZE_INNER )
+ aChain.ImplEndAdd( bInner ? VECT_POLY_INLINE_INNER : VECT_POLY_INLINE_OUTER );
+ else
+ aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );
+
+ const Polygon& rPoly = aChain.ImplGetPoly();
+
+ if( rPoly.GetSize() > 2 )
+ {
+ if( cReduce )
+ {
+ const Rectangle aBound( rPoly.GetBoundRect() );
+
+ if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
+ rPolyPoly.Insert( rPoly );
+ }
+ else
+ rPolyPoly.Insert( rPoly );
+ }
+
+ // skip rest of detected contour
+ while( pMap->IsCont( nY, nX ) )
+ nX++;
+ }
+ else
+ {
+ // process done segment
+ const long nStartSegX = nX++;
+
+ while( pMap->IsDone( nY, nX ) )
+ nX++;
+
+ if( ( ( nX - nStartSegX ) == 1L ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1L ) ) )
+ bInner = !bInner;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL ImplVectorizer::ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
+{
+ long nActX = rStartPt.X();
+ long nActY = rStartPt.Y();
+ long nTryX;
+ long nTryY;
+ ULONG nFound;
+ ULONG nLastDir = 0UL;
+ ULONG nDir;
+
+ do
+ {
+ nFound = 0UL;
+
+ // first try last direction
+ nTryX = nActX + aImplMove[ nLastDir ].nDX;
+ nTryY = nActY + aImplMove[ nLastDir ].nDY;
+
+ if( pMap->IsCont( nTryY, nTryX ) )
+ {
+ rChain.ImplAdd( (BYTE) nLastDir );
+ pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
+ nFound = 1UL;
+ }
+ else
+ {
+ // try other directions
+ for( nDir = 0UL; nDir < 8UL; nDir++ )
+ {
+ // we already tried nLastDir
+ if( nDir != nLastDir )
+ {
+ nTryX = nActX + aImplMove[ nDir ].nDX;
+ nTryY = nActY + aImplMove[ nDir ].nDY;
+
+ if( pMap->IsCont( nTryY, nTryX ) )
+ {
+ rChain.ImplAdd( (BYTE) nDir );
+ pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX );
+ nFound = 1UL;
+ nLastDir = nDir;
+ break;
+ }
+ }
+ }
+ }
+ }
+ while( nFound );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL ImplVectorizer::ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const
+{
+ if( pMap->IsDone( nY - 1L, nX ) )
+ return TRUE;
+ else if( pMap->IsDone( nY + 1L, nX ) )
+ return FALSE;
+ else if( pMap->IsDone( nY - 1L, nX - 1L ) || pMap->IsDone( nY - 1L, nX + 1L ) )
+ return TRUE;
+ else
+ return FALSE;
+}
diff --git a/vcl/source/gdi/impvect.hxx b/vcl/source/gdi/impvect.hxx
new file mode 100644
index 000000000000..b21a9df2eb7a
--- /dev/null
+++ b/vcl/source/gdi/impvect.hxx
@@ -0,0 +1,63 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_IMPVECT_HXX
+#define _SV_IMPVECT_HXX
+
+#include <tools/poly.hxx>
+#include <vcl/gdimtf.hxx>
+
+// --------------
+// - Vectorizer -
+// --------------
+
+class BitmapReadAccess;
+class ImplChain;
+class ImplVectMap;
+
+class ImplVectorizer
+{
+private:
+
+ ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor );
+ void ImplCalculate( ImplVectMap* pMap, PolyPolygon& rPolyPoly, BYTE cReduce, ULONG nFlags );
+ BOOL ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain );
+ BOOL ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const;
+ void ImplLimitPolyPoly( PolyPolygon& rPolyPoly );
+
+public:
+
+ ImplVectorizer();
+ ~ImplVectorizer();
+
+ BOOL ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
+ BYTE cReduce, ULONG nFlags, const Link* pProgress );
+ BOOL ImplVectorize( const Bitmap& rMonoBmp, PolyPolygon& rPolyPoly,
+ ULONG nFlags, const Link* pProgress );
+};
+
+#endif
diff --git a/vcl/source/gdi/jobset.cxx b/vcl/source/gdi/jobset.cxx
new file mode 100644
index 000000000000..2bc0addaa93c
--- /dev/null
+++ b/vcl/source/gdi/jobset.cxx
@@ -0,0 +1,458 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#ifndef _RTL_ALLOC_H
+#include <rtl/alloc.h>
+#endif
+#include <vcl/jobset.hxx>
+#include <vcl/jobset.h>
+
+// =======================================================================
+
+DBG_NAME( JobSetup )
+
+#define JOBSET_FILEFORMAT2 3780
+#define JOBSET_FILE364_SYSTEM ((USHORT)0xFFFF)
+#define JOBSET_FILE605_SYSTEM ((USHORT)0xFFFE)
+
+struct ImplOldJobSetupData
+{
+ char cPrinterName[64];
+ char cDeviceName[32];
+ char cPortName[32];
+ char cDriverName[32];
+};
+
+struct Impl364JobSetupData
+{
+ SVBT16 nSize;
+ SVBT16 nSystem;
+ SVBT32 nDriverDataLen;
+ SVBT16 nOrientation;
+ SVBT16 nPaperBin;
+ SVBT16 nPaperFormat;
+ SVBT32 nPaperWidth;
+ SVBT32 nPaperHeight;
+};
+
+// =======================================================================
+
+ImplJobSetup::ImplJobSetup()
+{
+ mnRefCount = 1;
+ mnSystem = 0;
+ meOrientation = ORIENTATION_PORTRAIT;
+ meDuplexMode = DUPLEX_UNKNOWN;
+ mnPaperBin = 0;
+ mePaperFormat = PAPER_USER;
+ mnPaperWidth = 0;
+ mnPaperHeight = 0;
+ mnDriverDataLen = 0;
+ mpDriverData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplJobSetup::ImplJobSetup( const ImplJobSetup& rJobSetup ) :
+ maPrinterName( rJobSetup.maPrinterName ),
+ maDriver( rJobSetup.maDriver )
+{
+ mnRefCount = 1;
+ mnSystem = rJobSetup.mnSystem;
+ meOrientation = rJobSetup.meOrientation;
+ meDuplexMode = rJobSetup.meDuplexMode;
+ mnPaperBin = rJobSetup.mnPaperBin;
+ mePaperFormat = rJobSetup.mePaperFormat;
+ mnPaperWidth = rJobSetup.mnPaperWidth;
+ mnPaperHeight = rJobSetup.mnPaperHeight;
+ mnDriverDataLen = rJobSetup.mnDriverDataLen;
+ if ( rJobSetup.mpDriverData )
+ {
+ mpDriverData = (BYTE*)rtl_allocateMemory( mnDriverDataLen );
+ memcpy( mpDriverData, rJobSetup.mpDriverData, mnDriverDataLen );
+ }
+ else
+ mpDriverData = NULL;
+ maValueMap = rJobSetup.maValueMap;
+}
+
+// -----------------------------------------------------------------------
+
+ImplJobSetup::~ImplJobSetup()
+{
+ rtl_freeMemory( mpDriverData );
+}
+
+// =======================================================================
+
+ImplJobSetup* JobSetup::ImplGetData()
+{
+ if ( !mpData )
+ mpData = new ImplJobSetup;
+ else if ( mpData->mnRefCount != 1 )
+ {
+ mpData->mnRefCount--;
+ mpData = new ImplJobSetup( *mpData );
+ }
+
+ return mpData;
+}
+
+// -----------------------------------------------------------------------
+
+ImplJobSetup* JobSetup::ImplGetConstData()
+{
+ if ( !mpData )
+ mpData = new ImplJobSetup;
+ return mpData;
+}
+
+// -----------------------------------------------------------------------
+
+const ImplJobSetup* JobSetup::ImplGetConstData() const
+{
+ if ( !mpData )
+ ((JobSetup*)this)->mpData = new ImplJobSetup;
+ return mpData;
+}
+
+// =======================================================================
+
+JobSetup::JobSetup()
+{
+ DBG_CTOR( JobSetup, NULL );
+
+ mpData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+JobSetup::JobSetup( const JobSetup& rJobSetup )
+{
+ DBG_CTOR( JobSetup, NULL );
+ DBG_CHKOBJ( &rJobSetup, JobSetup, NULL );
+ DBG_ASSERT( !rJobSetup.mpData || (rJobSetup.mpData->mnRefCount < 0xFFFE), "JobSetup: RefCount overflow" );
+
+ mpData = rJobSetup.mpData;
+ if ( mpData )
+ mpData->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+JobSetup::~JobSetup()
+{
+ DBG_DTOR( JobSetup, NULL );
+
+ if ( mpData )
+ {
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString JobSetup::GetPrinterName() const
+{
+ if ( mpData )
+ return mpData->maPrinterName;
+ else
+ {
+ XubString aName;
+ return aName;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString JobSetup::GetDriverName() const
+{
+ if ( mpData )
+ return mpData->maDriver;
+ else
+ {
+ XubString aDriver;
+ return aDriver;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+String JobSetup::GetValue( const String& rKey ) const
+{
+ if( mpData )
+ {
+ ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
+ it = mpData->maValueMap.find( rKey );
+ return it != mpData->maValueMap.end() ? String( it->second ) : String();
+ }
+ return String();
+}
+
+// -----------------------------------------------------------------------
+
+void JobSetup::SetValue( const String& rKey, const String& rValue )
+{
+ if( ! mpData )
+ mpData = new ImplJobSetup();
+
+ mpData->maValueMap[ rKey ] = rValue;
+}
+
+// -----------------------------------------------------------------------
+
+JobSetup& JobSetup::operator=( const JobSetup& rJobSetup )
+{
+ DBG_CHKTHIS( JobSetup, NULL );
+ DBG_CHKOBJ( &rJobSetup, JobSetup, NULL );
+ DBG_ASSERT( !rJobSetup.mpData || (rJobSetup.mpData->mnRefCount) < 0xFFFE, "JobSetup: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ if ( rJobSetup.mpData )
+ rJobSetup.mpData->mnRefCount++;
+
+ // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpData )
+ {
+ if ( mpData->mnRefCount == 1 )
+ delete mpData;
+ else
+ mpData->mnRefCount--;
+ }
+
+ mpData = rJobSetup.mpData;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL JobSetup::operator==( const JobSetup& rJobSetup ) const
+{
+ DBG_CHKTHIS( JobSetup, NULL );
+ DBG_CHKOBJ( &rJobSetup, JobSetup, NULL );
+
+ if ( mpData == rJobSetup.mpData )
+ return TRUE;
+
+ if ( !mpData || !rJobSetup.mpData )
+ return FALSE;
+
+ ImplJobSetup* pData1 = mpData;
+ ImplJobSetup* pData2 = rJobSetup.mpData;
+ if ( (pData1->mnSystem == pData2->mnSystem) &&
+ (pData1->maPrinterName == pData2->maPrinterName) &&
+ (pData1->maDriver == pData2->maDriver) &&
+ (pData1->meOrientation == pData2->meOrientation) &&
+ (pData1->meDuplexMode == pData2->meDuplexMode) &&
+ (pData1->mnPaperBin == pData2->mnPaperBin) &&
+ (pData1->mePaperFormat == pData2->mePaperFormat) &&
+ (pData1->mnPaperWidth == pData2->mnPaperWidth) &&
+ (pData1->mnPaperHeight == pData2->mnPaperHeight) &&
+ (pData1->mnDriverDataLen == pData2->mnDriverDataLen) &&
+ (memcmp( pData1->mpDriverData, pData2->mpDriverData, pData1->mnDriverDataLen ) == 0) &&
+ (pData1->maValueMap == pData2->maValueMap)
+ )
+ return TRUE;
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStream, JobSetup& rJobSetup )
+{
+ DBG_ASSERTWARNING( rIStream.GetVersion(), "JobSetup::>> - Solar-Version not set on rOStream" );
+
+ // Zur Zeit haben wir noch kein neues FileFormat
+// if ( rIStream.GetVersion() < JOBSET_FILEFORMAT2 )
+ {
+ USHORT nLen;
+ USHORT nSystem;
+ sal_Size nFirstPos = rIStream.Tell();
+ rIStream >> nLen;
+ if ( !nLen )
+ return rIStream;
+ rIStream >> nSystem;
+ char* pTempBuf = new char[nLen];
+ rIStream.Read( pTempBuf, nLen - sizeof( nLen ) - sizeof( nSystem ) );
+ if ( nLen >= sizeof(ImplOldJobSetupData)+4 )
+ {
+ ImplOldJobSetupData* pData = (ImplOldJobSetupData*)pTempBuf;
+ if ( rJobSetup.mpData )
+ {
+ if ( rJobSetup.mpData->mnRefCount == 1 )
+ delete rJobSetup.mpData;
+ else
+ rJobSetup.mpData->mnRefCount--;
+ }
+
+ rtl_TextEncoding aStreamEncoding = RTL_TEXTENCODING_UTF8;
+ if( nSystem == JOBSET_FILE364_SYSTEM )
+ aStreamEncoding = rIStream.GetStreamCharSet();
+
+ rJobSetup.mpData = new ImplJobSetup;
+ ImplJobSetup* pJobData = rJobSetup.mpData;
+ pJobData->maPrinterName = UniString( pData->cPrinterName, aStreamEncoding );
+ pJobData->maDriver = UniString( pData->cDriverName, aStreamEncoding );
+
+ // Sind es unsere neuen JobSetup-Daten?
+ if ( nSystem == JOBSET_FILE364_SYSTEM ||
+ nSystem == JOBSET_FILE605_SYSTEM )
+ {
+ Impl364JobSetupData* pOldJobData = (Impl364JobSetupData*)(pTempBuf + sizeof( ImplOldJobSetupData ));
+ USHORT nOldJobDataSize = SVBT16ToShort( pOldJobData->nSize );
+ pJobData->mnSystem = SVBT16ToShort( pOldJobData->nSystem );
+ pJobData->mnDriverDataLen = SVBT32ToUInt32( pOldJobData->nDriverDataLen );
+ pJobData->meOrientation = (Orientation)SVBT16ToShort( pOldJobData->nOrientation );
+ pJobData->meDuplexMode = DUPLEX_UNKNOWN;
+ pJobData->mnPaperBin = SVBT16ToShort( pOldJobData->nPaperBin );
+ pJobData->mePaperFormat = (Paper)SVBT16ToShort( pOldJobData->nPaperFormat );
+ pJobData->mnPaperWidth = (long)SVBT32ToUInt32( pOldJobData->nPaperWidth );
+ pJobData->mnPaperHeight = (long)SVBT32ToUInt32( pOldJobData->nPaperHeight );
+ if ( pJobData->mnDriverDataLen )
+ {
+ BYTE* pDriverData = ((BYTE*)pOldJobData) + nOldJobDataSize;
+ pJobData->mpDriverData = (BYTE*)rtl_allocateMemory( pJobData->mnDriverDataLen );
+ memcpy( pJobData->mpDriverData, pDriverData, pJobData->mnDriverDataLen );
+ }
+ if( nSystem == JOBSET_FILE605_SYSTEM )
+ {
+ rIStream.Seek( nFirstPos + sizeof( ImplOldJobSetupData ) + 4 + sizeof( Impl364JobSetupData ) + pJobData->mnDriverDataLen );
+ while( rIStream.Tell() < nFirstPos + nLen )
+ {
+ String aKey, aValue;
+ rIStream.ReadByteString( aKey, RTL_TEXTENCODING_UTF8 );
+ rIStream.ReadByteString( aValue, RTL_TEXTENCODING_UTF8 );
+ if( aKey.EqualsAscii( "COMPAT_DUPLEX_MODE" ) )
+ {
+ if( aValue.EqualsAscii( "DUPLEX_UNKNOWN" ) )
+ pJobData->meDuplexMode = DUPLEX_UNKNOWN;
+ else if( aValue.EqualsAscii( "DUPLEX_OFF" ) )
+ pJobData->meDuplexMode = DUPLEX_OFF;
+ else if( aValue.EqualsAscii( "DUPLEX_SHORTEDGE" ) )
+ pJobData->meDuplexMode = DUPLEX_SHORTEDGE;
+ else if( aValue.EqualsAscii( "DUPLEX_LONGEDGE" ) )
+ pJobData->meDuplexMode = DUPLEX_LONGEDGE;
+ }
+ else
+ pJobData->maValueMap[ aKey ] = aValue;
+ }
+ DBG_ASSERT( rIStream.Tell() == nFirstPos+nLen, "corrupted job setup" );
+ // ensure correct stream position
+ rIStream.Seek( nFirstPos + nLen );
+ }
+ }
+ }
+ delete[] pTempBuf;
+ }
+/*
+ else
+ {
+ }
+*/
+
+ return rIStream;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const JobSetup& rJobSetup )
+{
+ DBG_ASSERTWARNING( rOStream.GetVersion(), "JobSetup::<< - Solar-Version not set on rOStream" );
+
+ // Zur Zeit haben wir noch kein neues FileFormat
+// if ( rOStream.GetVersion() < JOBSET_FILEFORMAT2 )
+ {
+ USHORT nLen = 0;
+ if ( !rJobSetup.mpData )
+ rOStream << nLen;
+ else
+ {
+ USHORT nSystem = JOBSET_FILE605_SYSTEM;
+
+ const ImplJobSetup* pJobData = rJobSetup.ImplGetConstData();
+ Impl364JobSetupData aOldJobData;
+ USHORT nOldJobDataSize = sizeof( aOldJobData );
+ ShortToSVBT16( nOldJobDataSize, aOldJobData.nSize );
+ ShortToSVBT16( pJobData->mnSystem, aOldJobData.nSystem );
+ UInt32ToSVBT32( pJobData->mnDriverDataLen, aOldJobData.nDriverDataLen );
+ ShortToSVBT16( (USHORT)(pJobData->meOrientation), aOldJobData.nOrientation );
+ ShortToSVBT16( pJobData->mnPaperBin, aOldJobData.nPaperBin );
+ ShortToSVBT16( (USHORT)(pJobData->mePaperFormat), aOldJobData.nPaperFormat );
+ UInt32ToSVBT32( (ULONG)(pJobData->mnPaperWidth), aOldJobData.nPaperWidth );
+ UInt32ToSVBT32( (ULONG)(pJobData->mnPaperHeight), aOldJobData.nPaperHeight );
+
+ ImplOldJobSetupData aOldData;
+ memset( &aOldData, 0, sizeof( aOldData ) );
+ ByteString aPrnByteName( rJobSetup.GetPrinterName(), RTL_TEXTENCODING_UTF8 );
+ strncpy( aOldData.cPrinterName, aPrnByteName.GetBuffer(), 63 );
+ ByteString aDriverByteName( rJobSetup.GetDriverName(), RTL_TEXTENCODING_UTF8 );
+ strncpy( aOldData.cDriverName, aDriverByteName.GetBuffer(), 31 );
+// nLen = sizeof( aOldData ) + 4 + nOldJobDataSize + pJobData->mnDriverDataLen;
+ int nPos = rOStream.Tell();
+ rOStream << nLen;
+ rOStream << nSystem;
+ rOStream.Write( (char*)&aOldData, sizeof( aOldData ) );
+ rOStream.Write( (char*)&aOldJobData, nOldJobDataSize );
+ rOStream.Write( (char*)pJobData->mpDriverData, pJobData->mnDriverDataLen );
+ ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
+ for( it = pJobData->maValueMap.begin(); it != pJobData->maValueMap.end(); ++it )
+ {
+ rOStream.WriteByteString( it->first, RTL_TEXTENCODING_UTF8 );
+ rOStream.WriteByteString( it->second, RTL_TEXTENCODING_UTF8 );
+ }
+ rOStream.WriteByteString( "COMPAT_DUPLEX_MODE" ) ;
+ switch( pJobData->meDuplexMode )
+ {
+ case DUPLEX_UNKNOWN: rOStream.WriteByteString( "DUPLEX_UNKNOWN" );break;
+ case DUPLEX_OFF: rOStream.WriteByteString( "DUPLEX_OFF" );break;
+ case DUPLEX_SHORTEDGE: rOStream.WriteByteString( "DUPLEX_SHORTEDGE" );break;
+ case DUPLEX_LONGEDGE: rOStream.WriteByteString( "DUPLEX_LONGEDGE" );break;
+ }
+ nLen = sal::static_int_cast<USHORT>(rOStream.Tell() - nPos);
+ rOStream.Seek( nPos );
+ rOStream << nLen;
+ rOStream.Seek( nPos + nLen );
+ }
+ }
+/*
+ else
+ {
+ }
+*/
+
+ return rOStream;
+}
diff --git a/vcl/source/gdi/lineinfo.cxx b/vcl/source/gdi/lineinfo.cxx
new file mode 100644
index 000000000000..bb57a0b582e6
--- /dev/null
+++ b/vcl/source/gdi/lineinfo.cxx
@@ -0,0 +1,361 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/debug.hxx>
+#include <vcl/lineinfo.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+#include <numeric>
+
+DBG_NAME( LineInfo )
+
+// ----------------
+// - ImplLineInfo -
+// ----------------
+
+ImplLineInfo::ImplLineInfo() :
+ mnRefCount ( 1 ),
+ meStyle ( LINE_SOLID ),
+ mnWidth ( 0 ),
+ mnDashCount ( 0 ),
+ mnDashLen ( 0 ),
+ mnDotCount ( 0 ),
+ mnDotLen ( 0 ),
+ mnDistance ( 0 ),
+ meLineJoin ( basegfx::B2DLINEJOIN_ROUND )
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImplLineInfo::ImplLineInfo( const ImplLineInfo& rImplLineInfo ) :
+ mnRefCount ( 1 ),
+ meStyle ( rImplLineInfo.meStyle ),
+ mnWidth ( rImplLineInfo.mnWidth ),
+ mnDashCount ( rImplLineInfo.mnDashCount ),
+ mnDashLen ( rImplLineInfo.mnDashLen ),
+ mnDotCount ( rImplLineInfo.mnDotCount ),
+ mnDotLen ( rImplLineInfo.mnDotLen ),
+ mnDistance ( rImplLineInfo.mnDistance ),
+ meLineJoin ( rImplLineInfo.meLineJoin )
+{
+}
+
+// ------------
+// - LineInfo -
+// ------------
+
+LineInfo::LineInfo( LineStyle eStyle, long nWidth )
+{
+ DBG_CTOR( LineInfo, NULL );
+ mpImplLineInfo = new ImplLineInfo;
+ mpImplLineInfo->meStyle = eStyle;
+ mpImplLineInfo->mnWidth = nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+LineInfo::LineInfo( const LineInfo& rLineInfo )
+{
+ DBG_CTOR( LineInfo, NULL );
+ DBG_CHKOBJ( &rLineInfo, LineInfo, NULL );
+ mpImplLineInfo = rLineInfo.mpImplLineInfo;
+ mpImplLineInfo->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+LineInfo::~LineInfo()
+{
+ DBG_DTOR( LineInfo, NULL );
+ if( !( --mpImplLineInfo->mnRefCount ) )
+ delete mpImplLineInfo;
+}
+
+// -----------------------------------------------------------------------
+
+LineInfo& LineInfo::operator=( const LineInfo& rLineInfo )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ DBG_CHKOBJ( &rLineInfo, LineInfo, NULL );
+
+ rLineInfo.mpImplLineInfo->mnRefCount++;
+
+ if( !( --mpImplLineInfo->mnRefCount ) )
+ delete mpImplLineInfo;
+
+ mpImplLineInfo = rLineInfo.mpImplLineInfo;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL LineInfo::operator==( const LineInfo& rLineInfo ) const
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ DBG_CHKOBJ( &rLineInfo, LineInfo, NULL );
+
+ return( mpImplLineInfo == rLineInfo.mpImplLineInfo ||
+ ( mpImplLineInfo->meStyle == rLineInfo.mpImplLineInfo->meStyle &&
+ mpImplLineInfo->mnWidth == rLineInfo.mpImplLineInfo->mnWidth &&
+ mpImplLineInfo->mnDashCount == rLineInfo.mpImplLineInfo->mnDashCount &&
+ mpImplLineInfo->mnDashLen == rLineInfo.mpImplLineInfo->mnDashLen &&
+ mpImplLineInfo->mnDotCount == rLineInfo.mpImplLineInfo->mnDotCount &&
+ mpImplLineInfo->mnDotLen == rLineInfo.mpImplLineInfo->mnDotLen &&
+ mpImplLineInfo->mnDistance == rLineInfo.mpImplLineInfo->mnDistance ) );
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::ImplMakeUnique()
+{
+ if( mpImplLineInfo->mnRefCount != 1 )
+ {
+ if( mpImplLineInfo->mnRefCount )
+ mpImplLineInfo->mnRefCount--;
+
+ mpImplLineInfo = new ImplLineInfo( *mpImplLineInfo );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetStyle( LineStyle eStyle )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ ImplMakeUnique();
+ mpImplLineInfo->meStyle = eStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetWidth( long nWidth )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ ImplMakeUnique();
+ mpImplLineInfo->mnWidth = nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetDashCount( USHORT nDashCount )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ ImplMakeUnique();
+ mpImplLineInfo->mnDashCount = nDashCount;
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetDashLen( long nDashLen )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ ImplMakeUnique();
+ mpImplLineInfo->mnDashLen = nDashLen;
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetDotCount( USHORT nDotCount )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ ImplMakeUnique();
+ mpImplLineInfo->mnDotCount = nDotCount;
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetDotLen( long nDotLen )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ ImplMakeUnique();
+ mpImplLineInfo->mnDotLen = nDotLen;
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetDistance( long nDistance )
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+ ImplMakeUnique();
+ mpImplLineInfo->mnDistance = nDistance;
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::SetLineJoin(basegfx::B2DLineJoin eLineJoin)
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+
+ if(eLineJoin != mpImplLineInfo->meLineJoin)
+ {
+ ImplMakeUnique();
+ mpImplLineInfo->meLineJoin = eLineJoin;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+ UINT16 nTmp16;
+
+ rIStm >> nTmp16; rImplLineInfo.meStyle = (LineStyle) nTmp16;
+ rIStm >> rImplLineInfo.mnWidth;
+
+ if( aCompat.GetVersion() >= 2 )
+ {
+ // version 2
+ rIStm >> rImplLineInfo.mnDashCount >> rImplLineInfo.mnDashLen;
+ rIStm >> rImplLineInfo.mnDotCount >> rImplLineInfo.mnDotLen;
+ rIStm >> rImplLineInfo.mnDistance;
+ }
+
+ if( aCompat.GetVersion() >= 3 )
+ {
+ // version 3
+ rIStm >> nTmp16; rImplLineInfo.meLineJoin = (basegfx::B2DLineJoin) nTmp16;
+ }
+
+ return rIStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const ImplLineInfo& rImplLineInfo )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 3 );
+
+ // version 1
+ rOStm << (UINT16) rImplLineInfo.meStyle << rImplLineInfo.mnWidth;
+
+ // since version2
+ rOStm << rImplLineInfo.mnDashCount << rImplLineInfo.mnDashLen;
+ rOStm << rImplLineInfo.mnDotCount << rImplLineInfo.mnDotLen;
+ rOStm << rImplLineInfo.mnDistance;
+
+ // since version3
+ rOStm << (UINT16) rImplLineInfo.meLineJoin;
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, LineInfo& rLineInfo )
+{
+ rLineInfo.ImplMakeUnique();
+ return( rIStm >> *rLineInfo.mpImplLineInfo );
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo )
+{
+ return( rOStm << *rLineInfo.mpImplLineInfo );
+}
+
+// -----------------------------------------------------------------------
+
+bool LineInfo::isDashDotOrFatLineUsed() const
+{
+ return (LINE_DASH == GetStyle() || GetWidth() > 1);
+}
+
+// -----------------------------------------------------------------------
+
+void LineInfo::applyToB2DPolyPolygon(
+ basegfx::B2DPolyPolygon& io_rLinePolyPolygon,
+ basegfx::B2DPolyPolygon& o_rFillPolyPolygon) const
+{
+ o_rFillPolyPolygon.clear();
+
+ if(io_rLinePolyPolygon.count())
+ {
+ if(LINE_DASH == GetStyle())
+ {
+ ::std::vector< double > fDotDashArray;
+ const double fDashLen(GetDashLen());
+ const double fDotLen(GetDotLen());
+ const double fDistance(GetDistance());
+
+ for(sal_uInt16 a(0); a < GetDashCount(); a++)
+ {
+ fDotDashArray.push_back(fDashLen);
+ fDotDashArray.push_back(fDistance);
+ }
+
+ for(sal_uInt16 b(0); b < GetDotCount(); b++)
+ {
+ fDotDashArray.push_back(fDotLen);
+ fDotDashArray.push_back(fDistance);
+ }
+
+ const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
+
+ if(fAccumulated > 0.0)
+ {
+ basegfx::B2DPolyPolygon aResult;
+
+ for(sal_uInt32 c(0); c < io_rLinePolyPolygon.count(); c++)
+ {
+ basegfx::B2DPolyPolygon aLineTraget;
+ basegfx::tools::applyLineDashing(
+ io_rLinePolyPolygon.getB2DPolygon(c),
+ fDotDashArray,
+ &aLineTraget);
+ aResult.append(aLineTraget);
+ }
+
+ io_rLinePolyPolygon = aResult;
+ }
+ }
+
+ if(GetWidth() > 1 && io_rLinePolyPolygon.count())
+ {
+ const double fHalfLineWidth((GetWidth() * 0.5) + 0.5);
+
+ for(sal_uInt32 a(0); a < io_rLinePolyPolygon.count(); a++)
+ {
+ o_rFillPolyPolygon.append(basegfx::tools::createAreaGeometry(
+ io_rLinePolyPolygon.getB2DPolygon(a),
+ fHalfLineWidth,
+ GetLineJoin()));
+ }
+
+ io_rLinePolyPolygon.clear();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk
new file mode 100644
index 000000000000..77df20976c73
--- /dev/null
+++ b/vcl/source/gdi/makefile.mk
@@ -0,0 +1,121 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=gdi
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+.IF "$(COM)"=="ICC"
+CDEFS+=-D_STD_NO_NAMESPACE -D_VOS_NO_NAMESPACE -D_UNO_NO_NAMESPACE
+.ENDIF
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CDEFS+=-DENABLE_GRAPHITE
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+EXCEPTIONSFILES= $(SLO)$/salmisc.obj \
+ $(SLO)$/outdev.obj \
+ $(SLO)$/outdev3.obj \
+ $(SLO)$/outdevnative.obj \
+ $(SLO)$/gfxlink.obj \
+ $(SLO)$/print.obj \
+ $(SLO)$/print2.obj \
+ $(SLO)$/print3.obj \
+ $(SLO)$/oldprintadaptor.obj \
+ $(SLO)$/configsettings.obj \
+ $(SLO)$/sallayout.obj \
+ $(SLO)$/image.obj \
+ $(SLO)$/impimage.obj \
+ $(SLO)$/impgraph.obj \
+ $(SLO)$/metric.obj \
+ $(SLO)$/pdfwriter_impl.obj \
+ $(SLO)$/pdffontcache.obj\
+ $(SLO)$/bmpconv.obj \
+ $(SLO)$/pdfextoutdevdata.obj \
+ $(SLO)$/jobset.obj \
+ $(SLO)$/impimagetree.obj \
+ $(SLO)$/pngread.obj \
+ $(SLO)$/pngwrite.obj \
+ $(SLO)$/virdev.obj \
+ $(SLO)$/gdimtf.obj \
+ $(SLO)$/graphictools.obj \
+ $(SLO)$/textlayout.obj \
+ $(SLO)$/lineinfo.obj
+
+SLOFILES= $(EXCEPTIONSFILES) \
+ $(SLO)$/animate.obj \
+ $(SLO)$/impanmvw.obj \
+ $(SLO)$/bitmap.obj \
+ $(SLO)$/bitmap2.obj \
+ $(SLO)$/bitmap3.obj \
+ $(SLO)$/bitmap4.obj \
+ $(SLO)$/alpha.obj \
+ $(SLO)$/bitmapex.obj \
+ $(SLO)$/bmpacc.obj \
+ $(SLO)$/bmpacc2.obj \
+ $(SLO)$/bmpacc3.obj \
+ $(SLO)$/bmpfast.obj \
+ $(SLO)$/cvtsvm.obj \
+ $(SLO)$/cvtgrf.obj \
+ $(SLO)$/font.obj \
+ $(SLO)$/gradient.obj \
+ $(SLO)$/hatch.obj \
+ $(SLO)$/graph.obj \
+ $(SLO)$/impbmp.obj \
+ $(SLO)$/imagerepository.obj \
+ $(SLO)$/impvect.obj \
+ $(SLO)$/mapmod.obj \
+ $(SLO)$/metaact.obj \
+ $(SLO)$/octree.obj \
+ $(SLO)$/outmap.obj \
+ $(SLO)$/outdev2.obj \
+ $(SLO)$/outdev4.obj \
+ $(SLO)$/outdev5.obj \
+ $(SLO)$/outdev6.obj \
+ $(SLO)$/regband.obj \
+ $(SLO)$/region.obj \
+ $(SLO)$/wall.obj \
+ $(SLO)$/base14.obj \
+ $(SLO)$/pdfwriter.obj \
+ $(SLO)$/salgdilayout.obj \
+ $(SLO)$/extoutdevdata.obj \
+ $(SLO)$/salnativewidgets-none.obj
+
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/source/gdi/mapmod.cxx b/vcl/source/gdi/mapmod.cxx
new file mode 100644
index 000000000000..34f0f473c7f8
--- /dev/null
+++ b/vcl/source/gdi/mapmod.cxx
@@ -0,0 +1,311 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/debug.hxx>
+#include <vcl/mapmod.hxx>
+
+// =======================================================================
+
+DBG_NAME( MapMode )
+
+// -----------------------------------------------------------------------
+
+ImplMapMode::ImplMapMode() :
+ maOrigin( 0, 0 ),
+ maScaleX( 1, 1 ),
+ maScaleY( 1, 1 )
+{
+ mnRefCount = 1;
+ meUnit = MAP_PIXEL;
+ mbSimple = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplMapMode::ImplMapMode( const ImplMapMode& rImplMapMode ) :
+ maOrigin( rImplMapMode.maOrigin ),
+ maScaleX( rImplMapMode.maScaleX ),
+ maScaleY( rImplMapMode.maScaleY )
+{
+ mnRefCount = 1;
+ meUnit = rImplMapMode.meUnit;
+ mbSimple = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, ImplMapMode& rImplMapMode )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+ UINT16 nTmp16;
+
+ rIStm >> nTmp16; rImplMapMode.meUnit = (MapUnit) nTmp16;
+ rIStm >> rImplMapMode.maOrigin >> rImplMapMode.maScaleX >>
+ rImplMapMode.maScaleY >> rImplMapMode.mbSimple;
+
+ return rIStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const ImplMapMode& rImplMapMode )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 1 );
+
+ rOStm << (UINT16) rImplMapMode.meUnit <<
+ rImplMapMode.maOrigin <<
+ rImplMapMode.maScaleX <<
+ rImplMapMode.maScaleY <<
+ rImplMapMode.mbSimple;
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+ImplMapMode* ImplMapMode::ImplGetStaticMapMode( MapUnit eUnit )
+{
+ static long aStaticImplMapModeAry[(MAP_LASTENUMDUMMY)*sizeof(ImplMapMode)/sizeof(long)];
+
+ // #i19496 check for out-of-bounds
+ if( eUnit >= MAP_LASTENUMDUMMY )
+ return (ImplMapMode*)aStaticImplMapModeAry;
+
+ ImplMapMode* pImplMapMode = ((ImplMapMode*)aStaticImplMapModeAry)+eUnit;
+ if ( !pImplMapMode->mbSimple )
+ {
+ Fraction aDefFraction( 1, 1 );
+ pImplMapMode->maScaleX = aDefFraction;
+ pImplMapMode->maScaleY = aDefFraction;
+ pImplMapMode->meUnit = eUnit;
+ pImplMapMode->mbSimple = TRUE;
+ }
+
+ return pImplMapMode;
+}
+
+// -----------------------------------------------------------------------
+
+inline void MapMode::ImplMakeUnique()
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpImplMapMode->mnRefCount != 1 )
+ {
+ if ( mpImplMapMode->mnRefCount )
+ mpImplMapMode->mnRefCount--;
+ mpImplMapMode = new ImplMapMode( *mpImplMapMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MapMode::MapMode()
+{
+ DBG_CTOR( MapMode, NULL );
+
+ mpImplMapMode = ImplMapMode::ImplGetStaticMapMode( MAP_PIXEL );
+}
+
+// -----------------------------------------------------------------------
+
+MapMode::MapMode( const MapMode& rMapMode )
+{
+ DBG_CTOR( MapMode, NULL );
+ DBG_CHKOBJ( &rMapMode, MapMode, NULL );
+ DBG_ASSERT( rMapMode.mpImplMapMode->mnRefCount < 0xFFFFFFFE, "MapMode: RefCount overflow" );
+
+ // shared Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpImplMapMode = rMapMode.mpImplMapMode;
+ // RefCount == 0 fuer statische Objekte
+ if ( mpImplMapMode->mnRefCount )
+ mpImplMapMode->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+MapMode::MapMode( MapUnit eUnit )
+{
+ DBG_CTOR( MapMode, NULL );
+
+ mpImplMapMode = ImplMapMode::ImplGetStaticMapMode( eUnit );
+}
+
+// -----------------------------------------------------------------------
+
+MapMode::MapMode( MapUnit eUnit, const Point& rLogicOrg,
+ const Fraction& rScaleX, const Fraction& rScaleY )
+{
+ DBG_CTOR( MapMode, NULL );
+
+ mpImplMapMode = new ImplMapMode;
+ mpImplMapMode->meUnit = eUnit;
+ mpImplMapMode->maOrigin = rLogicOrg;
+ mpImplMapMode->maScaleX = rScaleX;
+ mpImplMapMode->maScaleY = rScaleY;
+}
+
+// -----------------------------------------------------------------------
+
+MapMode::~MapMode()
+{
+ DBG_DTOR( MapMode, NULL );
+
+ // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpImplMapMode->mnRefCount )
+ {
+ if ( mpImplMapMode->mnRefCount == 1 )
+ delete mpImplMapMode;
+ else
+ mpImplMapMode->mnRefCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void MapMode::SetMapUnit( MapUnit eUnit )
+{
+ DBG_CHKTHIS( MapMode, NULL );
+
+ ImplMakeUnique();
+ mpImplMapMode->meUnit = eUnit;
+}
+
+// -----------------------------------------------------------------------
+
+void MapMode::SetOrigin( const Point& rLogicOrg )
+{
+ DBG_CHKTHIS( MapMode, NULL );
+
+ ImplMakeUnique();
+ mpImplMapMode->maOrigin = rLogicOrg;
+}
+
+// -----------------------------------------------------------------------
+
+void MapMode::SetScaleX( const Fraction& rScaleX )
+{
+ DBG_CHKTHIS( MapMode, NULL );
+
+ ImplMakeUnique();
+ mpImplMapMode->maScaleX = rScaleX;
+}
+
+// -----------------------------------------------------------------------
+
+void MapMode::SetScaleY( const Fraction& rScaleY )
+{
+ DBG_CHKTHIS( MapMode, NULL );
+
+ ImplMakeUnique();
+ mpImplMapMode->maScaleY = rScaleY;
+}
+
+// -----------------------------------------------------------------------
+
+MapMode& MapMode::operator=( const MapMode& rMapMode )
+{
+ DBG_CHKTHIS( MapMode, NULL );
+ DBG_CHKOBJ( &rMapMode, MapMode, NULL );
+ DBG_ASSERT( rMapMode.mpImplMapMode->mnRefCount < 0xFFFFFFFE, "MapMode: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ // RefCount == 0 fuer statische Objekte
+ if ( rMapMode.mpImplMapMode->mnRefCount )
+ rMapMode.mpImplMapMode->mnRefCount++;
+
+ // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpImplMapMode->mnRefCount )
+ {
+ if ( mpImplMapMode->mnRefCount == 1 )
+ delete mpImplMapMode;
+ else
+ mpImplMapMode->mnRefCount--;
+ }
+
+ mpImplMapMode = rMapMode.mpImplMapMode;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MapMode::operator==( const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( MapMode, NULL );
+ DBG_CHKOBJ( &rMapMode, MapMode, NULL );
+
+ if ( mpImplMapMode == rMapMode.mpImplMapMode )
+ return TRUE;
+
+ if ( (mpImplMapMode->meUnit == rMapMode.mpImplMapMode->meUnit) &&
+ (mpImplMapMode->maOrigin == rMapMode.mpImplMapMode->maOrigin) &&
+ (mpImplMapMode->maScaleX == rMapMode.mpImplMapMode->maScaleX) &&
+ (mpImplMapMode->maScaleY == rMapMode.mpImplMapMode->maScaleY) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MapMode::IsDefault() const
+{
+ DBG_CHKTHIS( MapMode, NULL );
+
+ ImplMapMode* pDefMapMode = ImplMapMode::ImplGetStaticMapMode( MAP_PIXEL );
+ if ( mpImplMapMode == pDefMapMode )
+ return TRUE;
+
+ if ( (mpImplMapMode->meUnit == pDefMapMode->meUnit) &&
+ (mpImplMapMode->maOrigin == pDefMapMode->maOrigin) &&
+ (mpImplMapMode->maScaleX == pDefMapMode->maScaleX) &&
+ (mpImplMapMode->maScaleY == pDefMapMode->maScaleY) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, MapMode& rMapMode )
+{
+ rMapMode.ImplMakeUnique();
+ return (rIStm >> *rMapMode.mpImplMapMode);
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const MapMode& rMapMode )
+{
+ return (rOStm << *rMapMode.mpImplMapMode);
+}
diff --git a/vcl/source/gdi/metaact.cxx b/vcl/source/gdi/metaact.cxx
new file mode 100644
index 000000000000..752a4222bcb2
--- /dev/null
+++ b/vcl/source/gdi/metaact.cxx
@@ -0,0 +1,4276 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define ENABLE_BYTESTRING_STREAM_OPERATORS
+
+#include <algorithm>
+#include <string.h>
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/graphictools.hxx>
+
+// ========================================================================
+
+inline void ImplScalePoint( Point& rPt, double fScaleX, double fScaleY )
+{
+ rPt.X() = FRound( fScaleX * rPt.X() );
+ rPt.Y() = FRound( fScaleY * rPt.Y() );
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImplScaleRect( Rectangle& rRect, double fScaleX, double fScaleY )
+{
+ Point aTL( rRect.TopLeft() );
+ Point aBR( rRect.BottomRight() );
+
+ ImplScalePoint( aTL, fScaleX, fScaleY );
+ ImplScalePoint( aBR, fScaleX, fScaleY );
+
+ rRect = Rectangle( aTL, aBR );
+ rRect.Justify();
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImplScalePoly( Polygon& rPoly, double fScaleX, double fScaleY )
+{
+ for( USHORT i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
+ ImplScalePoint( rPoly[ i ], fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImplScaleLineInfo( LineInfo& rLineInfo, double fScaleX, double fScaleY )
+{
+ if( !rLineInfo.IsDefault() )
+ {
+ const double fScale = ( fabs(fScaleX) + fabs(fScaleY) ) * 0.5;
+
+ rLineInfo.SetWidth( FRound( fScale * rLineInfo.GetWidth() ) );
+ rLineInfo.SetDashLen( FRound( fScale * rLineInfo.GetDashLen() ) );
+ rLineInfo.SetDotLen( FRound( fScale * rLineInfo.GetDotLen() ) );
+ rLineInfo.SetDistance( FRound( fScale * rLineInfo.GetDistance() ) );
+ }
+}
+
+// ========================================================================
+
+#define COMPAT( _def_rIStm ) VersionCompat aCompat( ( _def_rIStm ), STREAM_READ );
+#define COMPAT_VERSION() aCompat.GetVersion()
+#define WRITE_BASE_COMPAT( _def_rOStm, _def_nVer, _pWriteData ) \
+ MetaAction::Write( ( _def_rOStm ), _pWriteData ); \
+ VersionCompat aCompat( ( _def_rOStm ), STREAM_WRITE, ( _def_nVer ) );
+
+// ========================================================================
+
+MetaAction::MetaAction() :
+ mnRefCount( 1 ),
+ mnType( META_NULL_ACTION )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction::MetaAction( USHORT nType ) :
+ mnRefCount( 1 ),
+ mnType( nType )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction::~MetaAction()
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaAction::Execute( OutputDevice* )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaAction::Clone()
+{
+ return new MetaAction;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaAction::Move( long, long )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaAction::Scale( double, double )
+{
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaAction::Compare( const MetaAction& ) const
+{
+ return sal_True;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaAction::IsEqual( const MetaAction& rMetaAction ) const
+{
+ if ( mnType != rMetaAction.mnType )
+ return sal_False;
+ else
+ return Compare( rMetaAction );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaAction::Write( SvStream& rOStm, ImplMetaWriteData* )
+{
+ rOStm << mnType;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ rIStm >> mnType;
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaAction::ReadMetaAction( SvStream& rIStm, ImplMetaReadData* pData )
+{
+ MetaAction* pAction = NULL;
+ UINT16 nType;
+
+ rIStm >> nType;
+
+ switch( nType )
+ {
+ case( META_NULL_ACTION ): pAction = new MetaAction; break;
+ case( META_PIXEL_ACTION ): pAction = new MetaPixelAction; break;
+ case( META_POINT_ACTION ): pAction = new MetaPointAction; break;
+ case( META_LINE_ACTION ): pAction = new MetaLineAction; break;
+ case( META_RECT_ACTION ): pAction = new MetaRectAction; break;
+ case( META_ROUNDRECT_ACTION ): pAction = new MetaRoundRectAction; break;
+ case( META_ELLIPSE_ACTION ): pAction = new MetaEllipseAction; break;
+ case( META_ARC_ACTION ): pAction = new MetaArcAction; break;
+ case( META_PIE_ACTION ): pAction = new MetaPieAction; break;
+ case( META_CHORD_ACTION ): pAction = new MetaChordAction; break;
+ case( META_POLYLINE_ACTION ): pAction = new MetaPolyLineAction; break;
+ case( META_POLYGON_ACTION ): pAction = new MetaPolygonAction; break;
+ case( META_POLYPOLYGON_ACTION ): pAction = new MetaPolyPolygonAction; break;
+ case( META_TEXT_ACTION ): pAction = new MetaTextAction; break;
+ case( META_TEXTARRAY_ACTION ): pAction = new MetaTextArrayAction; break;
+ case( META_STRETCHTEXT_ACTION ): pAction = new MetaStretchTextAction; break;
+ case( META_TEXTRECT_ACTION ): pAction = new MetaTextRectAction; break;
+ case( META_TEXTLINE_ACTION ): pAction = new MetaTextLineAction; break;
+ case( META_BMP_ACTION ): pAction = new MetaBmpAction; break;
+ case( META_BMPSCALE_ACTION ): pAction = new MetaBmpScaleAction; break;
+ case( META_BMPSCALEPART_ACTION ): pAction = new MetaBmpScalePartAction; break;
+ case( META_BMPEX_ACTION ): pAction = new MetaBmpExAction; break;
+ case( META_BMPEXSCALE_ACTION ): pAction = new MetaBmpExScaleAction; break;
+ case( META_BMPEXSCALEPART_ACTION ): pAction = new MetaBmpExScalePartAction; break;
+ case( META_MASK_ACTION ): pAction = new MetaMaskAction; break;
+ case( META_MASKSCALE_ACTION ): pAction = new MetaMaskScaleAction; break;
+ case( META_MASKSCALEPART_ACTION ): pAction = new MetaMaskScalePartAction; break;
+ case( META_GRADIENT_ACTION ): pAction = new MetaGradientAction; break;
+ case( META_GRADIENTEX_ACTION ): pAction = new MetaGradientExAction; break;
+ case( META_HATCH_ACTION ): pAction = new MetaHatchAction; break;
+ case( META_WALLPAPER_ACTION ): pAction = new MetaWallpaperAction; break;
+ case( META_CLIPREGION_ACTION ): pAction = new MetaClipRegionAction; break;
+ case( META_ISECTRECTCLIPREGION_ACTION ): pAction = new MetaISectRectClipRegionAction; break;
+ case( META_ISECTREGIONCLIPREGION_ACTION ): pAction = new MetaISectRegionClipRegionAction; break;
+ case( META_MOVECLIPREGION_ACTION ): pAction = new MetaMoveClipRegionAction; break;
+ case( META_LINECOLOR_ACTION ): pAction = new MetaLineColorAction; break;
+ case( META_FILLCOLOR_ACTION ): pAction = new MetaFillColorAction; break;
+ case( META_TEXTCOLOR_ACTION ): pAction = new MetaTextColorAction; break;
+ case( META_TEXTFILLCOLOR_ACTION ): pAction = new MetaTextFillColorAction; break;
+ case( META_TEXTLINECOLOR_ACTION ): pAction = new MetaTextLineColorAction; break;
+ case( META_OVERLINECOLOR_ACTION ): pAction = new MetaOverlineColorAction; break;
+ case( META_TEXTALIGN_ACTION ): pAction = new MetaTextAlignAction; break;
+ case( META_MAPMODE_ACTION ): pAction = new MetaMapModeAction; break;
+ case( META_FONT_ACTION ): pAction = new MetaFontAction; break;
+ case( META_PUSH_ACTION ): pAction = new MetaPushAction; break;
+ case( META_POP_ACTION ): pAction = new MetaPopAction; break;
+ case( META_RASTEROP_ACTION ): pAction = new MetaRasterOpAction; break;
+ case( META_TRANSPARENT_ACTION ): pAction = new MetaTransparentAction; break;
+ case( META_FLOATTRANSPARENT_ACTION ): pAction = new MetaFloatTransparentAction; break;
+ case( META_EPS_ACTION ): pAction = new MetaEPSAction; break;
+ case( META_REFPOINT_ACTION ): pAction = new MetaRefPointAction; break;
+ case( META_COMMENT_ACTION ): pAction = new MetaCommentAction; break;
+ case( META_LAYOUTMODE_ACTION ): pAction = new MetaLayoutModeAction; break;
+ case( META_TEXTLANGUAGE_ACTION ): pAction = new MetaTextLanguageAction; break;
+
+ default:
+ {
+ // Action ueberlesen durch Kombination Ctor/Dtor,
+ // new/delete, weil Compiler sonst vielleicht wegoptimieren
+ delete ( new VersionCompat( rIStm, STREAM_READ ) );
+ }
+ break;
+ }
+
+ if( pAction )
+ pAction->Read( rIStm, pData );
+
+ return pAction;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Pixel, META_PIXEL_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaPixelAction::MetaPixelAction( const Point& rPt, const Color& rColor ) :
+ MetaAction ( META_PIXEL_ACTION ),
+ maPt ( rPt ),
+ maColor ( rColor )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPixelAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawPixel( maPt, maColor );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPixelAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPixelAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPixelAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPixelAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaPixelAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maPt == ((MetaPixelAction&)rMetaAction).maPt ) &&
+ ( maColor == ((MetaPixelAction&)rMetaAction).maColor );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPixelAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maPt;
+ maColor.Write( rOStm, TRUE );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPixelAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maPt;
+ maColor.Read( rIStm, TRUE );
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Point, META_POINT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaPointAction::MetaPointAction( const Point& rPt ) :
+ MetaAction ( META_POINT_ACTION ),
+ maPt ( rPt )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPointAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawPixel( maPt );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPointAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPointAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPointAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPointAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaPointAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maPt == ((MetaPointAction&)rMetaAction).maPt;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPointAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maPt;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPointAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maPt;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Line, META_LINE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaLineAction::MetaLineAction( const Point& rStart, const Point& rEnd ) :
+ MetaAction ( META_LINE_ACTION ),
+ maStartPt ( rStart ),
+ maEndPt ( rEnd )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaLineAction::MetaLineAction( const Point& rStart, const Point& rEnd,
+ const LineInfo& rLineInfo ) :
+ MetaAction ( META_LINE_ACTION ),
+ maLineInfo ( rLineInfo ),
+ maStartPt ( rStart ),
+ maEndPt ( rEnd )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineAction::Execute( OutputDevice* pOut )
+{
+ if( maLineInfo.IsDefault() )
+ pOut->DrawLine( maStartPt, maEndPt );
+ else
+ pOut->DrawLine( maStartPt, maEndPt, maLineInfo );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaLineAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaLineAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineAction::Move( long nHorzMove, long nVertMove )
+{
+ maStartPt.Move( nHorzMove, nVertMove );
+ maEndPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maStartPt, fScaleX, fScaleY );
+ ImplScalePoint( maEndPt, fScaleX, fScaleY );
+ ImplScaleLineInfo( maLineInfo, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaLineAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maLineInfo == ((MetaLineAction&)rMetaAction).maLineInfo ) &&
+ ( maStartPt == ((MetaLineAction&)rMetaAction).maStartPt ) &&
+ ( maEndPt == ((MetaLineAction&)rMetaAction).maEndPt );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+
+ rOStm << maStartPt << maEndPt; // Version 1
+ rOStm << maLineInfo; // Version 2
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+
+ // Version 1
+ rIStm >> maStartPt >> maEndPt;
+
+ // Version 2
+ if( aCompat.GetVersion() >= 2 )
+ {
+ rIStm >> maLineInfo;
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Rect, META_RECT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaRectAction::MetaRectAction( const Rectangle& rRect ) :
+ MetaAction ( META_RECT_ACTION ),
+ maRect ( rRect )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRectAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawRect( maRect );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaRectAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaRectAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRectAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRectAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaRectAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maRect == ((MetaRectAction&)rMetaAction).maRect;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRectAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRectAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( RoundRect, META_ROUNDRECT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaRoundRectAction::MetaRoundRectAction( const Rectangle& rRect,
+ sal_uInt32 nHorzRound, sal_uInt32 nVertRound ) :
+ MetaAction ( META_ROUNDRECT_ACTION ),
+ maRect ( rRect ),
+ mnHorzRound ( nHorzRound ),
+ mnVertRound ( nVertRound )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRoundRectAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawRect( maRect, mnHorzRound, mnVertRound );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaRoundRectAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaRoundRectAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRoundRectAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRoundRectAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+ mnHorzRound = FRound( mnHorzRound * fabs(fScaleX) );
+ mnVertRound = FRound( mnVertRound * fabs(fScaleY) );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaRoundRectAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRect == ((MetaRoundRectAction&)rMetaAction).maRect ) &&
+ ( mnHorzRound == ((MetaRoundRectAction&)rMetaAction).mnHorzRound ) &&
+ ( mnVertRound == ((MetaRoundRectAction&)rMetaAction).mnVertRound );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRoundRectAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect << mnHorzRound << mnVertRound;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRoundRectAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect >> mnHorzRound >> mnVertRound;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Ellipse, META_ELLIPSE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaEllipseAction::MetaEllipseAction( const Rectangle& rRect ) :
+ MetaAction ( META_ELLIPSE_ACTION ),
+ maRect ( rRect )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEllipseAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawEllipse( maRect );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaEllipseAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaEllipseAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEllipseAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEllipseAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaEllipseAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maRect == ((MetaEllipseAction&)rMetaAction).maRect;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEllipseAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEllipseAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Arc, META_ARC_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaArcAction::MetaArcAction( const Rectangle& rRect,
+ const Point& rStart, const Point& rEnd ) :
+ MetaAction ( META_ARC_ACTION ),
+ maRect ( rRect ),
+ maStartPt ( rStart ),
+ maEndPt ( rEnd )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaArcAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawArc( maRect, maStartPt, maEndPt );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaArcAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaArcAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaArcAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+ maStartPt.Move( nHorzMove, nVertMove );
+ maEndPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaArcAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+ ImplScalePoint( maStartPt, fScaleX, fScaleY );
+ ImplScalePoint( maEndPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaArcAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRect == ((MetaArcAction&)rMetaAction).maRect ) &&
+ ( maStartPt == ((MetaArcAction&)rMetaAction).maStartPt ) &&
+ ( maEndPt == ((MetaArcAction&)rMetaAction).maEndPt );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaArcAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect << maStartPt << maEndPt;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaArcAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect >> maStartPt >> maEndPt;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Pie, META_PIE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaPieAction::MetaPieAction( const Rectangle& rRect,
+ const Point& rStart, const Point& rEnd ) :
+ MetaAction ( META_PIE_ACTION ),
+ maRect ( rRect ),
+ maStartPt ( rStart ),
+ maEndPt ( rEnd )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPieAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawPie( maRect, maStartPt, maEndPt );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPieAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPieAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPieAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+ maStartPt.Move( nHorzMove, nVertMove );
+ maEndPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPieAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+ ImplScalePoint( maStartPt, fScaleX, fScaleY );
+ ImplScalePoint( maEndPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaPieAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRect == ((MetaPieAction&)rMetaAction).maRect ) &&
+ ( maStartPt == ((MetaPieAction&)rMetaAction).maStartPt ) &&
+ ( maEndPt == ((MetaPieAction&)rMetaAction).maEndPt );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPieAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect << maStartPt << maEndPt;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPieAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect >> maStartPt >> maEndPt;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Chord, META_CHORD_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaChordAction::MetaChordAction( const Rectangle& rRect,
+ const Point& rStart, const Point& rEnd ) :
+ MetaAction ( META_CHORD_ACTION ),
+ maRect ( rRect ),
+ maStartPt ( rStart ),
+ maEndPt ( rEnd )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaChordAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawChord( maRect, maStartPt, maEndPt );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaChordAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaChordAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaChordAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+ maStartPt.Move( nHorzMove, nVertMove );
+ maEndPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaChordAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+ ImplScalePoint( maStartPt, fScaleX, fScaleY );
+ ImplScalePoint( maEndPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaChordAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRect == ((MetaChordAction&)rMetaAction).maRect ) &&
+ ( maStartPt == ((MetaChordAction&)rMetaAction).maStartPt ) &&
+ ( maEndPt == ((MetaChordAction&)rMetaAction).maEndPt );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaChordAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect << maStartPt << maEndPt;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaChordAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect >> maStartPt >> maEndPt;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( PolyLine, META_POLYLINE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaPolyLineAction::MetaPolyLineAction( const Polygon& rPoly ) :
+ MetaAction ( META_POLYLINE_ACTION ),
+ maPoly ( rPoly )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaPolyLineAction::MetaPolyLineAction( const Polygon& rPoly, const LineInfo& rLineInfo ) :
+ MetaAction ( META_POLYLINE_ACTION ),
+ maLineInfo ( rLineInfo ),
+ maPoly ( rPoly )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyLineAction::Execute( OutputDevice* pOut )
+{
+ if( maLineInfo.IsDefault() )
+ pOut->DrawPolyLine( maPoly );
+ else
+ pOut->DrawPolyLine( maPoly, maLineInfo );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPolyLineAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPolyLineAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyLineAction::Move( long nHorzMove, long nVertMove )
+{
+ maPoly.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyLineAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoly( maPoly, fScaleX, fScaleY );
+ ImplScaleLineInfo( maLineInfo, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaPolyLineAction::Compare( const MetaAction& rMetaAction ) const
+{
+ sal_Bool bIsEqual = sal_True;;
+ if ( maLineInfo != ((MetaPolyLineAction&)rMetaAction).maLineInfo )
+ bIsEqual = sal_False;
+ else
+ bIsEqual = maPoly.IsEqual(((MetaPolyLineAction&)rMetaAction).maPoly );
+ return bIsEqual;
+
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyLineAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 3, pData );
+
+ Polygon aSimplePoly;
+ maPoly.AdaptiveSubdivide( aSimplePoly );
+
+ rOStm << aSimplePoly; // Version 1
+ rOStm << maLineInfo; // Version 2
+
+ sal_uInt8 bHasPolyFlags = maPoly.HasFlags(); // Version 3
+ rOStm << bHasPolyFlags;
+ if ( bHasPolyFlags )
+ maPoly.Write( rOStm );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyLineAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+
+ // Version 1
+ rIStm >> maPoly;
+
+ // Version 2
+ if( aCompat.GetVersion() >= 2 )
+ rIStm >> maLineInfo;
+ if ( aCompat.GetVersion() >= 3 )
+ {
+ sal_uInt8 bHasPolyFlags;
+ rIStm >> bHasPolyFlags;
+ if ( bHasPolyFlags )
+ maPoly.Read( rIStm );
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Polygon, META_POLYGON_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaPolygonAction::MetaPolygonAction( const Polygon& rPoly ) :
+ MetaAction ( META_POLYGON_ACTION ),
+ maPoly ( rPoly )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolygonAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawPolygon( maPoly );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPolygonAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPolygonAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolygonAction::Move( long nHorzMove, long nVertMove )
+{
+ maPoly.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolygonAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoly( maPoly, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaPolygonAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maPoly.IsEqual(((MetaPolygonAction&)rMetaAction).maPoly );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolygonAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+
+ Polygon aSimplePoly; // Version 1
+ maPoly.AdaptiveSubdivide( aSimplePoly );
+ rOStm << aSimplePoly;
+
+ sal_uInt8 bHasPolyFlags = maPoly.HasFlags(); // Version 2
+ rOStm << bHasPolyFlags;
+ if ( bHasPolyFlags )
+ maPoly.Write( rOStm );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolygonAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+
+ rIStm >> maPoly; // Version 1
+
+ if( aCompat.GetVersion() >= 2 ) // Version 2
+ {
+ sal_uInt8 bHasPolyFlags;
+ rIStm >> bHasPolyFlags;
+ if ( bHasPolyFlags )
+ maPoly.Read( rIStm );
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( PolyPolygon, META_POLYPOLYGON_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaPolyPolygonAction::MetaPolyPolygonAction( const PolyPolygon& rPolyPoly ) :
+ MetaAction ( META_POLYPOLYGON_ACTION ),
+ maPolyPoly ( rPolyPoly )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyPolygonAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawPolyPolygon( maPolyPoly );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPolyPolygonAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPolyPolygonAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyPolygonAction::Move( long nHorzMove, long nVertMove )
+{
+ maPolyPoly.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyPolygonAction::Scale( double fScaleX, double fScaleY )
+{
+ for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ )
+ ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaPolyPolygonAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maPolyPoly.IsEqual(((MetaPolyPolygonAction&)rMetaAction).maPolyPoly );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyPolygonAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+
+ sal_uInt16 nNumberOfComplexPolygons = 0;
+ sal_uInt16 i, nPolyCount = maPolyPoly.Count();
+
+ Polygon aSimplePoly; // Version 1
+ rOStm << nPolyCount;
+ for ( i = 0; i < nPolyCount; i++ )
+ {
+ const Polygon& rPoly = maPolyPoly.GetObject( i );
+ if ( rPoly.HasFlags() )
+ nNumberOfComplexPolygons++;
+ rPoly.AdaptiveSubdivide( aSimplePoly );
+ rOStm << aSimplePoly;
+ }
+
+ rOStm << nNumberOfComplexPolygons; // Version 2
+ for ( i = 0; nNumberOfComplexPolygons && ( i < nPolyCount ); i++ )
+ {
+ const Polygon& rPoly = maPolyPoly.GetObject( i );
+ if ( rPoly.HasFlags() )
+ {
+ rOStm << i;
+ rPoly.Write( rOStm );
+
+ nNumberOfComplexPolygons--;
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPolyPolygonAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maPolyPoly; // Version 1
+
+ if ( aCompat.GetVersion() >= 2 ) // Version 2
+ {
+ sal_uInt16 i, nIndex, nNumberOfComplexPolygons;
+ rIStm >> nNumberOfComplexPolygons;
+ for ( i = 0; i < nNumberOfComplexPolygons; i++ )
+ {
+ rIStm >> nIndex;
+ Polygon aPoly;
+ aPoly.Read( rIStm );
+ maPolyPoly.Replace( aPoly, nIndex );
+ }
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Text, META_TEXT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextAction::MetaTextAction( const Point& rPt, const XubString& rStr,
+ USHORT nIndex, USHORT nLen ) :
+ MetaAction ( META_TEXT_ACTION ),
+ maPt ( rPt ),
+ maStr ( rStr ),
+ mnIndex ( nIndex ),
+ mnLen ( nLen )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawText( maPt, maStr, mnIndex, mnLen );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maPt == ((MetaTextAction&)rMetaAction).maPt ) &&
+ ( maStr == ((MetaTextAction&)rMetaAction).maStr ) &&
+ ( mnIndex == ((MetaTextAction&)rMetaAction).mnIndex ) &&
+ ( mnLen == ((MetaTextAction&)rMetaAction).mnLen );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+ rOStm << maPt;
+ rOStm.WriteByteString( maStr, pData->meActualCharSet );
+ rOStm << mnIndex;
+ rOStm << mnLen;
+
+ sal_uInt16 i, nLen = maStr.Len(); // version 2
+ rOStm << nLen;
+ for ( i = 0; i < nLen; i++ )
+ {
+ sal_Unicode nUni = maStr.GetChar( i );
+ rOStm << nUni;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAction::Read( SvStream& rIStm, ImplMetaReadData* pData )
+{
+ COMPAT( rIStm );
+ rIStm >> maPt;
+ rIStm.ReadByteString( maStr, pData->meActualCharSet );
+ rIStm >> mnIndex;
+ rIStm >> mnLen;
+
+ if ( aCompat.GetVersion() >= 2 ) // Version 2
+ {
+ sal_uInt16 nLen;
+ rIStm >> nLen;
+ sal_Unicode* pBuffer = maStr.AllocBuffer( nLen );
+ while ( nLen-- )
+ rIStm >> *pBuffer++;
+ }
+}
+
+// ========================================================================
+
+MetaTextArrayAction::MetaTextArrayAction() :
+ MetaAction ( META_TEXTARRAY_ACTION ),
+ mpDXAry ( NULL ),
+ mnIndex ( 0 ),
+ mnLen ( 0 )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaTextArrayAction::MetaTextArrayAction( const MetaTextArrayAction& rAction ) :
+ MetaAction ( META_TEXTARRAY_ACTION ),
+ maStartPt ( rAction.maStartPt ),
+ maStr ( rAction.maStr ),
+ mnIndex ( rAction.mnIndex ),
+ mnLen ( rAction.mnLen )
+{
+ if( rAction.mpDXAry )
+ {
+ const ULONG nAryLen = mnLen;
+
+ mpDXAry = new sal_Int32[ nAryLen ];
+ memcpy( mpDXAry, rAction.mpDXAry, nAryLen * sizeof( sal_Int32 ) );
+ }
+ else
+ mpDXAry = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+MetaTextArrayAction::MetaTextArrayAction( const Point& rStartPt,
+ const XubString& rStr,
+ const sal_Int32* pDXAry,
+ USHORT nIndex,
+ USHORT nLen ) :
+ MetaAction ( META_TEXTARRAY_ACTION ),
+ maStartPt ( rStartPt ),
+ maStr ( rStr ),
+ mnIndex ( nIndex ),
+ mnLen ( ( nLen == STRING_LEN ) ? rStr.Len() : nLen )
+{
+ const ULONG nAryLen = pDXAry ? mnLen : 0;
+
+ if( nAryLen )
+ {
+ mpDXAry = new sal_Int32[ nAryLen ];
+ memcpy( mpDXAry, pDXAry, nAryLen * sizeof( sal_Int32 ) );
+ }
+ else
+ mpDXAry = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+MetaTextArrayAction::~MetaTextArrayAction()
+{
+ delete[] mpDXAry;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextArrayAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawTextArray( maStartPt, maStr, mpDXAry, mnIndex, mnLen );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextArrayAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextArrayAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextArrayAction::Move( long nHorzMove, long nVertMove )
+{
+ maStartPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextArrayAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maStartPt, fScaleX, fScaleY );
+
+ if ( mpDXAry && mnLen )
+ {
+ for ( USHORT i = 0, nCount = mnLen; i < nCount; i++ )
+ mpDXAry[ i ] = FRound( mpDXAry[ i ] * fabs(fScaleX) );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextArrayAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maStartPt == ((MetaTextArrayAction&)rMetaAction).maStartPt ) &&
+ ( maStr == ((MetaTextArrayAction&)rMetaAction).maStr ) &&
+ ( mnIndex == ((MetaTextArrayAction&)rMetaAction).mnIndex ) &&
+ ( mnLen == ((MetaTextArrayAction&)rMetaAction).mnLen ) &&
+ ( memcmp( mpDXAry, ((MetaTextArrayAction&)rMetaAction).mpDXAry, mnLen ) == 0 );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextArrayAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ const sal_uInt32 nAryLen = mpDXAry ? mnLen : 0;
+
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+ rOStm << maStartPt;
+ rOStm.WriteByteString( maStr, pData->meActualCharSet );
+ rOStm << mnIndex;
+ rOStm << mnLen;
+ rOStm << nAryLen;
+
+ for( ULONG i = 0UL; i < nAryLen; i++ )
+ rOStm << mpDXAry[ i ];
+
+ sal_uInt16 j, nLen = maStr.Len(); // version 2
+ rOStm << nLen;
+ for ( j = 0; j < nLen; j++ )
+ {
+ sal_Unicode nUni = maStr.GetChar( j );
+ rOStm << nUni;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextArrayAction::Read( SvStream& rIStm, ImplMetaReadData* pData )
+{
+ sal_uInt32 nAryLen;
+
+ delete[] mpDXAry;
+
+ COMPAT( rIStm );
+ rIStm >> maStartPt;
+ rIStm.ReadByteString( maStr, pData->meActualCharSet );
+ rIStm >> mnIndex;
+ rIStm >> mnLen;
+ rIStm >> nAryLen;
+
+ if( nAryLen )
+ {
+ // #i9762#, #106172# Ensure that DX array is at least mnLen entries long
+ const ULONG nIntAryLen( Max(nAryLen, static_cast<sal_uInt32>(mnLen)) );
+ mpDXAry = new sal_Int32[ nIntAryLen ];
+
+ ULONG i;
+ for( i = 0UL; i < nAryLen; i++ )
+ rIStm >> mpDXAry[ i ];
+
+ // #106172# setup remainder
+ for( ; i < nIntAryLen; i++ )
+ mpDXAry[ i ] = 0;
+ }
+ else
+ mpDXAry = NULL;
+
+ if ( aCompat.GetVersion() >= 2 ) // Version 2
+ {
+ sal_uInt16 nLen;
+ rIStm >> nLen;
+ sal_Unicode* pBuffer = maStr.AllocBuffer( nLen );
+ while ( nLen-- )
+ rIStm >> *pBuffer++;
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( StretchText, META_STRETCHTEXT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaStretchTextAction::MetaStretchTextAction( const Point& rPt, sal_uInt32 nWidth,
+ const XubString& rStr,
+ USHORT nIndex, USHORT nLen ) :
+ MetaAction ( META_STRETCHTEXT_ACTION ),
+ maPt ( rPt ),
+ maStr ( rStr ),
+ mnWidth ( nWidth ),
+ mnIndex ( nIndex ),
+ mnLen ( nLen )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaStretchTextAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawStretchText( maPt, mnWidth, maStr, mnIndex, mnLen );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaStretchTextAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaStretchTextAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaStretchTextAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaStretchTextAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPt, fScaleX, fScaleY );
+ mnWidth = (ULONG)FRound( mnWidth * fabs(fScaleX) );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaStretchTextAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maPt == ((MetaStretchTextAction&)rMetaAction).maPt ) &&
+ ( maStr == ((MetaStretchTextAction&)rMetaAction).maStr ) &&
+ ( mnWidth == ((MetaStretchTextAction&)rMetaAction).mnWidth ) &&
+ ( mnIndex == ((MetaStretchTextAction&)rMetaAction).mnIndex ) &&
+ ( mnLen == ((MetaStretchTextAction&)rMetaAction).mnLen );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaStretchTextAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+ rOStm << maPt;
+ rOStm.WriteByteString( maStr, pData->meActualCharSet );
+ rOStm << mnWidth;
+ rOStm << mnIndex;
+ rOStm << mnLen;
+
+ sal_uInt16 i, nLen = maStr.Len(); // version 2
+ rOStm << nLen;
+ for ( i = 0; i < nLen; i++ )
+ {
+ sal_Unicode nUni = maStr.GetChar( i );
+ rOStm << nUni;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaStretchTextAction::Read( SvStream& rIStm, ImplMetaReadData* pData )
+{
+ COMPAT( rIStm );
+ rIStm >> maPt;
+ rIStm.ReadByteString( maStr, pData->meActualCharSet );
+ rIStm >> mnWidth;
+ rIStm >> mnIndex;
+ rIStm >> mnLen;
+
+ if ( aCompat.GetVersion() >= 2 ) // Version 2
+ {
+ sal_uInt16 nLen;
+ rIStm >> nLen;
+ sal_Unicode* pBuffer = maStr.AllocBuffer( nLen );
+ while ( nLen-- )
+ rIStm >> *pBuffer++;
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( TextRect, META_TEXTRECT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextRectAction::MetaTextRectAction( const Rectangle& rRect,
+ const XubString& rStr, USHORT nStyle ) :
+ MetaAction ( META_TEXTRECT_ACTION ),
+ maRect ( rRect ),
+ maStr ( rStr ),
+ mnStyle ( nStyle )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextRectAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawText( maRect, maStr, mnStyle );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextRectAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextRectAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextRectAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextRectAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextRectAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRect == ((MetaTextRectAction&)rMetaAction).maRect ) &&
+ ( maStr == ((MetaTextRectAction&)rMetaAction).maStr ) &&
+ ( mnStyle == ((MetaTextRectAction&)rMetaAction).mnStyle );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextRectAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+ rOStm << maRect;
+ rOStm.WriteByteString( maStr, pData->meActualCharSet );
+ rOStm << mnStyle;
+
+ sal_uInt16 i, nLen = maStr.Len(); // version 2
+ rOStm << nLen;
+ for ( i = 0; i < nLen; i++ )
+ {
+ sal_Unicode nUni = maStr.GetChar( i );
+ rOStm << nUni;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextRectAction::Read( SvStream& rIStm, ImplMetaReadData* pData )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect;
+ rIStm.ReadByteString( maStr, pData->meActualCharSet );
+ rIStm >> mnStyle;
+
+ if ( aCompat.GetVersion() >= 2 ) // Version 2
+ {
+ sal_uInt16 nLen;
+ rIStm >> nLen;
+ sal_Unicode* pBuffer = maStr.AllocBuffer( nLen );
+ while ( nLen-- )
+ rIStm >> *pBuffer++;
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( TextLine, META_TEXTLINE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextLineAction::MetaTextLineAction( const Point& rPos, long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ FontUnderline eOverline ) :
+ MetaAction ( META_TEXTLINE_ACTION ),
+ maPos ( rPos ),
+ mnWidth ( nWidth ),
+ meStrikeout ( eStrikeout ),
+ meUnderline ( eUnderline ),
+ meOverline ( eOverline )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawTextLine( maPos, mnWidth, meStrikeout, meUnderline, meOverline );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextLineAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*)new MetaTextLineAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineAction::Move( long nHorzMove, long nVertMove )
+{
+ maPos.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPos, fScaleX, fScaleY );
+ mnWidth = FRound( mnWidth * fabs(fScaleX) );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextLineAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maPos == ((MetaTextLineAction&)rMetaAction).maPos ) &&
+ ( mnWidth == ((MetaTextLineAction&)rMetaAction).mnWidth ) &&
+ ( meStrikeout == ((MetaTextLineAction&)rMetaAction).meStrikeout ) &&
+ ( meUnderline == ((MetaTextLineAction&)rMetaAction).meUnderline ) &&
+ ( meOverline == ((MetaTextLineAction&)rMetaAction).meOverline );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 2, pData );
+
+ rOStm << maPos;
+ rOStm << mnWidth;
+ rOStm << static_cast<sal_uInt32>(meStrikeout);
+ rOStm << static_cast<sal_uInt32>(meUnderline);
+ // new in version 2
+ rOStm << static_cast<sal_uInt32>(meOverline);
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+
+ sal_uInt32 nTemp;
+ rIStm >> maPos;
+ rIStm >> mnWidth;
+ rIStm >> nTemp;
+ meStrikeout = (FontStrikeout)nTemp;
+ rIStm >> nTemp;
+ meUnderline = (FontUnderline)nTemp;
+ if ( aCompat.GetVersion() >= 2 ) {
+ rIStm >> nTemp;
+ meUnderline = (FontUnderline)nTemp;
+ }
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Bmp, META_BMP_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaBmpAction::MetaBmpAction( const Point& rPt, const Bitmap& rBmp ) :
+ MetaAction ( META_BMP_ACTION ),
+ maBmp ( rBmp ),
+ maPt ( rPt )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawBitmap( maPt, maBmp );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaBmpAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaBmpAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaBmpAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maBmp.IsEqual(((MetaBmpAction&)rMetaAction).maBmp ) &&
+ ( maPt == ((MetaBmpAction&)rMetaAction).maPt );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmp )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmp << maPt;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmp >> maPt;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( BmpScale, META_BMPSCALE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaBmpScaleAction::MetaBmpScaleAction( const Point& rPt, const Size& rSz,
+ const Bitmap& rBmp ) :
+ MetaAction ( META_BMPSCALE_ACTION ),
+ maBmp ( rBmp ),
+ maPt ( rPt ),
+ maSz ( rSz )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScaleAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawBitmap( maPt, maSz, maBmp );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaBmpScaleAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaBmpScaleAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScaleAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScaleAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maPt, maSz);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maPt = aRectangle.TopLeft();
+ maSz = aRectangle.GetSize();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaBmpScaleAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmp.IsEqual(((MetaBmpScaleAction&)rMetaAction).maBmp )) &&
+ ( maPt == ((MetaBmpScaleAction&)rMetaAction).maPt ) &&
+ ( maSz == ((MetaBmpScaleAction&)rMetaAction).maSz );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScaleAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmp )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmp << maPt << maSz;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScaleAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmp >> maPt >> maSz;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( BmpScalePart, META_BMPSCALEPART_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaBmpScalePartAction::MetaBmpScalePartAction( const Point& rDstPt, const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const Bitmap& rBmp ) :
+ MetaAction ( META_BMPSCALEPART_ACTION ),
+ maBmp ( rBmp ),
+ maDstPt ( rDstPt ),
+ maDstSz ( rDstSz ),
+ maSrcPt ( rSrcPt ),
+ maSrcSz ( rSrcSz )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScalePartAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawBitmap( maDstPt, maDstSz, maSrcPt, maSrcSz, maBmp );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaBmpScalePartAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaBmpScalePartAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScalePartAction::Move( long nHorzMove, long nVertMove )
+{
+ maDstPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScalePartAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maDstPt, maDstSz);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maDstPt = aRectangle.TopLeft();
+ maDstSz = aRectangle.GetSize();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaBmpScalePartAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmp.IsEqual(((MetaBmpScalePartAction&)rMetaAction).maBmp )) &&
+ ( maDstPt == ((MetaBmpScalePartAction&)rMetaAction).maDstPt ) &&
+ ( maDstSz == ((MetaBmpScalePartAction&)rMetaAction).maDstSz ) &&
+ ( maSrcPt == ((MetaBmpScalePartAction&)rMetaAction).maSrcPt ) &&
+ ( maSrcSz == ((MetaBmpScalePartAction&)rMetaAction).maSrcSz );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScalePartAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmp )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmp << maDstPt << maDstSz << maSrcPt << maSrcSz;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpScalePartAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmp >> maDstPt >> maDstSz >> maSrcPt >> maSrcSz;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( BmpEx, META_BMPEX_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaBmpExAction::MetaBmpExAction( const Point& rPt, const BitmapEx& rBmpEx ) :
+ MetaAction ( META_BMPEX_ACTION ),
+ maBmpEx ( rBmpEx ),
+ maPt ( rPt )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawBitmapEx( maPt, maBmpEx );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaBmpExAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaBmpExAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaBmpExAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmpEx.IsEqual(((MetaBmpExAction&)rMetaAction).maBmpEx )) &&
+ ( maPt == ((MetaBmpExAction&)rMetaAction).maPt );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmpEx.GetBitmap() )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmpEx << maPt;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmpEx >> maPt;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( BmpExScale, META_BMPEXSCALE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaBmpExScaleAction::MetaBmpExScaleAction( const Point& rPt, const Size& rSz,
+ const BitmapEx& rBmpEx ) :
+ MetaAction ( META_BMPEXSCALE_ACTION ),
+ maBmpEx ( rBmpEx ),
+ maPt ( rPt ),
+ maSz ( rSz )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScaleAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawBitmapEx( maPt, maSz, maBmpEx );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaBmpExScaleAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaBmpExScaleAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScaleAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScaleAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maPt, maSz);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maPt = aRectangle.TopLeft();
+ maSz = aRectangle.GetSize();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaBmpExScaleAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmpEx.IsEqual(((MetaBmpExScaleAction&)rMetaAction).maBmpEx )) &&
+ ( maPt == ((MetaBmpExScaleAction&)rMetaAction).maPt ) &&
+ ( maSz == ((MetaBmpExScaleAction&)rMetaAction).maSz );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScaleAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmpEx.GetBitmap() )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmpEx << maPt << maSz;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScaleAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmpEx >> maPt >> maSz;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( BmpExScalePart, META_BMPEXSCALEPART_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaBmpExScalePartAction::MetaBmpExScalePartAction( const Point& rDstPt, const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const BitmapEx& rBmpEx ) :
+ MetaAction ( META_BMPEXSCALEPART_ACTION ),
+ maBmpEx ( rBmpEx ),
+ maDstPt ( rDstPt ),
+ maDstSz ( rDstSz ),
+ maSrcPt ( rSrcPt ),
+ maSrcSz ( rSrcSz )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScalePartAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawBitmapEx( maDstPt, maDstSz, maSrcPt, maSrcSz, maBmpEx );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaBmpExScalePartAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaBmpExScalePartAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScalePartAction::Move( long nHorzMove, long nVertMove )
+{
+ maDstPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScalePartAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maDstPt, maDstSz);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maDstPt = aRectangle.TopLeft();
+ maDstSz = aRectangle.GetSize();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaBmpExScalePartAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmpEx.IsEqual(((MetaBmpExScalePartAction&)rMetaAction).maBmpEx )) &&
+ ( maDstPt == ((MetaBmpExScalePartAction&)rMetaAction).maDstPt ) &&
+ ( maDstSz == ((MetaBmpExScalePartAction&)rMetaAction).maDstSz ) &&
+ ( maSrcPt == ((MetaBmpExScalePartAction&)rMetaAction).maSrcPt ) &&
+ ( maSrcSz == ((MetaBmpExScalePartAction&)rMetaAction).maSrcSz );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScalePartAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmpEx.GetBitmap() )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmpEx << maDstPt << maDstSz << maSrcPt << maSrcSz;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaBmpExScalePartAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmpEx >> maDstPt >> maDstSz >> maSrcPt >> maSrcSz;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Mask, META_MASK_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaMaskAction::MetaMaskAction( const Point& rPt,
+ const Bitmap& rBmp,
+ const Color& rColor ) :
+ MetaAction ( META_MASK_ACTION ),
+ maBmp ( rBmp ),
+ maColor ( rColor ),
+ maPt ( rPt )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawMask( maPt, maBmp, maColor );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaMaskAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaMaskAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScalePoint( maPt, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaMaskAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmp.IsEqual(((MetaMaskAction&)rMetaAction).maBmp )) &&
+ ( maColor == ((MetaMaskAction&)rMetaAction).maColor ) &&
+ ( maPt == ((MetaMaskAction&)rMetaAction).maPt );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmp )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmp << maPt;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmp >> maPt;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( MaskScale, META_MASKSCALE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaMaskScaleAction::MetaMaskScaleAction( const Point& rPt, const Size& rSz,
+ const Bitmap& rBmp,
+ const Color& rColor ) :
+ MetaAction ( META_MASKSCALE_ACTION ),
+ maBmp ( rBmp ),
+ maColor ( rColor ),
+ maPt ( rPt ),
+ maSz ( rSz )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScaleAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawMask( maPt, maSz, maBmp, maColor );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaMaskScaleAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaMaskScaleAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScaleAction::Move( long nHorzMove, long nVertMove )
+{
+ maPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScaleAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maPt, maSz);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maPt = aRectangle.TopLeft();
+ maSz = aRectangle.GetSize();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaMaskScaleAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmp.IsEqual(((MetaMaskScaleAction&)rMetaAction).maBmp )) &&
+ ( maColor == ((MetaMaskScaleAction&)rMetaAction).maColor ) &&
+ ( maPt == ((MetaMaskScaleAction&)rMetaAction).maPt ) &&
+ ( maSz == ((MetaMaskScaleAction&)rMetaAction).maSz );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScaleAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmp )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmp << maPt << maSz;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScaleAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmp >> maPt >> maSz;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( MaskScalePart, META_MASKSCALEPART_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaMaskScalePartAction::MetaMaskScalePartAction( const Point& rDstPt, const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const Bitmap& rBmp,
+ const Color& rColor ) :
+ MetaAction ( META_MASKSCALEPART_ACTION ),
+ maBmp ( rBmp ),
+ maColor ( rColor ),
+ maDstPt ( rDstPt ),
+ maDstSz ( rDstSz ),
+ maSrcPt ( rSrcPt ),
+ maSrcSz ( rSrcSz )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScalePartAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawMask( maDstPt, maDstSz, maSrcPt, maSrcSz, maBmp, maColor );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaMaskScalePartAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaMaskScalePartAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScalePartAction::Move( long nHorzMove, long nVertMove )
+{
+ maDstPt.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScalePartAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maDstPt, maDstSz);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maDstPt = aRectangle.TopLeft();
+ maDstSz = aRectangle.GetSize();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaMaskScalePartAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maBmp.IsEqual(((MetaMaskScalePartAction&)rMetaAction).maBmp )) &&
+ ( maColor == ((MetaMaskScalePartAction&)rMetaAction).maColor ) &&
+ ( maDstPt == ((MetaMaskScalePartAction&)rMetaAction).maDstPt ) &&
+ ( maDstSz == ((MetaMaskScalePartAction&)rMetaAction).maDstSz ) &&
+ ( maSrcPt == ((MetaMaskScalePartAction&)rMetaAction).maSrcPt ) &&
+ ( maSrcSz == ((MetaMaskScalePartAction&)rMetaAction).maSrcSz );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScalePartAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ if( !!maBmp )
+ {
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maBmp;
+ maColor.Write( rOStm, TRUE );
+ rOStm << maDstPt << maDstSz << maSrcPt << maSrcSz;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMaskScalePartAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maBmp;
+ maColor.Read( rIStm, TRUE );
+ rIStm >> maDstPt >> maDstSz >> maSrcPt >> maSrcSz;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Gradient, META_GRADIENT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaGradientAction::MetaGradientAction( const Rectangle& rRect, const Gradient& rGradient ) :
+ MetaAction ( META_GRADIENT_ACTION ),
+ maRect ( rRect ),
+ maGradient ( rGradient )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawGradient( maRect, maGradient );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaGradientAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaGradientAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaGradientAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRect == ((MetaGradientAction&)rMetaAction).maRect ) &&
+ ( maGradient == ((MetaGradientAction&)rMetaAction).maGradient );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect << maGradient;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect >> maGradient;
+}
+
+// ========================================================================
+
+MetaGradientExAction::MetaGradientExAction() :
+ MetaAction ( META_GRADIENTEX_ACTION )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaGradientExAction::MetaGradientExAction( const PolyPolygon& rPolyPoly, const Gradient& rGradient ) :
+ MetaAction ( META_GRADIENTEX_ACTION ),
+ maPolyPoly ( rPolyPoly ),
+ maGradient ( rGradient )
+{
+}
+
+// ------------------------------------------------------------------------
+
+MetaGradientExAction::~MetaGradientExAction()
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientExAction::Execute( OutputDevice* pOut )
+{
+ if( pOut->GetConnectMetaFile() )
+ pOut->GetConnectMetaFile()->AddAction( Clone() );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaGradientExAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaGradientExAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientExAction::Move( long nHorzMove, long nVertMove )
+{
+ maPolyPoly.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientExAction::Scale( double fScaleX, double fScaleY )
+{
+ for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ )
+ ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaGradientExAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maPolyPoly == ((MetaGradientExAction&)rMetaAction).maPolyPoly ) &&
+ ( maGradient == ((MetaGradientExAction&)rMetaAction).maGradient );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientExAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+
+ // #i105373# see comment at MetaTransparentAction::Write
+ PolyPolygon aNoCurvePolyPolygon;
+ maPolyPoly.AdaptiveSubdivide(aNoCurvePolyPolygon);
+
+ rOStm << aNoCurvePolyPolygon;
+ rOStm << maGradient;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaGradientExAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maPolyPoly >> maGradient;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Hatch, META_HATCH_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaHatchAction::MetaHatchAction( const PolyPolygon& rPolyPoly, const Hatch& rHatch ) :
+ MetaAction ( META_HATCH_ACTION ),
+ maPolyPoly ( rPolyPoly ),
+ maHatch ( rHatch )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaHatchAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawHatch( maPolyPoly, maHatch );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaHatchAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaHatchAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaHatchAction::Move( long nHorzMove, long nVertMove )
+{
+ maPolyPoly.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaHatchAction::Scale( double fScaleX, double fScaleY )
+{
+ for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ )
+ ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaHatchAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maPolyPoly == ((MetaHatchAction&)rMetaAction).maPolyPoly ) &&
+ ( maHatch == ((MetaHatchAction&)rMetaAction).maHatch );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaHatchAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+
+ // #i105373# see comment at MetaTransparentAction::Write
+ PolyPolygon aNoCurvePolyPolygon;
+ maPolyPoly.AdaptiveSubdivide(aNoCurvePolyPolygon);
+
+ rOStm << aNoCurvePolyPolygon;
+ rOStm << maHatch;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaHatchAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maPolyPoly >> maHatch;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Wallpaper, META_WALLPAPER_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaWallpaperAction::MetaWallpaperAction( const Rectangle& rRect,
+ const Wallpaper& rPaper ) :
+ MetaAction ( META_WALLPAPER_ACTION ),
+ maRect ( rRect ),
+ maWallpaper ( rPaper )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaWallpaperAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawWallpaper( maRect, maWallpaper );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaWallpaperAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaWallpaperAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaWallpaperAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaWallpaperAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaWallpaperAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRect == ((MetaWallpaperAction&)rMetaAction).maRect ) &&
+ ( maWallpaper == ((MetaWallpaperAction&)rMetaAction).maWallpaper );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaWallpaperAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maWallpaper;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaWallpaperAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maWallpaper;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( ClipRegion, META_CLIPREGION_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaClipRegionAction::MetaClipRegionAction( const Region& rRegion, BOOL bClip ) :
+ MetaAction ( META_CLIPREGION_ACTION ),
+ maRegion ( rRegion ),
+ mbClip ( bClip )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaClipRegionAction::Execute( OutputDevice* pOut )
+{
+ if( mbClip )
+ pOut->SetClipRegion( maRegion );
+ else
+ pOut->SetClipRegion();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaClipRegionAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaClipRegionAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaClipRegionAction::Move( long nHorzMove, long nVertMove )
+{
+ maRegion.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaClipRegionAction::Scale( double fScaleX, double fScaleY )
+{
+ maRegion.Scale( fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaClipRegionAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRegion == ((MetaClipRegionAction&)rMetaAction).maRegion ) &&
+ ( mbClip == ((MetaClipRegionAction&)rMetaAction).mbClip );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRegion << mbClip;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRegion >> mbClip;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( ISectRectClipRegion, META_ISECTRECTCLIPREGION_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaISectRectClipRegionAction::MetaISectRectClipRegionAction( const Rectangle& rRect ) :
+ MetaAction ( META_ISECTRECTCLIPREGION_ACTION ),
+ maRect ( rRect )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRectClipRegionAction::Execute( OutputDevice* pOut )
+{
+ pOut->IntersectClipRegion( maRect );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaISectRectClipRegionAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaISectRectClipRegionAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRectClipRegionAction::Move( long nHorzMove, long nVertMove )
+{
+ maRect.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRectClipRegionAction::Scale( double fScaleX, double fScaleY )
+{
+ ImplScaleRect( maRect, fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaISectRectClipRegionAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maRect == ((MetaISectRectClipRegionAction&)rMetaAction).maRect;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRectClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRect;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRectClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRect;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( ISectRegionClipRegion, META_ISECTREGIONCLIPREGION_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaISectRegionClipRegionAction::MetaISectRegionClipRegionAction( const Region& rRegion ) :
+ MetaAction ( META_ISECTREGIONCLIPREGION_ACTION ),
+ maRegion ( rRegion )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRegionClipRegionAction::Execute( OutputDevice* pOut )
+{
+ pOut->IntersectClipRegion( maRegion );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaISectRegionClipRegionAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaISectRegionClipRegionAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRegionClipRegionAction::Move( long nHorzMove, long nVertMove )
+{
+ maRegion.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRegionClipRegionAction::Scale( double fScaleX, double fScaleY )
+{
+ maRegion.Scale( fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaISectRegionClipRegionAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maRegion == ((MetaISectRegionClipRegionAction&)rMetaAction).maRegion;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRegionClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRegion;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaISectRegionClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRegion;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( MoveClipRegion, META_MOVECLIPREGION_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaMoveClipRegionAction::MetaMoveClipRegionAction( long nHorzMove, long nVertMove ) :
+ MetaAction ( META_MOVECLIPREGION_ACTION ),
+ mnHorzMove ( nHorzMove ),
+ mnVertMove ( nVertMove )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMoveClipRegionAction::Execute( OutputDevice* pOut )
+{
+ pOut->MoveClipRegion( mnHorzMove, mnVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaMoveClipRegionAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaMoveClipRegionAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMoveClipRegionAction::Scale( double fScaleX, double fScaleY )
+{
+ mnHorzMove = FRound( mnHorzMove * fScaleX );
+ mnVertMove = FRound( mnVertMove * fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaMoveClipRegionAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( mnHorzMove == ((MetaMoveClipRegionAction&)rMetaAction).mnHorzMove ) &&
+ ( mnVertMove == ((MetaMoveClipRegionAction&)rMetaAction).mnVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMoveClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << mnHorzMove << mnVertMove;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMoveClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> mnHorzMove >> mnVertMove;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( LineColor, META_LINECOLOR_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaLineColorAction::MetaLineColorAction( const Color& rColor, BOOL bSet ) :
+ MetaAction ( META_LINECOLOR_ACTION ),
+ maColor ( rColor ),
+ mbSet ( bSet )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineColorAction::Execute( OutputDevice* pOut )
+{
+ if( mbSet )
+ pOut->SetLineColor( maColor );
+ else
+ pOut->SetLineColor();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaLineColorAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaLineColorAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaLineColorAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maColor == ((MetaLineColorAction&)rMetaAction).maColor ) &&
+ ( mbSet == ((MetaLineColorAction&)rMetaAction).mbSet );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ maColor.Write( rOStm, TRUE );
+ rOStm << mbSet;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLineColorAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ maColor.Read( rIStm, TRUE );
+ rIStm >> mbSet;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( FillColor, META_FILLCOLOR_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaFillColorAction::MetaFillColorAction( const Color& rColor, BOOL bSet ) :
+ MetaAction ( META_FILLCOLOR_ACTION ),
+ maColor ( rColor ),
+ mbSet ( bSet )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFillColorAction::Execute( OutputDevice* pOut )
+{
+ if( mbSet )
+ pOut->SetFillColor( maColor );
+ else
+ pOut->SetFillColor();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaFillColorAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaFillColorAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaFillColorAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maColor == ((MetaFillColorAction&)rMetaAction).maColor ) &&
+ ( mbSet == ((MetaFillColorAction&)rMetaAction).mbSet );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFillColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ maColor.Write( rOStm, TRUE );
+ rOStm << mbSet;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFillColorAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ maColor.Read( rIStm, TRUE );
+ rIStm >> mbSet;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( TextColor, META_TEXTCOLOR_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextColorAction::MetaTextColorAction( const Color& rColor ) :
+ MetaAction ( META_TEXTCOLOR_ACTION ),
+ maColor ( rColor )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextColorAction::Execute( OutputDevice* pOut )
+{
+ pOut->SetTextColor( maColor );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextColorAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextColorAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextColorAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maColor == ((MetaTextColorAction&)rMetaAction).maColor;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ maColor.Write( rOStm, TRUE );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextColorAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ maColor.Read( rIStm, TRUE );
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( TextFillColor, META_TEXTFILLCOLOR_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextFillColorAction::MetaTextFillColorAction( const Color& rColor, BOOL bSet ) :
+ MetaAction ( META_TEXTFILLCOLOR_ACTION ),
+ maColor ( rColor ),
+ mbSet ( bSet )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextFillColorAction::Execute( OutputDevice* pOut )
+{
+ if( mbSet )
+ pOut->SetTextFillColor( maColor );
+ else
+ pOut->SetTextFillColor();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextFillColorAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextFillColorAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextFillColorAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maColor == ((MetaTextFillColorAction&)rMetaAction).maColor ) &&
+ ( mbSet == ((MetaTextFillColorAction&)rMetaAction).mbSet );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextFillColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ maColor.Write( rOStm, TRUE );
+ rOStm << mbSet;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextFillColorAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ maColor.Read( rIStm, TRUE );
+ rIStm >> mbSet;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( TextLineColor, META_TEXTLINECOLOR_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextLineColorAction::MetaTextLineColorAction( const Color& rColor, BOOL bSet ) :
+ MetaAction ( META_TEXTLINECOLOR_ACTION ),
+ maColor ( rColor ),
+ mbSet ( bSet )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineColorAction::Execute( OutputDevice* pOut )
+{
+ if( mbSet )
+ pOut->SetTextLineColor( maColor );
+ else
+ pOut->SetTextLineColor();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextLineColorAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextLineColorAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextLineColorAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maColor == ((MetaTextLineColorAction&)rMetaAction).maColor ) &&
+ ( mbSet == ((MetaTextLineColorAction&)rMetaAction).mbSet );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ maColor.Write( rOStm, TRUE );
+ rOStm << mbSet;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLineColorAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ maColor.Read( rIStm, TRUE );
+ rIStm >> mbSet;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( OverlineColor, META_OVERLINECOLOR_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaOverlineColorAction::MetaOverlineColorAction( const Color& rColor, BOOL bSet ) :
+ MetaAction ( META_OVERLINECOLOR_ACTION ),
+ maColor ( rColor ),
+ mbSet ( bSet )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaOverlineColorAction::Execute( OutputDevice* pOut )
+{
+ if( mbSet )
+ pOut->SetOverlineColor( maColor );
+ else
+ pOut->SetOverlineColor();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaOverlineColorAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaOverlineColorAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaOverlineColorAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maColor == ((MetaOverlineColorAction&)rMetaAction).maColor ) &&
+ ( mbSet == ((MetaOverlineColorAction&)rMetaAction).mbSet );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaOverlineColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ maColor.Write( rOStm, TRUE );
+ rOStm << mbSet;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaOverlineColorAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ maColor.Read( rIStm, TRUE );
+ rIStm >> mbSet;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( TextAlign, META_TEXTALIGN_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextAlignAction::MetaTextAlignAction( TextAlign aAlign ) :
+ MetaAction ( META_TEXTALIGN_ACTION ),
+ maAlign ( aAlign )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAlignAction::Execute( OutputDevice* pOut )
+{
+ pOut->SetTextAlign( maAlign );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextAlignAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextAlignAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextAlignAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maAlign == ((MetaTextAlignAction&)rMetaAction).maAlign;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAlignAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << (UINT16) maAlign;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextAlignAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ UINT16 nTmp16;
+
+ COMPAT( rIStm );
+ rIStm >> nTmp16; maAlign = (TextAlign) nTmp16;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( MapMode, META_MAPMODE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaMapModeAction::MetaMapModeAction( const MapMode& rMapMode ) :
+ MetaAction ( META_MAPMODE_ACTION ),
+ maMapMode ( rMapMode )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMapModeAction::Execute( OutputDevice* pOut )
+{
+ pOut->SetMapMode( maMapMode );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaMapModeAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaMapModeAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMapModeAction::Scale( double fScaleX, double fScaleY )
+{
+ Point aPoint( maMapMode.GetOrigin() );
+
+ ImplScalePoint( aPoint, fScaleX, fScaleY );
+ maMapMode.SetOrigin( aPoint );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaMapModeAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maMapMode == ((MetaMapModeAction&)rMetaAction).maMapMode;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMapModeAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maMapMode;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaMapModeAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maMapMode;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Font, META_FONT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaFontAction::MetaFontAction( const Font& rFont ) :
+ MetaAction ( META_FONT_ACTION ),
+ maFont ( rFont )
+{
+ // #96876: because RTL_TEXTENCODING_SYMBOL is often set at the StarSymbol font,
+ // we change the textencoding to RTL_TEXTENCODING_UNICODE here, which seems
+ // to be the right way; changing the textencoding at other sources
+ // is too dangerous at the moment
+ if( ( ( maFont.GetName().SearchAscii( "StarSymbol" ) != STRING_NOTFOUND )
+ || ( maFont.GetName().SearchAscii( "OpenSymbol" ) != STRING_NOTFOUND ) )
+ && ( maFont.GetCharSet() != RTL_TEXTENCODING_UNICODE ) )
+ {
+ maFont.SetCharSet( RTL_TEXTENCODING_UNICODE );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFontAction::Execute( OutputDevice* pOut )
+{
+ pOut->SetFont( maFont );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaFontAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaFontAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFontAction::Scale( double fScaleX, double fScaleY )
+{
+ const Size aSize(
+ FRound(maFont.GetSize().Width() * fabs(fScaleX)),
+ FRound(maFont.GetSize().Height() * fabs(fScaleY)));
+ maFont.SetSize( aSize );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaFontAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return maFont == ((MetaFontAction&)rMetaAction).maFont;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFontAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maFont;
+ pData->meActualCharSet = maFont.GetCharSet();
+ if ( pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW )
+ pData->meActualCharSet = gsl_getSystemTextEncoding();
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFontAction::Read( SvStream& rIStm, ImplMetaReadData* pData )
+{
+ COMPAT( rIStm );
+ rIStm >> maFont;
+ pData->meActualCharSet = maFont.GetCharSet();
+ if ( pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW )
+ pData->meActualCharSet = gsl_getSystemTextEncoding();
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Push, META_PUSH_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaPushAction::MetaPushAction( USHORT nFlags ) :
+ MetaAction ( META_PUSH_ACTION ),
+ mnFlags ( nFlags )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPushAction::Execute( OutputDevice* pOut )
+{
+ pOut->Push( mnFlags );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPushAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPushAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaPushAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return mnFlags == ((MetaPushAction&)rMetaAction).mnFlags;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPushAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << mnFlags;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPushAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> mnFlags;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Pop, META_POP_ACTION )
+
+// ------------------------------------------------------------------------
+
+void MetaPopAction::Execute( OutputDevice* pOut )
+{
+ pOut->Pop();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaPopAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaPopAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPopAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaPopAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( RasterOp, META_RASTEROP_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaRasterOpAction::MetaRasterOpAction( RasterOp eRasterOp ) :
+ MetaAction ( META_RASTEROP_ACTION ),
+ meRasterOp ( eRasterOp )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRasterOpAction::Execute( OutputDevice* pOut )
+{
+ pOut->SetRasterOp( meRasterOp );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaRasterOpAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaRasterOpAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaRasterOpAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return meRasterOp == ((MetaRasterOpAction&)rMetaAction).meRasterOp;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRasterOpAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << (UINT16) meRasterOp;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRasterOpAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ UINT16 nTmp16;
+
+ COMPAT( rIStm );
+ rIStm >> nTmp16; meRasterOp = (RasterOp) nTmp16;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( Transparent, META_TRANSPARENT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTransparentAction::MetaTransparentAction( const PolyPolygon& rPolyPoly, USHORT nTransPercent ) :
+ MetaAction ( META_TRANSPARENT_ACTION ),
+ maPolyPoly ( rPolyPoly ),
+ mnTransPercent ( nTransPercent )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTransparentAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawTransparent( maPolyPoly, mnTransPercent );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTransparentAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTransparentAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTransparentAction::Move( long nHorzMove, long nVertMove )
+{
+ maPolyPoly.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTransparentAction::Scale( double fScaleX, double fScaleY )
+{
+ for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ )
+ ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTransparentAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maPolyPoly == ((MetaTransparentAction&)rMetaAction).maPolyPoly ) &&
+ ( mnTransPercent == ((MetaTransparentAction&)rMetaAction).mnTransPercent );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTransparentAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+
+ // #i105373# The PolyPolygon in this action may be a curve; this
+ // was ignored until now what is an error. To make older office
+ // versions work with MetaFiles, i opt for applying AdaptiveSubdivide
+ // to the PolyPoylgon.
+ // The alternative would be to really write the curve information
+ // like in MetaPolyPolygonAction::Write (where someone extended it
+ // correctly, but not here :-( ).
+ // The golden solution would be to combine both, but i think it's
+ // not necessary; a good subdivision will be sufficient.
+ PolyPolygon aNoCurvePolyPolygon;
+ maPolyPoly.AdaptiveSubdivide(aNoCurvePolyPolygon);
+
+ rOStm << aNoCurvePolyPolygon;
+ rOStm << mnTransPercent;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTransparentAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maPolyPoly;
+ rIStm >> mnTransPercent;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( FloatTransparent, META_FLOATTRANSPARENT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaFloatTransparentAction::MetaFloatTransparentAction( const GDIMetaFile& rMtf, const Point& rPos,
+ const Size& rSize, const Gradient& rGradient ) :
+ MetaAction ( META_FLOATTRANSPARENT_ACTION ),
+ maMtf ( rMtf ),
+ maPoint ( rPos ),
+ maSize ( rSize ),
+ maGradient ( rGradient )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFloatTransparentAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawTransparent( maMtf, maPoint, maSize, maGradient );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaFloatTransparentAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaFloatTransparentAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFloatTransparentAction::Move( long nHorzMove, long nVertMove )
+{
+ maPoint.Move( nHorzMove, nVertMove );
+ maMtf.Move(nHorzMove, nVertMove);
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFloatTransparentAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maPoint, maSize);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maPoint = aRectangle.TopLeft();
+ maSize = aRectangle.GetSize();
+ maMtf.Scale(fScaleX, fScaleY);
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaFloatTransparentAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maMtf == ((MetaFloatTransparentAction&)rMetaAction).maMtf ) &&
+ ( maPoint == ((MetaFloatTransparentAction&)rMetaAction).maPoint ) &&
+ ( maSize == ((MetaFloatTransparentAction&)rMetaAction).maSize ) &&
+ ( maGradient == ((MetaFloatTransparentAction&)rMetaAction).maGradient );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFloatTransparentAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+
+ maMtf.Write( rOStm );
+ rOStm << maPoint << maSize << maGradient;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaFloatTransparentAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maMtf >> maPoint >> maSize >> maGradient;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( EPS, META_EPS_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaEPSAction::MetaEPSAction( const Point& rPoint, const Size& rSize,
+ const GfxLink& rGfxLink, const GDIMetaFile& rSubst ) :
+ MetaAction ( META_EPS_ACTION ),
+ maGfxLink ( rGfxLink ),
+ maSubst ( rSubst ),
+ maPoint ( rPoint ),
+ maSize ( rSize )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEPSAction::Execute( OutputDevice* pOut )
+{
+ pOut->DrawEPS( maPoint, maSize, maGfxLink, &maSubst );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaEPSAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaEPSAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEPSAction::Move( long nHorzMove, long nVertMove )
+{
+ maPoint.Move( nHorzMove, nVertMove );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEPSAction::Scale( double fScaleX, double fScaleY )
+{
+ Rectangle aRectangle(maPoint, maSize);
+ ImplScaleRect( aRectangle, fScaleX, fScaleY );
+ maPoint = aRectangle.TopLeft();
+ maSize = aRectangle.GetSize();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaEPSAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maGfxLink.IsEqual(((MetaEPSAction&)rMetaAction).maGfxLink )) &&
+ ( maSubst == ((MetaEPSAction&)rMetaAction).maSubst ) &&
+ ( maPoint == ((MetaEPSAction&)rMetaAction).maPoint ) &&
+ ( maSize == ((MetaEPSAction&)rMetaAction).maSize );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEPSAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maGfxLink;
+ rOStm << maPoint;
+ rOStm << maSize;
+ maSubst.Write( rOStm );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaEPSAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maGfxLink;
+ rIStm >> maPoint;
+ rIStm >> maSize;
+ rIStm >> maSubst;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( RefPoint, META_REFPOINT_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaRefPointAction::MetaRefPointAction( const Point& rRefPoint, BOOL bSet ) :
+ MetaAction ( META_REFPOINT_ACTION ),
+ maRefPoint ( rRefPoint ),
+ mbSet ( bSet )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRefPointAction::Execute( OutputDevice* pOut )
+{
+ if( mbSet )
+ pOut->SetRefPoint( maRefPoint );
+ else
+ pOut->SetRefPoint();
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaRefPointAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaRefPointAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaRefPointAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maRefPoint == ((MetaRefPointAction&)rMetaAction).maRefPoint ) &&
+ ( mbSet == ((MetaRefPointAction&)rMetaAction).mbSet );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRefPointAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maRefPoint << mbSet;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaRefPointAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maRefPoint >> mbSet;
+}
+
+// ========================================================================
+
+MetaCommentAction::MetaCommentAction( sal_Int32 nValue ) :
+ MetaAction ( META_COMMENT_ACTION ),
+ mnValue ( nValue )
+{
+ ImplInitDynamicData( NULL, 0UL );
+}
+
+// ------------------------------------------------------------------------
+
+MetaCommentAction::MetaCommentAction( const MetaCommentAction& rAct ) :
+ MetaAction ( META_COMMENT_ACTION ),
+ maComment ( rAct.maComment ),
+ mnValue ( rAct.mnValue )
+{
+ ImplInitDynamicData( rAct.mpData, rAct.mnDataSize );
+}
+
+// ------------------------------------------------------------------------
+
+MetaCommentAction::MetaCommentAction( const ByteString& rComment, sal_Int32 nValue, const BYTE* pData, sal_uInt32 nDataSize ) :
+ MetaAction ( META_COMMENT_ACTION ),
+ maComment ( rComment ),
+ mnValue ( nValue )
+{
+ ImplInitDynamicData( pData, nDataSize );
+}
+
+// ------------------------------------------------------------------------
+
+MetaCommentAction::MetaCommentAction( const BYTE* pData, sal_uInt32 nDataSize ) :
+ MetaAction ( META_COMMENT_ACTION ),
+ mnValue ( 0L )
+{
+ ImplInitDynamicData( pData, nDataSize );
+}
+
+// ------------------------------------------------------------------------
+
+MetaCommentAction::~MetaCommentAction()
+{
+ if ( mpData )
+ delete[] mpData;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaCommentAction::ImplInitDynamicData( const BYTE* pData, sal_uInt32 nDataSize )
+{
+ if ( nDataSize && pData )
+ {
+ mnDataSize = nDataSize, mpData = new BYTE[ mnDataSize ];
+ memcpy( mpData, pData, mnDataSize );
+ }
+ else
+ {
+ mnDataSize = 0;
+ mpData = NULL;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void MetaCommentAction::Execute( OutputDevice* pOut )
+{
+ if ( pOut->GetConnectMetaFile() )
+ pOut->GetConnectMetaFile()->AddAction( Clone() );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaCommentAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaCommentAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+void MetaCommentAction::Move( long nXMove, long nYMove )
+{
+ if ( nXMove || nYMove )
+ {
+ if ( mnDataSize && mpData )
+ {
+ sal_Bool bPathStroke = maComment.Equals( "XPATHSTROKE_SEQ_BEGIN" );
+ if ( bPathStroke || maComment.Equals( "XPATHFILL_SEQ_BEGIN" ) )
+ {
+ SvMemoryStream aMemStm( (void*)mpData, mnDataSize, STREAM_READ );
+ SvMemoryStream aDest;
+ if ( bPathStroke )
+ {
+ SvtGraphicStroke aStroke;
+ aMemStm >> aStroke;
+ Polygon aPath;
+ aStroke.getPath( aPath );
+ aPath.Move( nXMove, nYMove );
+ aStroke.setPath( aPath );
+ aDest << aStroke;
+ }
+ else
+ {
+ SvtGraphicFill aFill;
+ aMemStm >> aFill;
+ PolyPolygon aPath;
+ aFill.getPath( aPath );
+ aPath.Scale( nXMove, nYMove );
+ aFill.setPath( aPath );
+ aDest << aFill;
+ }
+ delete[] mpData;
+ ImplInitDynamicData( static_cast<const BYTE*>( aDest.GetData() ), aDest.Tell() );
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+// SJ: 25.07.06 #i56656# we are not able to mirrorcertain kind of
+// comments properly, especially the XPATHSTROKE and XPATHFILL lead to
+// problems, so it is better to remove these comments when mirroring
+void MetaCommentAction::Scale( double fXScale, double fYScale )
+{
+ if ( ( fXScale != 1.0 ) || ( fYScale != 1.0 ) )
+ {
+ if ( mnDataSize && mpData )
+ {
+ sal_Bool bPathStroke = maComment.Equals( "XPATHSTROKE_SEQ_BEGIN" );
+ if ( bPathStroke || maComment.Equals( "XPATHFILL_SEQ_BEGIN" ) )
+ {
+ SvMemoryStream aMemStm( (void*)mpData, mnDataSize, STREAM_READ );
+ SvMemoryStream aDest;
+ if ( bPathStroke )
+ {
+ SvtGraphicStroke aStroke;
+ aMemStm >> aStroke;
+ Polygon aPath;
+ aStroke.getPath( aPath );
+ aPath.Scale( fXScale, fYScale );
+ aStroke.setPath( aPath );
+ aDest << aStroke;
+ }
+ else
+ {
+ SvtGraphicFill aFill;
+ aMemStm >> aFill;
+ PolyPolygon aPath;
+ aFill.getPath( aPath );
+ aPath.Scale( fXScale, fYScale );
+ aFill.setPath( aPath );
+ aDest << aFill;
+ }
+ delete[] mpData;
+ ImplInitDynamicData( static_cast<const BYTE*>( aDest.GetData() ), aDest.Tell() );
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaCommentAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return ( maComment == ((MetaCommentAction&)rMetaAction).maComment ) &&
+ ( mnValue == ((MetaCommentAction&)rMetaAction).mnValue ) &&
+ ( mnDataSize == ((MetaCommentAction&)rMetaAction).mnDataSize ) &&
+ ( memcmp( mpData, ((MetaCommentAction&)rMetaAction).mpData, mnDataSize ) == 0 );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaCommentAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << maComment << mnValue << mnDataSize;
+
+ if ( mnDataSize )
+ rOStm.Write( mpData, mnDataSize );
+}
+
+// ------------------------------------------------------------------------
+
+void MetaCommentAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> maComment >> mnValue >> mnDataSize;
+
+ if( mpData )
+ delete[] mpData;
+
+ if( mnDataSize )
+ {
+ mpData = new BYTE[ mnDataSize ];
+ rIStm.Read( mpData, mnDataSize );
+ }
+ else
+ mpData = NULL;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( LayoutMode, META_LAYOUTMODE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaLayoutModeAction::MetaLayoutModeAction( sal_uInt32 nLayoutMode ) :
+ MetaAction ( META_LAYOUTMODE_ACTION ),
+ mnLayoutMode( nLayoutMode )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLayoutModeAction::Execute( OutputDevice* pOut )
+{
+ pOut->SetLayoutMode( mnLayoutMode );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaLayoutModeAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaLayoutModeAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaLayoutModeAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return mnLayoutMode == ((MetaLayoutModeAction&)rMetaAction).mnLayoutMode;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLayoutModeAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << mnLayoutMode;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaLayoutModeAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> mnLayoutMode;
+}
+
+// ========================================================================
+
+IMPL_META_ACTION( TextLanguage, META_TEXTLANGUAGE_ACTION )
+
+// ------------------------------------------------------------------------
+
+MetaTextLanguageAction::MetaTextLanguageAction( LanguageType eTextLanguage ) :
+ MetaAction ( META_TEXTLANGUAGE_ACTION ),
+ meTextLanguage( eTextLanguage )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLanguageAction::Execute( OutputDevice* pOut )
+{
+ pOut->SetDigitLanguage( meTextLanguage );
+}
+
+// ------------------------------------------------------------------------
+
+MetaAction* MetaTextLanguageAction::Clone()
+{
+ MetaAction* pClone = (MetaAction*) new MetaTextLanguageAction( *this );
+ pClone->ResetRefCount();
+ return pClone;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool MetaTextLanguageAction::Compare( const MetaAction& rMetaAction ) const
+{
+ return meTextLanguage == ((MetaTextLanguageAction&)rMetaAction).meTextLanguage;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLanguageAction::Write( SvStream& rOStm, ImplMetaWriteData* pData )
+{
+ WRITE_BASE_COMPAT( rOStm, 1, pData );
+ rOStm << meTextLanguage;
+}
+
+// ------------------------------------------------------------------------
+
+void MetaTextLanguageAction::Read( SvStream& rIStm, ImplMetaReadData* )
+{
+ COMPAT( rIStm );
+ rIStm >> meTextLanguage;
+}
+
+// ========================================================================
diff --git a/vcl/source/gdi/metric.cxx b/vcl/source/gdi/metric.cxx
new file mode 100644
index 000000000000..325146b6be8a
--- /dev/null
+++ b/vcl/source/gdi/metric.cxx
@@ -0,0 +1,916 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/impfont.hxx>
+#include <vcl/metric.hxx>
+
+#include <vector>
+#include <set>
+
+// =======================================================================
+
+ImplFontMetric::ImplFontMetric()
+: mnAscent( 0 ),
+ mnDescent( 0 ),
+ mnIntLeading( 0 ),
+ mnExtLeading( 0 ),
+ mnLineHeight( 0 ),
+ mnSlant( 0 ),
+ mnMiscFlags( 0 ),
+ mnRefCount( 1 )
+{}
+
+// -----------------------------------------------------------------------
+
+inline void ImplFontMetric::AddReference()
+{
+ ++mnRefCount;
+}
+
+// -----------------------------------------------------------------------
+
+inline void ImplFontMetric::DeReference()
+{
+ if( --mnRefCount <= 0 )
+ delete this;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplFontMetric::operator==( const ImplFontMetric& r ) const
+{
+ if( mnMiscFlags != r.mnMiscFlags )
+ return false;
+ if( mnAscent != r.mnAscent )
+ return false;
+ if( mnDescent != r.mnDescent )
+ return false;
+ if( mnIntLeading != r.mnIntLeading )
+ return false;
+ if( mnExtLeading != r.mnExtLeading )
+ return false;
+ if( mnSlant != r.mnSlant )
+ return false;
+
+ return true;
+}
+
+// =======================================================================
+
+FontInfo::FontInfo()
+: mpImplMetric( new ImplFontMetric )
+{}
+
+// -----------------------------------------------------------------------
+
+FontInfo::FontInfo( const FontInfo& rInfo )
+: Font( rInfo )
+{
+ mpImplMetric = rInfo.mpImplMetric;
+ mpImplMetric->AddReference();
+}
+
+// -----------------------------------------------------------------------
+
+FontInfo::~FontInfo()
+{
+ mpImplMetric->DeReference();
+}
+
+// -----------------------------------------------------------------------
+
+FontInfo& FontInfo::operator=( const FontInfo& rInfo )
+{
+ Font::operator=( rInfo );
+
+ if( mpImplMetric != rInfo.mpImplMetric )
+ {
+ mpImplMetric->DeReference();
+ mpImplMetric = rInfo.mpImplMetric;
+ mpImplMetric->AddReference();
+ }
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontInfo::operator==( const FontInfo& rInfo ) const
+{
+ if( !Font::operator==( rInfo ) )
+ return FALSE;
+ if( mpImplMetric == rInfo.mpImplMetric )
+ return TRUE;
+ if( *mpImplMetric == *rInfo.mpImplMetric )
+ return TRUE;
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+FontType FontInfo::GetType() const
+{
+ return (mpImplMetric->IsScalable() ? TYPE_SCALABLE : TYPE_RASTER);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontInfo::IsDeviceFont() const
+{
+ return mpImplMetric->IsDeviceFont();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontInfo::SupportsLatin() const
+{
+ return mpImplMetric->SupportsLatin();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontInfo::SupportsCJK() const
+{
+ return mpImplMetric->SupportsCJK();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontInfo::SupportsCTL() const
+{
+ return mpImplMetric->SupportsCTL();
+}
+
+// =======================================================================
+
+FontMetric::FontMetric( const FontMetric& rMetric )
+: FontInfo( rMetric )
+{}
+
+// -----------------------------------------------------------------------
+
+long FontMetric::GetAscent() const
+{
+ return mpImplMetric->GetAscent();
+}
+
+// -----------------------------------------------------------------------
+
+long FontMetric::GetDescent() const
+{
+ return mpImplMetric->GetDescent();
+}
+
+// -----------------------------------------------------------------------
+
+long FontMetric::GetIntLeading() const
+{
+ return mpImplMetric->GetIntLeading();
+}
+
+// -----------------------------------------------------------------------
+
+long FontMetric::GetExtLeading() const
+{
+ return mpImplMetric->GetExtLeading();
+}
+
+// -----------------------------------------------------------------------
+
+long FontMetric::GetLineHeight() const
+{
+ return mpImplMetric->GetLineHeight();
+}
+
+// -----------------------------------------------------------------------
+
+long FontMetric::GetSlant() const
+{
+ return mpImplMetric->GetSlant();
+}
+
+// -----------------------------------------------------------------------
+
+FontMetric& FontMetric::operator =( const FontMetric& rMetric )
+{
+ FontInfo::operator=( rMetric );
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontMetric::operator==( const FontMetric& rMetric ) const
+{
+ return FontInfo::operator==( rMetric );
+}
+
+// =======================================================================
+
+CmapResult::CmapResult( bool bSymbolic,
+ const sal_uInt32* pRangeCodes, int nRangeCount,
+ const int* pStartGlyphs, const USHORT* pExtraGlyphIds )
+: mpRangeCodes( pRangeCodes)
+, mpStartGlyphs( pStartGlyphs)
+, mpGlyphIds( pExtraGlyphIds)
+, mnRangeCount( nRangeCount)
+, mbSymbolic( bSymbolic)
+, mbRecoded( false)
+{}
+
+// =======================================================================
+
+ImplFontCharMap::ImplFontCharMap( const CmapResult& rCR )
+: mpRangeCodes( rCR.mpRangeCodes )
+, mpStartGlyphs( rCR.mpStartGlyphs )
+, mpGlyphIds( rCR.mpGlyphIds )
+, mnRangeCount( rCR.mnRangeCount )
+, mnCharCount( 0 )
+, mnRefCount( 1 )
+{
+ const sal_uInt32* pRangePtr = mpRangeCodes;
+ for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 )
+ {
+ sal_uInt32 cFirst = pRangePtr[0];
+ sal_uInt32 cLast = pRangePtr[1];
+ mnCharCount += cLast - cFirst;
+ }
+}
+
+static ImplFontCharMap* pDefaultImplFontCharMap = NULL;
+static const sal_uInt32 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0};
+static const sal_uInt32 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100};
+
+// -----------------------------------------------------------------------
+
+bool ImplFontCharMap::IsDefaultMap() const
+{
+ const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges);
+ return bIsDefault;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap::~ImplFontCharMap()
+{
+ if( IsDefaultMap() )
+ return;
+ delete[] mpRangeCodes;
+ delete[] mpStartGlyphs;
+ delete[] mpGlyphIds;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap* ImplFontCharMap::GetDefaultMap( bool bSymbols)
+{
+ if( pDefaultImplFontCharMap )
+ pDefaultImplFontCharMap->AddReference();
+ else
+ {
+ const sal_uInt32* pRangeCodes = aDefaultUnicodeRanges;
+ int nCodesCount = sizeof(aDefaultUnicodeRanges) / sizeof(*pRangeCodes);
+ if( bSymbols )
+ {
+ pRangeCodes = aDefaultSymbolRanges;
+ nCodesCount = sizeof(aDefaultSymbolRanges) / sizeof(*pRangeCodes);
+ }
+
+ CmapResult aDefaultCR( bSymbols, pRangeCodes, nCodesCount/2 );
+ pDefaultImplFontCharMap = new ImplFontCharMap( aDefaultCR );
+ }
+
+ return pDefaultImplFontCharMap;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFontCharMap::AddReference()
+{
+ ++mnRefCount;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFontCharMap::DeReference()
+{
+ if( --mnRefCount <= 0 )
+ if( this != pDefaultImplFontCharMap )
+ delete this;
+}
+
+// -----------------------------------------------------------------------
+
+int ImplFontCharMap::GetCharCount() const
+{
+ return mnCharCount;
+}
+
+// -----------------------------------------------------------------------
+
+int ImplFontCharMap::ImplFindRangeIndex( sal_uInt32 cChar ) const
+{
+ int nLower = 0;
+ int nMid = mnRangeCount;
+ int nUpper = 2 * mnRangeCount - 1;
+ while( nLower < nUpper )
+ {
+ if( cChar >= mpRangeCodes[ nMid ] )
+ nLower = nMid;
+ else
+ nUpper = nMid - 1;
+ nMid = (nLower + nUpper + 1) / 2;
+ }
+
+ return nMid;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplFontCharMap::HasChar( sal_uInt32 cChar ) const
+{
+ bool bHasChar = false;
+
+ if( mpStartGlyphs == NULL ) { // only the char-ranges are known
+ const int nRange = ImplFindRangeIndex( cChar );
+ if( nRange==0 && cChar<mpRangeCodes[0] )
+ return false;
+ bHasChar = ((nRange & 1) == 0); // inside a range
+ } else { // glyph mapping is available
+ const int nGlyphIndex = GetGlyphIndex( cChar );
+ bHasChar = (nGlyphIndex != 0); // not the notdef-glyph
+ }
+
+ return bHasChar;
+}
+
+// -----------------------------------------------------------------------
+
+int ImplFontCharMap::GetGlyphIndex( sal_uInt32 cChar ) const
+{
+ // return -1 if the object doesn't know the glyph ids
+ if( !mpStartGlyphs )
+ return -1;
+
+ // return 0 if the unicode doesn't have a matching glyph
+ int nRange = ImplFindRangeIndex( cChar );
+ // check that we are inside any range
+ if( (nRange == 0) && (cChar < mpRangeCodes[0]) ) {
+ // symbol aliasing gives symbol fonts a second chance
+ const bool bSymbolic = (mpRangeCodes[0]>=0xF000) & (mpRangeCodes[1]<=0xF0FF);
+ if( !bSymbolic )
+ return 0;
+ // check for symbol aliasing (U+00xx <-> U+F0xx)
+ cChar |= 0xF000;
+ nRange = ImplFindRangeIndex( cChar );
+ }
+ // check that we are inside a range
+ if( (nRange & 1) != 0 )
+ return 0;
+
+ // get glyph index directly or indirectly
+ int nGlyphIndex = cChar - mpRangeCodes[ nRange ];
+ const int nStartIndex = mpStartGlyphs[ nRange/2 ];
+ if( nStartIndex >= 0 ) {
+ // the glyph index can be calculated
+ nGlyphIndex += nStartIndex;
+ } else {
+ // the glyphid array has the glyph index
+ nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex ];
+ }
+
+ return nGlyphIndex;
+}
+
+// -----------------------------------------------------------------------
+
+// returns the number of chars supported by the font, which
+// are inside the unicode range from cMin to cMax (inclusive)
+int ImplFontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const
+{
+ int nCount = 0;
+
+ // find and adjust range and char count for cMin
+ int nRangeMin = ImplFindRangeIndex( cMin );
+ if( nRangeMin & 1 )
+ ++nRangeMin;
+ else if( cMin > mpRangeCodes[ nRangeMin ] )
+ nCount -= cMin - mpRangeCodes[ nRangeMin ];
+
+ // find and adjust range and char count for cMax
+ int nRangeMax = ImplFindRangeIndex( cMax );
+ if( nRangeMax & 1 )
+ --nRangeMax;
+ else
+ nCount -= mpRangeCodes[ nRangeMax+1 ] - cMax - 1;
+
+ // count chars in complete ranges between cMin and cMax
+ for( int i = nRangeMin; i <= nRangeMax; i+=2 )
+ nCount += mpRangeCodes[i+1] - mpRangeCodes[i];
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 ImplFontCharMap::GetFirstChar() const
+{
+ return mpRangeCodes[0];
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 ImplFontCharMap::GetLastChar() const
+{
+ return (mpRangeCodes[ 2*mnRangeCount-1 ] - 1);
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 ImplFontCharMap::GetNextChar( sal_uInt32 cChar ) const
+{
+ if( cChar < GetFirstChar() )
+ return GetFirstChar();
+ if( cChar >= GetLastChar() )
+ return GetLastChar();
+
+ int nRange = ImplFindRangeIndex( cChar + 1 );
+ if( nRange & 1 ) // outside of range?
+ return mpRangeCodes[ nRange + 1 ]; // => first in next range
+ return (cChar + 1);
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 ImplFontCharMap::GetPrevChar( sal_uInt32 cChar ) const
+{
+ if( cChar <= GetFirstChar() )
+ return GetFirstChar();
+ if( cChar > GetLastChar() )
+ return GetLastChar();
+
+ int nRange = ImplFindRangeIndex( cChar - 1 );
+ if( nRange & 1 ) // outside a range?
+ return (mpRangeCodes[ nRange ] - 1); // => last in prev range
+ return (cChar - 1);
+}
+
+// -----------------------------------------------------------------------
+
+int ImplFontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const
+{
+ // TODO: improve linear walk?
+ int nCharIndex = 0;
+ const sal_uInt32* pRange = &mpRangeCodes[0];
+ for( int i = 0; i < mnRangeCount; ++i )
+ {
+ sal_uInt32 cFirst = *(pRange++);
+ sal_uInt32 cLast = *(pRange++);
+ if( cChar >= cLast )
+ nCharIndex += cLast - cFirst;
+ else if( cChar >= cFirst )
+ return nCharIndex + (cChar - cFirst);
+ else
+ break;
+ }
+
+ return -1;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 ImplFontCharMap::GetCharFromIndex( int nCharIndex ) const
+{
+ // TODO: improve linear walk?
+ const sal_uInt32* pRange = &mpRangeCodes[0];
+ for( int i = 0; i < mnRangeCount; ++i )
+ {
+ sal_uInt32 cFirst = *(pRange++);
+ sal_uInt32 cLast = *(pRange++);
+ nCharIndex -= cLast - cFirst;
+ if( nCharIndex < 0 )
+ return (cLast + nCharIndex);
+ }
+
+ // we can only get here with an out-of-bounds charindex
+ return mpRangeCodes[0];
+}
+
+// =======================================================================
+
+static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
+static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8) | p[1]);}
+static int GetSShort( const unsigned char* p ){ return((static_cast<signed char>(p[0])<<8)|p[1]);}
+
+// TODO: move CMAP parsing directly into the ImplFontCharMap class
+bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult )
+{
+ rResult.mpRangeCodes = NULL;
+ rResult.mpStartGlyphs= NULL;
+ rResult.mpGlyphIds = NULL;
+ rResult.mnRangeCount = 0;
+ rResult.mbRecoded = false;
+ rResult.mbSymbolic = false;
+
+ // parse the table header and check for validity
+ if( !pCmap || (nLength < 24) )
+ return false;
+
+ if( GetUShort( pCmap ) != 0x0000 ) // simple check for CMAP corruption
+ return false;
+
+ int nSubTables = GetUShort( pCmap + 2 );
+ if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) )
+ return false;
+
+ // find the most interesting subtable in the CMAP
+ rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
+ int nOffset = 0;
+ int nFormat = -1;
+ int nBestVal = 0;
+ for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
+ {
+ int nPlatform = GetUShort( p );
+ int nEncoding = GetUShort( p+2 );
+ int nPlatformEncoding = (nPlatform << 8) + nEncoding;
+
+ int nValue;
+ rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE;
+ switch( nPlatformEncoding )
+ {
+ case 0x000: nValue = 20; break; // Unicode 1.0
+ case 0x001: nValue = 21; break; // Unicode 1.1
+ case 0x002: nValue = 22; break; // iso10646_1993
+ case 0x003: nValue = 23; break; // UCS-2
+ case 0x004: nValue = 24; break; // UCS-4
+ case 0x100: nValue = 22; break; // Mac Unicode<2.0
+ case 0x103: nValue = 23; break; // Mac Unicode>2.0
+ case 0x300: nValue = 5; rResult.mbSymbolic = true; break; // Win Symbol
+ case 0x301: nValue = 28; break; // Win UCS-2
+ case 0x30A: nValue = 29; break; // Win-UCS-4
+ case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break;
+ case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break;
+ case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break;
+ case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break;
+ case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break;
+ default: nValue = 0; break;
+ }
+
+ if( nValue <= 0 ) // ignore unknown encodings
+ continue;
+
+ int nTmpOffset = GetUInt( p+4 );
+ int nTmpFormat = GetUShort( pCmap + nTmpOffset );
+ if( nTmpFormat == 12 ) // 32bit code -> glyph map format
+ nValue += 3;
+ else if( nTmpFormat != 4 ) // 16bit code -> glyph map format
+ continue; // ignore other formats
+
+ if( nBestVal < nValue )
+ {
+ nBestVal = nValue;
+ nOffset = nTmpOffset;
+ nFormat = nTmpFormat;
+ eRecodeFrom = eTmpEncoding;
+ }
+ }
+
+ // parse the best CMAP subtable
+ int nRangeCount = 0;
+ sal_uInt32* pCodePairs = NULL;
+ int* pStartGlyphs = NULL;
+
+ typedef std::vector<USHORT> U16Vector;
+ U16Vector aGlyphIdArray;
+ aGlyphIdArray.reserve( 0x1000 );
+ aGlyphIdArray.push_back( 0 );
+
+ // format 4, the most common 16bit char mapping table
+ if( (nFormat == 4) && ((nOffset+16) < nLength) )
+ {
+ int nSegCountX2 = GetUShort( pCmap + nOffset + 6 );
+ nRangeCount = nSegCountX2/2 - 1;
+ pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
+ pStartGlyphs = new int[ nRangeCount ];
+ const unsigned char* pLimitBase = pCmap + nOffset + 14;
+ const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2;
+ const unsigned char* pDeltaBase = pBeginBase + nSegCountX2;
+ const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2;
+ sal_uInt32* pCP = pCodePairs;
+ for( int i = 0; i < nRangeCount; ++i )
+ {
+ const sal_uInt32 cMinChar = GetUShort( pBeginBase + 2*i );
+ const sal_uInt32 cMaxChar = GetUShort( pLimitBase + 2*i );
+ const int nGlyphDelta = GetSShort( pDeltaBase + 2*i );
+ const int nRangeOffset = GetUShort( pOffsetBase + 2*i );
+ if( cMinChar > cMaxChar ) // no sane font should trigger this
+ break;
+ if( cMaxChar == 0xFFFF )
+ break;
+ *(pCP++) = cMinChar;
+ *(pCP++) = cMaxChar + 1;
+ if( !nRangeOffset ) {
+ // glyphid can be calculated directly
+ pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF;
+ } else {
+ // update the glyphid-array with the glyphs in this range
+ pStartGlyphs[i] = -(int)aGlyphIdArray.size();
+ const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset;
+ for( sal_uInt32 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) {
+ const int nGlyphIndex = GetUShort( pGlyphIdPtr ) + nGlyphDelta;
+ aGlyphIdArray.push_back( static_cast<USHORT>(nGlyphIndex) );
+ }
+ }
+ }
+ nRangeCount = (pCP - pCodePairs) / 2;
+ }
+ // format 12, the most common 32bit char mapping table
+ else if( (nFormat == 12) && ((nOffset+16) < nLength) )
+ {
+ nRangeCount = GetUInt( pCmap + nOffset + 12 );
+ pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
+ pStartGlyphs = new int[ nRangeCount ];
+ const unsigned char* pGroup = pCmap + nOffset + 16;
+ sal_uInt32* pCP = pCodePairs;
+ for( int i = 0; i < nRangeCount; ++i )
+ {
+ sal_uInt32 cMinChar = GetUInt( pGroup + 0 );
+ sal_uInt32 cMaxChar = GetUInt( pGroup + 4 );
+ int nGlyphId = GetUInt( pGroup + 8 );
+ pGroup += 12;
+#if 0 // TODO: remove unicode baseplane clipping for UCS-4 support
+ if( cMinChar > 0xFFFF )
+ continue;
+ if( cMaxChar > 0xFFFF )
+ cMaxChar = 0xFFFF;
+#else
+ if( cMinChar > cMaxChar ) // no sane font should trigger this
+ break;
+#endif
+ *(pCP++) = cMinChar;
+ *(pCP++) = cMaxChar + 1;
+ pStartGlyphs[i] = nGlyphId;
+ }
+ nRangeCount = (pCP - pCodePairs) / 2;
+ }
+
+ // check if any subtable resulted in something usable
+ if( nRangeCount <= 0 )
+ {
+ delete[] pCodePairs;
+ delete[] pStartGlyphs;
+
+ // even when no CMAP is available we know it for symbol fonts
+ if( rResult.mbSymbolic )
+ {
+ pCodePairs = new sal_uInt32[4];
+ pCodePairs[0] = 0x0020; // aliased symbols
+ pCodePairs[1] = 0x0100;
+ pCodePairs[2] = 0xF020; // original symbols
+ pCodePairs[3] = 0xF100;
+ rResult.mpRangeCodes = pCodePairs;
+ rResult.mnRangeCount = 2;
+ return true;
+ }
+
+ return false;
+ }
+
+ // recode the code ranges to their unicode encoded ranges if needed
+ rtl_TextToUnicodeConverter aConverter = NULL;
+ rtl_UnicodeToTextContext aCvtContext = NULL;
+
+ rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE );
+ if( rResult.mbRecoded )
+ {
+ aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom );
+ aCvtContext = rtl_createTextToUnicodeContext( aConverter );
+ }
+
+ if( aConverter && aCvtContext )
+ {
+ // determine the set of supported unicodes from encoded ranges
+ typedef std::set<sal_uInt32> IntSet;
+ IntSet aSupportedUnicodes;
+
+ static const int NINSIZE = 64;
+ static const int NOUTSIZE = 64;
+ sal_Char cCharsInp[ NINSIZE ];
+ sal_Unicode cCharsOut[ NOUTSIZE ];
+ sal_uInt32* pCP = pCodePairs;
+ for( int i = 0; i < nRangeCount; ++i )
+ {
+ sal_uInt32 cMin = *(pCP++);
+ sal_uInt32 cEnd = *(pCP++);
+ while( cMin < cEnd )
+ {
+ int j = 0;
+ for(; (cMin < cEnd) && (j < NINSIZE); ++cMin )
+ {
+ if( cMin >= 0x0100 )
+ cCharsInp[ j++ ] = static_cast<sal_Char>(cMin >> 8);
+ if( (cMin >= 0x0100) || (cMin < 0x00A0) )
+ cCharsInp[ j++ ] = static_cast<sal_Char>(cMin);
+ }
+
+ sal_uInt32 nCvtInfo;
+ sal_Size nSrcCvtBytes;
+ int nOutLen = rtl_convertTextToUnicode(
+ aConverter, aCvtContext,
+ cCharsInp, j, cCharsOut, NOUTSIZE,
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
+ | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE,
+ &nCvtInfo, &nSrcCvtBytes );
+
+ for( j = 0; j < nOutLen; ++j )
+ aSupportedUnicodes.insert( cCharsOut[j] );
+ }
+ }
+
+ rtl_destroyTextToUnicodeConverter( aCvtContext );
+ rtl_destroyTextToUnicodeConverter( aConverter );
+
+ // convert the set of supported unicodes to ranges
+ typedef std::vector<sal_uInt32> IntVector;
+ IntVector aSupportedRanges;
+
+ IntSet::const_iterator itChar = aSupportedUnicodes.begin();
+ for(; itChar != aSupportedUnicodes.end(); ++itChar )
+ {
+ if( aSupportedRanges.empty()
+ || (aSupportedRanges.back() != *itChar) )
+ {
+ // add new range beginning with current unicode
+ aSupportedRanges.push_back( *itChar );
+ aSupportedRanges.push_back( 0 );
+ }
+
+ // extend existing range to include current unicode
+ aSupportedRanges.back() = *itChar + 1;
+ }
+
+ // glyph mapping for non-unicode fonts not implemented
+ delete[] pStartGlyphs;
+ pStartGlyphs = NULL;
+ aGlyphIdArray.clear();
+
+ // make a pCodePairs array using the vector from above
+ delete[] pCodePairs;
+ nRangeCount = aSupportedRanges.size() / 2;
+ if( nRangeCount <= 0 )
+ return false;
+ pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
+ IntVector::const_iterator itInt = aSupportedRanges.begin();
+ for( pCP = pCodePairs; itInt != aSupportedRanges.end(); ++itInt )
+ *(pCP++) = *itInt;
+ }
+
+ // prepare the glyphid-array if needed
+ // TODO: merge ranges if they are close enough?
+ USHORT* pGlyphIds = NULL;
+ if( !aGlyphIdArray.empty())
+ {
+ pGlyphIds = new USHORT[ aGlyphIdArray.size() ];
+ USHORT* pOut = pGlyphIds;
+ U16Vector::const_iterator it = aGlyphIdArray.begin();
+ while( it != aGlyphIdArray.end() )
+ *(pOut++) = *(it++);
+ }
+
+ // update the result struct
+ rResult.mpRangeCodes = pCodePairs;
+ rResult.mpStartGlyphs = pStartGlyphs;
+ rResult.mnRangeCount = nRangeCount;
+ rResult.mpGlyphIds = pGlyphIds;
+ return true;
+}
+
+// =======================================================================
+
+FontCharMap::FontCharMap()
+: mpImpl( ImplFontCharMap::GetDefaultMap() )
+{}
+
+// -----------------------------------------------------------------------
+
+FontCharMap::~FontCharMap()
+{
+ mpImpl->DeReference();
+ mpImpl = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+int FontCharMap::GetCharCount() const
+{
+ return mpImpl->GetCharCount();
+}
+
+// -----------------------------------------------------------------------
+
+int FontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const
+{
+ return mpImpl->CountCharsInRange( cMin, cMax );
+}
+
+// -----------------------------------------------------------------------
+
+void FontCharMap::Reset( ImplFontCharMap* pNewMap )
+{
+ if( pNewMap == NULL )
+ {
+ mpImpl->DeReference();
+ mpImpl = ImplFontCharMap::GetDefaultMap();
+ }
+ else if( pNewMap != mpImpl )
+ {
+ mpImpl->DeReference();
+ mpImpl = pNewMap;
+ mpImpl->AddReference();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontCharMap::IsDefaultMap() const
+{
+ return mpImpl->IsDefaultMap();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FontCharMap::HasChar( sal_uInt32 cChar ) const
+{
+ return mpImpl->HasChar( cChar );
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 FontCharMap::GetFirstChar() const
+{
+ return mpImpl->GetFirstChar();
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 FontCharMap::GetLastChar() const
+{
+ return mpImpl->GetLastChar();
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 FontCharMap::GetNextChar( sal_uInt32 cChar ) const
+{
+ return mpImpl->GetNextChar( cChar );
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 FontCharMap::GetPrevChar( sal_uInt32 cChar ) const
+{
+ return mpImpl->GetPrevChar( cChar );
+}
+
+// -----------------------------------------------------------------------
+
+int FontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const
+{
+ return mpImpl->GetIndexFromChar( cChar );
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt32 FontCharMap::GetCharFromIndex( int nIndex ) const
+{
+ return mpImpl->GetCharFromIndex( nIndex );
+}
+
+// =======================================================================
+
diff --git a/vcl/source/gdi/octree.cxx b/vcl/source/gdi/octree.cxx
new file mode 100644
index 000000000000..0660728fc8a5
--- /dev/null
+++ b/vcl/source/gdi/octree.cxx
@@ -0,0 +1,369 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <limits.h>
+#include <vcl/bmpacc.hxx>
+#include <vcl/impoct.hxx>
+#include <vcl/octree.hxx>
+
+// ---------
+// - pMask -
+// ---------
+
+static BYTE pImplMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+// -------------
+// - NodeCache -
+// -------------
+
+ImpNodeCache::ImpNodeCache( const ULONG nInitSize ) :
+ pActNode( NULL )
+{
+ const ULONG nSize = nInitSize + 4;
+
+ for( ULONG i = 0; i < nSize; i++ )
+ {
+ OctreeNode* pNewNode = new NODE;
+
+ pNewNode->pNextInCache = pActNode;
+ pActNode = pNewNode;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+ImpNodeCache::~ImpNodeCache()
+{
+ while( pActNode )
+ {
+ OctreeNode* pNode = pActNode;
+
+ pActNode = pNode->pNextInCache;
+ delete pNode;
+ }
+}
+
+// ----------
+// - Octree -
+// ----------
+
+Octree::Octree( ULONG nColors ) :
+ nMax ( nColors ),
+ nLeafCount ( 0L ),
+ pTree ( NULL ),
+ pAcc ( NULL )
+{
+ pNodeCache = new ImpNodeCache( nColors );
+ memset( pReduce, 0, ( OCTREE_BITS + 1 ) * sizeof( PNODE ) );
+}
+
+// ------------------------------------------------------------------------
+
+Octree::Octree( const BitmapReadAccess& rReadAcc, ULONG nColors ) :
+ nMax ( nColors ),
+ nLeafCount ( 0L ),
+ pTree ( NULL ),
+ pAcc ( &rReadAcc )
+{
+ pNodeCache = new ImpNodeCache( nColors );
+ memset( pReduce, 0, ( OCTREE_BITS + 1 ) * sizeof( PNODE ) );
+ ImplCreateOctree();
+}
+
+// ------------------------------------------------------------------------
+
+Octree::~Octree()
+{
+ ImplDeleteOctree( &pTree );
+ delete pNodeCache;
+}
+
+// ------------------------------------------------------------------------
+
+void Octree::AddColor( const BitmapColor& rColor )
+{
+ pColor = &(BitmapColor&) rColor;
+ nLevel = 0L;
+ ImplAdd( &pTree );
+
+ while( nLeafCount > nMax )
+ ImplReduce();
+}
+
+// ------------------------------------------------------------------------
+
+void Octree::ImplCreateOctree()
+{
+ if( !!*pAcc )
+ {
+ const long nWidth = pAcc->Width();
+ const long nHeight = pAcc->Height();
+
+ if( pAcc->HasPalette() )
+ {
+ for( long nY = 0; nY < nHeight; nY++ )
+ {
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ pColor = &(BitmapColor&) pAcc->GetPaletteColor( pAcc->GetPixel( nY, nX ) );
+ nLevel = 0L;
+ ImplAdd( &pTree );
+
+ while( nLeafCount > nMax )
+ ImplReduce();
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aColor;
+
+ pColor = &aColor;
+
+ for( long nY = 0; nY < nHeight; nY++ )
+ {
+ for( long nX = 0; nX < nWidth; nX++ )
+ {
+ aColor = pAcc->GetPixel( nY, nX );
+ nLevel = 0L;
+ ImplAdd( &pTree );
+
+ while( nLeafCount > nMax )
+ ImplReduce();
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void Octree::ImplDeleteOctree( PPNODE ppNode )
+{
+ for ( ULONG i = 0UL; i < 8UL; i++ )
+ {
+ if ( (*ppNode)->pChild[ i ] )
+ ImplDeleteOctree( &(*ppNode)->pChild[ i ] );
+ }
+
+ pNodeCache->ImplReleaseNode( *ppNode );
+ *ppNode = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+void Octree::ImplAdd( PPNODE ppNode )
+{
+ // ggf. neuen Knoten erzeugen
+ if( !*ppNode )
+ {
+ *ppNode = pNodeCache->ImplGetFreeNode();
+ (*ppNode)->bLeaf = ( OCTREE_BITS == nLevel );
+
+ if( (*ppNode)->bLeaf )
+ nLeafCount++;
+ else
+ {
+ (*ppNode)->pNext = pReduce[ nLevel ];
+ pReduce[ nLevel ] = *ppNode;
+ }
+ }
+
+ if( (*ppNode)->bLeaf )
+ {
+ (*ppNode)->nCount++;
+ (*ppNode)->nRed += pColor->GetRed();
+ (*ppNode)->nGreen += pColor->GetGreen();
+ (*ppNode)->nBlue += pColor->GetBlue();
+ }
+ else
+ {
+ const ULONG nShift = 7 - nLevel;
+ const BYTE cMask = pImplMask[ nLevel ];
+ const ULONG nIndex = ( ( ( pColor->GetRed() & cMask ) >> nShift ) << 2 ) |
+ ( ( ( pColor->GetGreen() & cMask ) >> nShift ) << 1 ) |
+ ( ( pColor->GetBlue() & cMask ) >> nShift );
+
+ nLevel++;
+ ImplAdd( &(*ppNode)->pChild[ nIndex ] );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void Octree::ImplReduce()
+{
+ ULONG i;
+ PNODE pNode;
+ ULONG nRedSum = 0L;
+ ULONG nGreenSum = 0L;
+ ULONG nBlueSum = 0L;
+ ULONG nChilds = 0L;
+
+ for ( i = OCTREE_BITS - 1; i && !pReduce[i]; i-- ) {}
+
+ pNode = pReduce[ i ];
+ pReduce[ i ] = pNode->pNext;
+
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( pNode->pChild[ i ] )
+ {
+ PNODE pChild = pNode->pChild[ i ];
+
+ nRedSum += pChild->nRed;
+ nGreenSum += pChild->nGreen;
+ nBlueSum += pChild->nBlue;
+ pNode->nCount += pChild->nCount;
+
+ pNodeCache->ImplReleaseNode( pNode->pChild[ i ] );
+ pNode->pChild[ i ] = NULL;
+ nChilds++;
+ }
+ }
+
+ pNode->bLeaf = TRUE;
+ pNode->nRed = nRedSum;
+ pNode->nGreen = nGreenSum;
+ pNode->nBlue = nBlueSum;
+ nLeafCount -= --nChilds;
+}
+
+// ------------------------------------------------------------------------
+
+void Octree::CreatePalette( PNODE pNode )
+{
+ if( pNode->bLeaf )
+ {
+ pNode->nPalIndex = nPalIndex;
+ aPal[ nPalIndex++ ] = BitmapColor( (BYTE) ( (double) pNode->nRed / pNode->nCount ),
+ (BYTE) ( (double) pNode->nGreen / pNode->nCount ),
+ (BYTE) ( (double) pNode->nBlue / pNode->nCount ) );
+ }
+ else for( ULONG i = 0UL; i < 8UL; i++ )
+ if( pNode->pChild[ i ] )
+ CreatePalette( pNode->pChild[ i ] );
+
+}
+
+// ------------------------------------------------------------------------
+
+void Octree::GetPalIndex( PNODE pNode )
+{
+ if ( pNode->bLeaf )
+ nPalIndex = pNode->nPalIndex;
+ else
+ {
+ const ULONG nShift = 7 - nLevel;
+ const BYTE cMask = pImplMask[ nLevel++ ];
+ const ULONG nIndex = ( ( ( pColor->GetRed() & cMask ) >> nShift ) << 2 ) |
+ ( ( ( pColor->GetGreen() & cMask ) >> nShift ) << 1 ) |
+ ( ( pColor->GetBlue() & cMask ) >> nShift );
+
+ GetPalIndex( pNode->pChild[ nIndex ] );
+ }
+}
+
+// -------------------
+// - InverseColorMap -
+// -------------------
+
+InverseColorMap::InverseColorMap( const BitmapPalette& rPal ) :
+ nBits( 8 - OCTREE_BITS )
+{
+ ULONG* cdp;
+ BYTE* crgbp;
+ const ULONG nColorMax = 1 << OCTREE_BITS;
+ const ULONG xsqr = 1 << ( nBits << 1 );
+ const ULONG xsqr2 = xsqr << 1;
+ const ULONG nColors = rPal.GetEntryCount();
+ const long x = 1L << nBits;
+ const long x2 = x >> 1L;
+ ULONG r, g, b;
+ long rxx, gxx, bxx;
+ long rdist, gdist, bdist;
+ long crinc, cginc, cbinc;
+
+ ImplCreateBuffers( nColorMax );
+
+ for( ULONG nIndex = 0; nIndex < nColors; nIndex++ )
+ {
+ const BitmapColor& rColor = rPal[ (USHORT) nIndex ];
+ const BYTE cRed = rColor.GetRed();
+ const BYTE cGreen = rColor.GetGreen();
+ const BYTE cBlue = rColor.GetBlue();
+
+ rdist = cRed - x2;
+ gdist = cGreen - x2;
+ bdist = cBlue - x2;
+ rdist = rdist*rdist + gdist*gdist + bdist*bdist;
+
+ crinc = ( xsqr - ( cRed << nBits ) ) << 1L;
+ cginc = ( xsqr - ( cGreen << nBits ) ) << 1L;
+ cbinc = ( xsqr - ( cBlue << nBits ) ) << 1L;
+
+ cdp = (ULONG*) pBuffer;
+ crgbp = pMap;
+
+ for( r = 0, rxx = crinc; r < nColorMax; rdist += rxx, r++, rxx += xsqr2 )
+ {
+ for( g = 0, gdist = rdist, gxx = cginc; g < nColorMax; gdist += gxx, g++, gxx += xsqr2 )
+ {
+ for( b = 0, bdist = gdist, bxx = cbinc; b < nColorMax; bdist += bxx, b++, cdp++, crgbp++, bxx += xsqr2 )
+ if ( !nIndex || ( (long) *cdp ) > bdist )
+ {
+ *cdp = bdist;
+ *crgbp = (BYTE) nIndex;
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+InverseColorMap::~InverseColorMap()
+{
+ rtl_freeMemory( pBuffer );
+ rtl_freeMemory( pMap );
+}
+
+// ------------------------------------------------------------------------
+
+void InverseColorMap::ImplCreateBuffers( const ULONG nMax )
+{
+ const ULONG nCount = nMax * nMax * nMax;
+ const ULONG nSize = nCount * sizeof( ULONG );
+
+ pMap = (BYTE*) rtl_allocateMemory( nCount );
+ memset( pMap, 0x00, nCount );
+
+ pBuffer = (BYTE*) rtl_allocateMemory( nSize );
+ memset( pBuffer, 0xff, nSize );
+}
diff --git a/vcl/source/gdi/oldprintadaptor.cxx b/vcl/source/gdi/oldprintadaptor.cxx
new file mode 100644
index 000000000000..ce3ece7e1e5b
--- /dev/null
+++ b/vcl/source/gdi/oldprintadaptor.cxx
@@ -0,0 +1,117 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_vcl.hxx"
+
+#include "vcl/oldprintadaptor.hxx"
+#include "vcl/gdimtf.hxx"
+
+#include "com/sun/star/awt/Size.hpp"
+
+#include <vector>
+
+namespace vcl
+{
+ struct AdaptorPage
+ {
+ GDIMetaFile maPage;
+ com::sun::star::awt::Size maPageSize;
+ };
+
+ struct ImplOldStyleAdaptorData
+ {
+ std::vector< AdaptorPage > maPages;
+ };
+}
+
+using namespace vcl;
+using namespace cppu;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+
+OldStylePrintAdaptor::OldStylePrintAdaptor( const boost::shared_ptr< Printer >& i_pPrinter )
+ : PrinterController( i_pPrinter )
+ , mpData( new ImplOldStyleAdaptorData() )
+{
+}
+
+OldStylePrintAdaptor::~OldStylePrintAdaptor()
+{
+}
+
+void OldStylePrintAdaptor::StartPage()
+{
+ Size aPaperSize( getPrinter()->PixelToLogic( getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) );
+ mpData->maPages.push_back( AdaptorPage() );
+ mpData->maPages.back().maPageSize.Width = aPaperSize.getWidth();
+ mpData->maPages.back().maPageSize.Height = aPaperSize.getHeight();
+ getPrinter()->SetConnectMetaFile( &mpData->maPages.back().maPage );
+
+ // copy state into metafile
+ boost::shared_ptr<Printer> pPrinter( getPrinter() );
+ pPrinter->SetMapMode( pPrinter->GetMapMode() );
+ pPrinter->SetFont( pPrinter->GetFont() );
+ pPrinter->SetDrawMode( pPrinter->GetDrawMode() );
+ pPrinter->SetLineColor( pPrinter->GetLineColor() );
+ pPrinter->SetFillColor( pPrinter->GetFillColor() );
+}
+
+void OldStylePrintAdaptor::EndPage()
+{
+ getPrinter()->SetConnectMetaFile( NULL );
+ mpData->maPages.back().maPage.WindStart();
+}
+
+int OldStylePrintAdaptor::getPageCount() const
+{
+ return int(mpData->maPages.size());
+}
+
+Sequence< PropertyValue > OldStylePrintAdaptor::getPageParameters( int i_nPage ) const
+{
+ Sequence< PropertyValue > aRet( 1 );
+ aRet[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("PageSize") );
+ if( i_nPage < int(mpData->maPages.size() ) )
+ aRet[0].Value = makeAny( mpData->maPages[i_nPage].maPageSize );
+ else
+ {
+ awt::Size aEmpty( 0, 0 );
+ aRet[0].Value = makeAny( aEmpty );
+ }
+ return aRet;
+}
+
+void OldStylePrintAdaptor::printPage( int i_nPage ) const
+{
+ if( i_nPage < int(mpData->maPages.size()) )
+ {
+ mpData->maPages[ i_nPage ].maPage.WindStart();
+ mpData->maPages[ i_nPage ].maPage.Play( getPrinter().get() );
+ }
+}
+
diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx
new file mode 100644
index 000000000000..a011e4ee4a92
--- /dev/null
+++ b/vcl/source/gdi/outdev.cxx
@@ -0,0 +1,3493 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/ref.hxx>
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salgdi.hxx>
+#include <vcl/sallayout.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/salvd.hxx>
+#include <vcl/salprn.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/ctrl.hxx>
+#ifndef _POLY_HXX
+#include <tools/poly.hxx>
+#endif
+#include <vcl/region.hxx>
+#include <vcl/region.h>
+#include <vcl/virdev.hxx>
+#include <vcl/window.h>
+#include <vcl/window.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/outdata.hxx>
+#include <vcl/print.hxx>
+#include <vcl/outdev.h>
+#include <vcl/outdev.hxx>
+#include <vcl/unowrap.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+
+#include <com/sun/star/awt/XGraphics.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <vcl/unohelp.hxx>
+
+#include <numeric>
+
+using namespace ::com::sun::star;
+
+DBG_NAME( OutputDevice )
+DBG_NAME( Polygon )
+DBG_NAME( PolyPolygon )
+DBG_NAMEEX( Region )
+
+// -----------------------------------------------------------------------
+
+#ifdef DBG_UTIL
+const char* ImplDbgCheckOutputDevice( const void* pObj )
+{
+ DBG_TESTSOLARMUTEX();
+
+ const OutputDevice* pOutDev = (OutputDevice*)pObj;
+
+ if ( (pOutDev->GetOutDevType() != OUTDEV_DONTKNOW) &&
+ (pOutDev->GetOutDevType() != OUTDEV_WINDOW) &&
+ (pOutDev->GetOutDevType() != OUTDEV_PRINTER) &&
+ (pOutDev->GetOutDevType() != OUTDEV_VIRDEV) )
+ return "OutputDevice data overwrite";
+
+ return NULL;
+}
+#endif
+
+// =======================================================================
+
+#define OUTDEV_POLYPOLY_STACKBUF 32
+
+// =======================================================================
+
+struct ImplObjStack
+{
+ ImplObjStack* mpPrev;
+ MapMode* mpMapMode;
+ Region* mpClipRegion;
+ Color* mpLineColor;
+ Color* mpFillColor;
+ Font* mpFont;
+ Color* mpTextColor;
+ Color* mpTextFillColor;
+ Color* mpTextLineColor;
+ Color* mpOverlineColor;
+ Point* mpRefPoint;
+ TextAlign meTextAlign;
+ RasterOp meRasterOp;
+ ULONG mnTextLayoutMode;
+ LanguageType meTextLanguage;
+ USHORT mnFlags;
+};
+
+// -----------------------------------------------------------------------
+
+static void ImplDeleteObjStack( ImplObjStack* pObjStack )
+{
+ if ( pObjStack->mnFlags & PUSH_LINECOLOR )
+ {
+ if ( pObjStack->mpLineColor )
+ delete pObjStack->mpLineColor;
+ }
+ if ( pObjStack->mnFlags & PUSH_FILLCOLOR )
+ {
+ if ( pObjStack->mpFillColor )
+ delete pObjStack->mpFillColor;
+ }
+ if ( pObjStack->mnFlags & PUSH_FONT )
+ delete pObjStack->mpFont;
+ if ( pObjStack->mnFlags & PUSH_TEXTCOLOR )
+ delete pObjStack->mpTextColor;
+ if ( pObjStack->mnFlags & PUSH_TEXTFILLCOLOR )
+ {
+ if ( pObjStack->mpTextFillColor )
+ delete pObjStack->mpTextFillColor;
+ }
+ if ( pObjStack->mnFlags & PUSH_TEXTLINECOLOR )
+ {
+ if ( pObjStack->mpTextLineColor )
+ delete pObjStack->mpTextLineColor;
+ }
+ if ( pObjStack->mnFlags & PUSH_OVERLINECOLOR )
+ {
+ if ( pObjStack->mpOverlineColor )
+ delete pObjStack->mpOverlineColor;
+ }
+ if ( pObjStack->mnFlags & PUSH_MAPMODE )
+ {
+ if ( pObjStack->mpMapMode )
+ delete pObjStack->mpMapMode;
+ }
+ if ( pObjStack->mnFlags & PUSH_CLIPREGION )
+ {
+ if ( pObjStack->mpClipRegion )
+ delete pObjStack->mpClipRegion;
+ }
+ if ( pObjStack->mnFlags & PUSH_REFPOINT )
+ {
+ if ( pObjStack->mpRefPoint )
+ delete pObjStack->mpRefPoint;
+ }
+
+ delete pObjStack;
+}
+
+// -----------------------------------------------------------------------
+
+bool OutputDevice::ImplIsAntiparallel() const
+{
+ bool bRet = false;
+ if( ImplGetGraphics() )
+ {
+ if( ( (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && ! IsRTLEnabled() ) ||
+ ( ! (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && IsRTLEnabled() ) )
+ {
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+
+bool OutputDevice::ImplSelectClipRegion( const Region& rRegion, SalGraphics* pGraphics )
+{
+ DBG_TESTSOLARMUTEX();
+
+ // TODO(Q3): Change from static to plain method - everybody's
+ // calling it with pOutDev=this!
+ // => done, but only with minimal changes for now => TODO
+ OutputDevice* const pOutDev = this;
+ if( !pGraphics )
+ {
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return false;
+ pGraphics = mpGraphics;
+ }
+
+ if( rRegion.HasPolyPolygon()
+ && pGraphics->supportsOperation( OutDevSupport_B2DClip ) )
+ {
+ const ::basegfx::B2DPolyPolygon& rB2DPolyPolygon = rRegion.GetB2DPolyPolygon();
+ pGraphics->BeginSetClipRegion( 0 );
+ pGraphics->UnionClipRegion( rB2DPolyPolygon, pOutDev );
+ pGraphics->EndSetClipRegion();
+ return true;
+ }
+
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ULONG nRectCount;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+ BOOL bClipRegion = TRUE;
+ const BOOL bClipDeviceBounds( !pOutDev->GetPDFWriter()
+ && pOutDev->GetOutDevType() != OUTDEV_PRINTER );
+
+ nRectCount = rRegion.GetRectCount();
+ pGraphics->BeginSetClipRegion( nRectCount );
+ bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ if( bClipDeviceBounds )
+ {
+ // #b6520266# Perform actual rect clip against outdev
+ // dimensions, to generate empty clips whenever one of the
+ // values is completely off the device.
+ const long nOffX( pOutDev->mnOutOffX );
+ const long nOffY( pOutDev->mnOutOffY );
+ const long nDeviceWidth( pOutDev->GetOutputWidthPixel() );
+ const long nDeviceHeight( pOutDev->GetOutputHeightPixel() );
+ Rectangle aDeviceBounds( nOffX, nOffY,
+ nOffX+nDeviceWidth-1,
+ nOffY+nDeviceHeight-1 );
+ while ( bRegionRect )
+ {
+ // #i59315# Limit coordinates passed to sal layer to actual
+ // outdev dimensions - everything else bears the risk of
+ // overflowing internal coordinates (e.g. the 16 bit wire
+ // format of X11).
+ Rectangle aTmpRect(nX,nY,nX+nWidth-1,nY+nHeight-1);
+ aTmpRect.Intersection(aDeviceBounds);
+
+ if( !aTmpRect.IsEmpty() )
+ {
+ if ( !pGraphics->UnionClipRegion( aTmpRect.Left(),
+ aTmpRect.Top(),
+ aTmpRect.GetWidth(),
+ aTmpRect.GetHeight(),
+ pOutDev ) )
+ {
+ bClipRegion = FALSE;
+ }
+ }
+ else
+ {
+ // #i79850# Fake off-screen clip
+ if ( !pGraphics->UnionClipRegion( nDeviceWidth+1,
+ nDeviceHeight+1,
+ 1, 1,
+ pOutDev ) )
+ {
+ bClipRegion = FALSE;
+ }
+ }
+ DBG_ASSERT( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't create region" );
+ bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ }
+ else
+ {
+ // #i65720# Actually, _don't_ clip anything on printer or PDF
+ // export, since output might be visible outside the specified
+ // device boundaries.
+ while ( bRegionRect )
+ {
+ if ( !pGraphics->UnionClipRegion( nX, nY, nWidth, nHeight, pOutDev ) )
+ bClipRegion = FALSE;
+ DBG_ASSERT( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't cerate region" );
+ bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ }
+ pGraphics->EndSetClipRegion();
+ return bClipRegion;
+}
+
+
+// =======================================================================
+
+Polygon ImplSubdivideBezier( const Polygon& rPoly )
+{
+ Polygon aPoly;
+
+ // #100127# Use adaptive subdivide instead of fixed 25 segments
+ rPoly.AdaptiveSubdivide( aPoly );
+
+ return aPoly;
+}
+
+// =======================================================================
+
+PolyPolygon ImplSubdivideBezier( const PolyPolygon& rPolyPoly )
+{
+ USHORT i, nPolys = rPolyPoly.Count();
+ PolyPolygon aPolyPoly( nPolys );
+ for( i=0; i<nPolys; ++i )
+ aPolyPoly.Insert( ImplSubdivideBezier( rPolyPoly.GetObject(i) ) );
+
+ return aPolyPoly;
+}
+
+// =======================================================================
+
+// #100127# Extracted from OutputDevice::DrawPolyPolygon()
+void OutputDevice::ImplDrawPolyPolygon( USHORT nPoly, const PolyPolygon& rPolyPoly )
+{
+ // AW: This crashes on empty PolyPolygons, avoid that
+ if(!nPoly)
+ return;
+
+ sal_uInt32 aStackAry1[OUTDEV_POLYPOLY_STACKBUF];
+ PCONSTSALPOINT aStackAry2[OUTDEV_POLYPOLY_STACKBUF];
+ BYTE* aStackAry3[OUTDEV_POLYPOLY_STACKBUF];
+ sal_uInt32* pPointAry;
+ PCONSTSALPOINT* pPointAryAry;
+ const BYTE** pFlagAryAry;
+ USHORT i = 0, j = 0, last = 0;
+ BOOL bHaveBezier = sal_False;
+ if ( nPoly > OUTDEV_POLYPOLY_STACKBUF )
+ {
+ pPointAry = new sal_uInt32[nPoly];
+ pPointAryAry = new PCONSTSALPOINT[nPoly];
+ pFlagAryAry = new const BYTE*[nPoly];
+ }
+ else
+ {
+ pPointAry = aStackAry1;
+ pPointAryAry = aStackAry2;
+ pFlagAryAry = (const BYTE**)aStackAry3;
+ }
+ do
+ {
+ const Polygon& rPoly = rPolyPoly.GetObject( i );
+ USHORT nSize = rPoly.GetSize();
+ if ( nSize )
+ {
+ pPointAry[j] = nSize;
+ pPointAryAry[j] = (PCONSTSALPOINT)rPoly.GetConstPointAry();
+ pFlagAryAry[j] = rPoly.GetConstFlagAry();
+ last = i;
+
+ if( pFlagAryAry[j] )
+ bHaveBezier = sal_True;
+
+ ++j;
+ }
+
+ ++i;
+ }
+ while ( i < nPoly );
+
+ if ( j == 1 )
+ {
+ // #100127# Forward beziers to sal, if any
+ if( bHaveBezier )
+ {
+ if( !mpGraphics->DrawPolygonBezier( *pPointAry, *pPointAryAry, *pFlagAryAry, this ) )
+ {
+ Polygon aPoly = ImplSubdivideBezier( rPolyPoly.GetObject( last ) );
+ mpGraphics->DrawPolygon( aPoly.GetSize(), (const SalPoint*)aPoly.GetConstPointAry(), this );
+ }
+ }
+ else
+ {
+ mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this );
+ }
+ }
+ else
+ {
+ // #100127# Forward beziers to sal, if any
+ if( bHaveBezier )
+ {
+ if( !mpGraphics->DrawPolyPolygonBezier( j, pPointAry, pPointAryAry, pFlagAryAry, this ) )
+ {
+ PolyPolygon aPolyPoly = ImplSubdivideBezier( rPolyPoly );
+ ImplDrawPolyPolygon( aPolyPoly.Count(), aPolyPoly );
+ }
+ }
+ else
+ {
+ mpGraphics->DrawPolyPolygon( j, pPointAry, pPointAryAry, this );
+ }
+ }
+
+ if ( pPointAry != aStackAry1 )
+ {
+ delete[] pPointAry;
+ delete[] pPointAryAry;
+ delete[] pFlagAryAry;
+ }
+}
+
+// =======================================================================
+
+OutputDevice::OutputDevice() :
+ maRegion( REGION_NULL ),
+ maFillColor( COL_WHITE ),
+ maTextLineColor( COL_TRANSPARENT ),
+ maSettings( Application::GetSettings() )
+{
+ DBG_CTOR( OutputDevice, ImplDbgCheckOutputDevice );
+
+ mpGraphics = NULL;
+ mpUnoGraphicsList = NULL;
+ mpPrevGraphics = NULL;
+ mpNextGraphics = NULL;
+ mpMetaFile = NULL;
+ mpFontEntry = NULL;
+ mpFontCache = NULL;
+ mpFontList = NULL;
+ mpGetDevFontList = NULL;
+ mpGetDevSizeList = NULL;
+ mpObjStack = NULL;
+ mpOutDevData = NULL;
+ mpPDFWriter = NULL;
+ mpAlphaVDev = NULL;
+ mpExtOutDevData = NULL;
+ mnOutOffX = 0;
+ mnOutOffY = 0;
+ mnOutWidth = 0;
+ mnOutHeight = 0;
+ mnDPIX = 0;
+ mnDPIY = 0;
+ mnTextOffX = 0;
+ mnTextOffY = 0;
+ mnOutOffOrigX = 0;
+ mnOutOffLogicX = 0;
+ mnOutOffOrigY = 0;
+ mnOutOffLogicY = 0;
+ mnEmphasisAscent = 0;
+ mnEmphasisDescent = 0;
+ mnDrawMode = 0;
+ mnTextLayoutMode = TEXT_LAYOUT_DEFAULT;
+ if( Application::GetSettings().GetLayoutRTL() ) //#i84553# tip BiDi preference to RTL
+ mnTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
+ meOutDevType = OUTDEV_DONTKNOW;
+ meOutDevViewType = OUTDEV_VIEWTYPE_DONTKNOW;
+ mbMap = FALSE;
+ mbMapIsDefault = TRUE;
+ mbClipRegion = FALSE;
+ mbBackground = FALSE;
+ mbOutput = TRUE;
+ mbDevOutput = FALSE;
+ mbOutputClipped = FALSE;
+ maTextColor = Color( COL_BLACK );
+ maOverlineColor = Color( COL_TRANSPARENT );
+ meTextAlign = maFont.GetAlign();
+ meRasterOp = ROP_OVERPAINT;
+ mnAntialiasing = 0;
+ meTextLanguage = 0; // TODO: get default from configuration?
+ mbLineColor = TRUE;
+ mbFillColor = TRUE;
+ mbInitLineColor = TRUE;
+ mbInitFillColor = TRUE;
+ mbInitFont = TRUE;
+ mbInitTextColor = TRUE;
+ mbInitClipRegion = TRUE;
+ mbClipRegionSet = FALSE;
+ mbKerning = FALSE;
+ mbNewFont = TRUE;
+ mbTextLines = FALSE;
+ mbTextSpecial = FALSE;
+ mbRefPoint = FALSE;
+ mbEnableRTL = FALSE; // mirroring must be explicitly allowed (typically for windows only)
+
+ // struct ImplMapRes
+ maMapRes.mnMapOfsX = 0;
+ maMapRes.mnMapOfsY = 0;
+ maMapRes.mnMapScNumX = 1;
+ maMapRes.mnMapScNumY = 1;
+ maMapRes.mnMapScDenomX = 1;
+ maMapRes.mnMapScDenomY = 1;
+ // struct ImplThresholdRes
+ maThresRes.mnThresLogToPixX = 0;
+ maThresRes.mnThresLogToPixY = 0;
+ maThresRes.mnThresPixToLogX = 0;
+ maThresRes.mnThresPixToLogY = 0;
+}
+
+// -----------------------------------------------------------------------
+
+OutputDevice::~OutputDevice()
+{
+ DBG_DTOR( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( GetUnoGraphicsList() )
+ {
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper( FALSE );
+ if ( pWrapper )
+ pWrapper->ReleaseAllGraphics( this );
+ delete mpUnoGraphicsList;
+ mpUnoGraphicsList = NULL;
+ }
+
+ if ( mpOutDevData )
+ ImplDeInitOutDevData();
+
+ ImplObjStack* pData = mpObjStack;
+ if ( pData )
+ {
+ DBG_ERRORFILE( "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" );
+ while ( pData )
+ {
+ ImplObjStack* pTemp = pData;
+ pData = pData->mpPrev;
+ ImplDeleteObjStack( pTemp );
+ }
+ }
+
+ // release the active font instance
+ if( mpFontEntry )
+ mpFontCache->Release( mpFontEntry );
+ // remove cached results of GetDevFontList/GetDevSizeList
+ // TODO: use smart pointers for them
+ if( mpGetDevFontList )
+ delete mpGetDevFontList;
+ if( mpGetDevSizeList )
+ delete mpGetDevSizeList;
+
+ // release ImplFontCache specific to this OutputDevice
+ // TODO: refcount ImplFontCache
+ if( mpFontCache
+ && (mpFontCache != ImplGetSVData()->maGDIData.mpScreenFontCache)
+ && (ImplGetSVData()->maGDIData.mpScreenFontCache != NULL) )
+ {
+ delete mpFontCache;
+ mpFontCache = NULL;
+ }
+
+ // release ImplFontList specific to this OutputDevice
+ // TODO: refcount ImplFontList
+ if( mpFontList
+ && (mpFontList != ImplGetSVData()->maGDIData.mpScreenFontList)
+ && (ImplGetSVData()->maGDIData.mpScreenFontList != NULL) )
+ {
+ mpFontList->Clear();
+ delete mpFontList;
+ mpFontList = NULL;
+ }
+
+ delete mpAlphaVDev;
+}
+
+bool OutputDevice::supportsOperation( OutDevSupportType eType ) const
+{
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return false;
+ const bool bHasSupport = mpGraphics->supportsOperation( eType );
+ return bHasSupport;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::EnableRTL( BOOL bEnable )
+{
+ mbEnableRTL = (bEnable != 0);
+ if( meOutDevType == OUTDEV_VIRDEV )
+ {
+ // virdevs default to not mirroring, they will only be set to mirroring
+ // under rare circumstances in the UI, eg the valueset control
+ // because each virdev has its own SalGraphics we can safely switch the SalGraphics here
+ // ...hopefully
+ if( ImplGetGraphics() )
+ mpGraphics->SetLayout( mbEnableRTL ? SAL_LAYOUT_BIDI_RTL : 0 );
+ }
+
+ // convenience: for controls also switch layout mode
+ if( dynamic_cast<Control*>(this) != 0 )
+ SetLayoutMode( bEnable ? TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT : TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT);
+
+ Window* pWin = dynamic_cast<Window*>(this);
+ if( pWin )
+ pWin->StateChanged( STATE_CHANGE_MIRRORING );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->EnableRTL( bEnable );
+}
+
+BOOL OutputDevice::ImplHasMirroredGraphics()
+{
+ // HOTFIX for #i55719#
+ if( meOutDevType == OUTDEV_PRINTER )
+ return FALSE;
+
+ return ( ImplGetGraphics() && (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) );
+}
+
+// note: the coordiantes to be remirrored are in frame coordiantes !
+
+void OutputDevice::ImplReMirror( Point &rPoint ) const
+{
+ rPoint.X() = mnOutOffX + mnOutWidth - 1 - rPoint.X() + mnOutOffX;
+}
+void OutputDevice::ImplReMirror( Rectangle &rRect ) const
+{
+ long nWidth = rRect.nRight - rRect.nLeft;
+
+ //long lc_x = rRect.nLeft - mnOutOffX; // normalize
+ //lc_x = mnOutWidth - nWidth - 1 - lc_x; // mirror
+ //rRect.nLeft = lc_x + mnOutOffX; // re-normalize
+
+ rRect.nLeft = mnOutOffX + mnOutWidth - nWidth - 1 - rRect.nLeft + mnOutOffX;
+ rRect.nRight = rRect.nLeft + nWidth;
+}
+void OutputDevice::ImplReMirror( Region &rRegion ) const
+{
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+ Region aMirroredRegion;
+
+ bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ while ( bRegionRect )
+ {
+ Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) );
+ ImplReMirror( aRect );
+ aMirroredRegion.Union( aRect );
+ bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ rRegion = aMirroredRegion;
+}
+
+
+// -----------------------------------------------------------------------
+
+int OutputDevice::ImplGetGraphics() const
+{
+ DBG_TESTSOLARMUTEX();
+
+ if ( mpGraphics )
+ return TRUE;
+
+ mbInitLineColor = TRUE;
+ mbInitFillColor = TRUE;
+ mbInitFont = TRUE;
+ mbInitTextColor = TRUE;
+ mbInitClipRegion = TRUE;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( meOutDevType == OUTDEV_WINDOW )
+ {
+ Window* pWindow = (Window*)this;
+
+ mpGraphics = pWindow->mpWindowImpl->mpFrame->GetGraphics();
+ // try harder if no wingraphics was available directly
+ if ( !mpGraphics )
+ {
+ // find another output device in the same frame
+ OutputDevice* pReleaseOutDev = pSVData->maGDIData.mpLastWinGraphics;
+ while ( pReleaseOutDev )
+ {
+ if ( ((Window*)pReleaseOutDev)->mpWindowImpl->mpFrame == pWindow->mpWindowImpl->mpFrame )
+ break;
+ pReleaseOutDev = pReleaseOutDev->mpPrevGraphics;
+ }
+
+ if ( pReleaseOutDev )
+ {
+ // steal the wingraphics from the other outdev
+ mpGraphics = pReleaseOutDev->mpGraphics;
+ pReleaseOutDev->ImplReleaseGraphics( FALSE );
+ }
+ else
+ {
+ // if needed retry after releasing least recently used wingraphics
+ while ( !mpGraphics )
+ {
+ if ( !pSVData->maGDIData.mpLastWinGraphics )
+ break;
+ pSVData->maGDIData.mpLastWinGraphics->ImplReleaseGraphics();
+ mpGraphics = pWindow->mpWindowImpl->mpFrame->GetGraphics();
+ }
+ }
+ }
+
+ // update global LRU list of wingraphics
+ if ( mpGraphics )
+ {
+ mpNextGraphics = pSVData->maGDIData.mpFirstWinGraphics;
+ pSVData->maGDIData.mpFirstWinGraphics = const_cast<OutputDevice*>(this);
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
+ if ( !pSVData->maGDIData.mpLastWinGraphics )
+ pSVData->maGDIData.mpLastWinGraphics = const_cast<OutputDevice*>(this);
+ }
+ }
+ else if ( meOutDevType == OUTDEV_VIRDEV )
+ {
+ const VirtualDevice* pVirDev = (const VirtualDevice*)this;
+
+ if ( pVirDev->mpVirDev )
+ {
+ mpGraphics = pVirDev->mpVirDev->GetGraphics();
+ // if needed retry after releasing least recently used virtual device graphics
+ while ( !mpGraphics )
+ {
+ if ( !pSVData->maGDIData.mpLastVirGraphics )
+ break;
+ pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics();
+ mpGraphics = pVirDev->mpVirDev->GetGraphics();
+ }
+ // update global LRU list of virtual device graphics
+ if ( mpGraphics )
+ {
+ mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
+ pSVData->maGDIData.mpFirstVirGraphics = const_cast<OutputDevice*>(this);
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
+ if ( !pSVData->maGDIData.mpLastVirGraphics )
+ pSVData->maGDIData.mpLastVirGraphics = const_cast<OutputDevice*>(this);
+ }
+ }
+ }
+ else if ( meOutDevType == OUTDEV_PRINTER )
+ {
+ const Printer* pPrinter = (const Printer*)this;
+
+ if ( pPrinter->mpJobGraphics )
+ mpGraphics = pPrinter->mpJobGraphics;
+ else if ( pPrinter->mpDisplayDev )
+ {
+ const VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
+ mpGraphics = pVirDev->mpVirDev->GetGraphics();
+ // if needed retry after releasing least recently used virtual device graphics
+ while ( !mpGraphics )
+ {
+ if ( !pSVData->maGDIData.mpLastVirGraphics )
+ break;
+ pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics();
+ mpGraphics = pVirDev->mpVirDev->GetGraphics();
+ }
+ // update global LRU list of virtual device graphics
+ if ( mpGraphics )
+ {
+ mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
+ pSVData->maGDIData.mpFirstVirGraphics = const_cast<OutputDevice*>(this);
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
+ if ( !pSVData->maGDIData.mpLastVirGraphics )
+ pSVData->maGDIData.mpLastVirGraphics = const_cast<OutputDevice*>(this);
+ }
+ }
+ else
+ {
+ mpGraphics = pPrinter->mpInfoPrinter->GetGraphics();
+ // if needed retry after releasing least recently used printer graphics
+ while ( !mpGraphics )
+ {
+ if ( !pSVData->maGDIData.mpLastPrnGraphics )
+ break;
+ pSVData->maGDIData.mpLastPrnGraphics->ImplReleaseGraphics();
+ mpGraphics = pPrinter->mpInfoPrinter->GetGraphics();
+ }
+ // update global LRU list of printer graphics
+ if ( mpGraphics )
+ {
+ mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics;
+ pSVData->maGDIData.mpFirstPrnGraphics = const_cast<OutputDevice*>(this);
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
+ if ( !pSVData->maGDIData.mpLastPrnGraphics )
+ pSVData->maGDIData.mpLastPrnGraphics = const_cast<OutputDevice*>(this);
+ }
+ }
+ }
+
+ if ( mpGraphics )
+ {
+ mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp), ROP_INVERT == meRasterOp );
+ mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplReleaseGraphics( BOOL bRelease )
+{
+ DBG_TESTSOLARMUTEX();
+
+ if ( !mpGraphics )
+ return;
+
+ // release the fonts of the physically released graphics device
+ if( bRelease )
+ {
+#ifndef UNX
+ // HACK to fix an urgent P1 printing issue fast
+ // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions
+ // so Printer::mpGraphics often points to a dead WinSalGraphics
+ // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling
+ if( meOutDevType != OUTDEV_PRINTER )
+#endif
+ mpGraphics->ReleaseFonts();
+
+ mbNewFont = true;
+ mbInitFont = true;
+
+ if ( mpFontEntry )
+ {
+ mpFontCache->Release( mpFontEntry );
+ mpFontEntry = NULL;
+ }
+
+ if ( mpGetDevFontList )
+ {
+ delete mpGetDevFontList;
+ mpGetDevFontList = NULL;
+ }
+
+ if ( mpGetDevSizeList )
+ {
+ delete mpGetDevSizeList;
+ mpGetDevSizeList = NULL;
+ }
+ }
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( meOutDevType == OUTDEV_WINDOW )
+ {
+ Window* pWindow = (Window*)this;
+
+ if ( bRelease )
+ pWindow->mpWindowImpl->mpFrame->ReleaseGraphics( mpGraphics );
+ // remove from global LRU list of window graphics
+ if ( mpPrevGraphics )
+ mpPrevGraphics->mpNextGraphics = mpNextGraphics;
+ else
+ pSVData->maGDIData.mpFirstWinGraphics = mpNextGraphics;
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
+ else
+ pSVData->maGDIData.mpLastWinGraphics = mpPrevGraphics;
+ }
+ else if ( meOutDevType == OUTDEV_VIRDEV )
+ {
+ VirtualDevice* pVirDev = (VirtualDevice*)this;
+
+ if ( bRelease )
+ pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
+ // remove from global LRU list of virtual device graphics
+ if ( mpPrevGraphics )
+ mpPrevGraphics->mpNextGraphics = mpNextGraphics;
+ else
+ pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
+ else
+ pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
+ }
+ else if ( meOutDevType == OUTDEV_PRINTER )
+ {
+ Printer* pPrinter = (Printer*)this;
+
+ if ( !pPrinter->mpJobGraphics )
+ {
+ if ( pPrinter->mpDisplayDev )
+ {
+ VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
+ if ( bRelease )
+ pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
+ // remove from global LRU list of virtual device graphics
+ if ( mpPrevGraphics )
+ mpPrevGraphics->mpNextGraphics = mpNextGraphics;
+ else
+ pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
+ else
+ pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
+ }
+ else
+ {
+ if ( bRelease )
+ pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics );
+ // remove from global LRU list of printer graphics
+ if ( mpPrevGraphics )
+ mpPrevGraphics->mpNextGraphics = mpNextGraphics;
+ else
+ pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics;
+ if ( mpNextGraphics )
+ mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
+ else
+ pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics;
+ }
+ }
+ }
+
+ mpGraphics = NULL;
+ mpPrevGraphics = NULL;
+ mpNextGraphics = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplInitOutDevData()
+{
+ if ( !mpOutDevData )
+ {
+ mpOutDevData = new ImplOutDevData;
+ mpOutDevData->mpRotateDev = NULL;
+ mpOutDevData->mpRecordLayout = NULL;
+
+ // #i75163#
+ mpOutDevData->mpViewTransform = NULL;
+ mpOutDevData->mpInverseViewTransform = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// #i75163#
+void OutputDevice::ImplInvalidateViewTransform()
+{
+ if(mpOutDevData)
+ {
+ if(mpOutDevData->mpViewTransform)
+ {
+ delete mpOutDevData->mpViewTransform;
+ mpOutDevData->mpViewTransform = NULL;
+ }
+
+ if(mpOutDevData->mpInverseViewTransform)
+ {
+ delete mpOutDevData->mpInverseViewTransform;
+ mpOutDevData->mpInverseViewTransform = NULL;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::ImplIsRecordLayout() const
+{
+ return mpOutDevData && mpOutDevData->mpRecordLayout;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDeInitOutDevData()
+{
+ if ( mpOutDevData )
+ {
+ if ( mpOutDevData->mpRotateDev )
+ delete mpOutDevData->mpRotateDev;
+
+ // #i75163#
+ ImplInvalidateViewTransform();
+
+ delete mpOutDevData;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplInitLineColor()
+{
+ DBG_TESTSOLARMUTEX();
+
+ if( mbLineColor )
+ {
+ if( ROP_0 == meRasterOp )
+ mpGraphics->SetROPLineColor( SAL_ROP_0 );
+ else if( ROP_1 == meRasterOp )
+ mpGraphics->SetROPLineColor( SAL_ROP_1 );
+ else if( ROP_INVERT == meRasterOp )
+ mpGraphics->SetROPLineColor( SAL_ROP_INVERT );
+ else
+ mpGraphics->SetLineColor( ImplColorToSal( maLineColor ) );
+ }
+ else
+ mpGraphics->SetLineColor();
+
+ mbInitLineColor = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplInitFillColor()
+{
+ DBG_TESTSOLARMUTEX();
+
+ if( mbFillColor )
+ {
+ if( ROP_0 == meRasterOp )
+ mpGraphics->SetROPFillColor( SAL_ROP_0 );
+ else if( ROP_1 == meRasterOp )
+ mpGraphics->SetROPFillColor( SAL_ROP_1 );
+ else if( ROP_INVERT == meRasterOp )
+ mpGraphics->SetROPFillColor( SAL_ROP_INVERT );
+ else
+ mpGraphics->SetFillColor( ImplColorToSal( maFillColor ) );
+ }
+ else
+ mpGraphics->SetFillColor();
+
+ mbInitFillColor = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplInitClipRegion()
+{
+ DBG_TESTSOLARMUTEX();
+
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ Window* pWindow = (Window*)this;
+ Region aRegion;
+
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( pWindow->mpWindowImpl->mpFrameData->mpFirstBackWin )
+ pWindow->ImplInvalidateAllOverlapBackgrounds();
+ if ( pWindow->mpWindowImpl->mbInPaint )
+ aRegion = *(pWindow->mpWindowImpl->mpPaintRegion);
+ else
+ {
+ aRegion = *(pWindow->ImplGetWinChildClipRegion());
+ // --- RTL -- only this region is in frame coordinates, so re-mirror it
+ // the mpWindowImpl->mpPaintRegion above is already correct (see ImplCallPaint()) !
+ if( ImplIsAntiparallel() )
+ ImplReMirror ( aRegion );
+ }
+ if ( mbClipRegion )
+ aRegion.Intersect( ImplPixelToDevicePixel( maRegion ) );
+ if ( aRegion.IsEmpty() )
+ mbOutputClipped = TRUE;
+ else
+ {
+ mbOutputClipped = FALSE;
+ ImplSelectClipRegion( aRegion );
+ }
+ mbClipRegionSet = TRUE;
+ }
+ else
+ {
+ if ( mbClipRegion )
+ {
+ if ( maRegion.IsEmpty() )
+ mbOutputClipped = TRUE;
+ else
+ {
+ mbOutputClipped = FALSE;
+ ImplSelectClipRegion(
+ // #102532# Respect output offset also for clip region
+ ImplPixelToDevicePixel( maRegion ) );
+ }
+
+ mbClipRegionSet = TRUE;
+ }
+ else
+ {
+ if ( mbClipRegionSet )
+ {
+ mpGraphics->ResetClipRegion();
+ mbClipRegionSet = FALSE;
+ }
+
+ mbOutputClipped = FALSE;
+ }
+ }
+
+ mbInitClipRegion = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplSetClipRegion( const Region* pRegion )
+{
+ DBG_TESTSOLARMUTEX();
+
+ if ( !pRegion )
+ {
+ if ( mbClipRegion )
+ {
+ maRegion = Region( REGION_NULL );
+ mbClipRegion = FALSE;
+ mbInitClipRegion = TRUE;
+ }
+ }
+ else
+ {
+ maRegion = *pRegion;
+ mbClipRegion = TRUE;
+ mbInitClipRegion = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+namespace
+{
+ inline int iround( float x )
+ {
+ union
+ {
+ float f;
+ sal_Int32 i;
+ };
+ f = x;
+ sal_Int32 exponent = (127 + 31) - ((i >> 23) & 0xFF);
+ sal_Int32 r = ((sal_Int32(i) << 8) | (1U << 31)) >> exponent;
+ r &= ((exponent - 32) >> 31);
+ sal_Int32 sign = i >> 31;
+ return r = (r ^ sign) - sign;
+ }
+
+ inline int floorDiv(int a, int b)
+ {
+ if(b == 0)
+ return 0x80000000;
+ if(a >= 0)
+ return a / b;
+ int q = -(-a / b); // quotient
+ int r = -a % b; // remainder
+ if(r)
+ q--;
+ return q;
+ }
+
+ inline int floorMod( int a, int b )
+ {
+ if(b == 0)
+ return 0x80000000;
+ if(a >= 0)
+ return a % b;
+ int r = -a % b; // remainder
+ if(r)
+ r = b - r;
+ return r;
+ }
+
+ inline int ceilDiv( int a, int b )
+ {
+ if(b == 0)
+ return 0x80000000;
+ a += - 1 + b;
+ if(a >= 0)
+ return a / b;
+ int q = -(-a / b); // quotient
+ int r = -a % b; // remainder
+ if(r)
+ q--;
+ return q;
+ }
+
+ inline int ceilMod( int a, int b )
+ {
+ if(b == 0)
+ return 0x80000000;
+ a += - 1 + b;
+ if(a >= 0)
+ return (a % b) + 1 - b;
+ int r = -a % b;
+ if(r)
+ r = b - r;
+ return r + 1 - b;
+ }
+
+ inline int ceilFix4(int x) { return (x + 0xF) & 0xFFFFFFF0; }
+
+ struct vertex
+ {
+ float x,y;
+ inline vertex( const Point &p )
+ : x((float)p.getX()),y((float)p.getY()) {}
+ };
+
+ template<class T> inline void swap(T &a, T &b) { T t=a; a=b; b=t; }
+
+ class SpanIterator
+ {
+ public:
+
+ SpanIterator( sal_Int32 *pTable, size_t dwPitch, sal_Int32 dwNumScanlines );
+ std::pair<sal_Int32,sal_Int32> GetNextSpan( void );
+ sal_Int32 GetNumRemainingScanlines( void );
+ sal_Int32 GetNumEqualScanlines( void );
+ SpanIterator &operator++ ();
+ SpanIterator &Skip( sal_Int32 dwNumScanlines );
+ sal_Int32 GetRemainingSpans( void ) const { return maNumSpans; }
+
+ private:
+
+ sal_Int32 *mpTable;
+ sal_Int32 *mpSpanArray;
+ sal_Int32 maNumSpans;
+ sal_Int32 maRemainingScanlines;
+ size_t maPitch;
+ };
+
+ inline SpanIterator::SpanIterator( sal_Int32 *pTable, size_t dwPitch, sal_Int32 dwNumScanlines )
+ : mpTable(pTable),maRemainingScanlines(dwNumScanlines),maPitch(dwPitch)
+ {
+ sal_Int32 *pNumSpans = mpTable;
+ mpSpanArray = reinterpret_cast<sal_Int32 *>(pNumSpans+2);
+ maNumSpans = *pNumSpans;
+ }
+
+ inline SpanIterator &SpanIterator::operator++ ()
+ {
+ --maRemainingScanlines;
+ mpTable += maPitch;
+ sal_Int32 *pNumSpans = mpTable;
+ mpSpanArray = reinterpret_cast<sal_Int32 *>(pNumSpans+2);
+ maNumSpans = *pNumSpans;
+ return (*this);
+ }
+
+ inline SpanIterator &SpanIterator::Skip( sal_Int32 dwNumScanlines )
+ {
+ // don't skip more scanlines than there are...
+ if(dwNumScanlines > maRemainingScanlines)
+ dwNumScanlines = maRemainingScanlines;
+
+ // skip in one fellow swoop...
+ maRemainingScanlines -= dwNumScanlines;
+ mpTable += maPitch * dwNumScanlines;
+
+ // initialize necessary query fields...
+ sal_Int32 *pNumSpans = mpTable;
+ mpSpanArray = reinterpret_cast<sal_Int32 *>(pNumSpans+2);
+ maNumSpans = *pNumSpans;
+ return (*this);
+ }
+
+ inline std::pair<sal_Int32,sal_Int32> SpanIterator::GetNextSpan( void )
+ {
+ sal_Int32 x(0);
+ sal_Int32 w(0);
+ if(maNumSpans)
+ {
+ x = *mpSpanArray++;
+ w = *mpSpanArray++;
+ --maNumSpans;
+ }
+ return std::pair<sal_Int32,sal_Int32>(x,w);
+ }
+
+ inline sal_Int32 SpanIterator::GetNumEqualScanlines( void )
+ {
+ return mpTable[1];
+ }
+
+ inline sal_Int32 SpanIterator::GetNumRemainingScanlines( void )
+ {
+ return maRemainingScanlines;
+ }
+
+ class ScanlineContainer
+ {
+
+ public:
+
+ ScanlineContainer( sal_uInt32 dwNumScanlines,
+ sal_uInt32 dwNumSpansPerScanline );
+
+ ~ScanlineContainer( void );
+
+ void InsertSpan( sal_Int32 y, sal_Int32 lx, sal_Int32 rx );
+
+ SpanIterator Iterate( void ) const { return SpanIterator(mpTable,maPitch,maNumScanlines); }
+
+ inline sal_uInt32 GetNumSpans( void ) const { return maNumberOfSpans; }
+
+ void Consolidate( void );
+
+ private:
+
+ // the span table will assist in determinate exactly how many clipping
+ // regions [that is *spans*] we will end up with.
+ // the counter for this purpose is right ahead.
+ sal_uInt32 maNumberOfSpans;
+
+ struct span
+ {
+ sal_Int32 x;
+ sal_Int32 w;
+ };
+
+ sal_uInt32 maNumScanlines;
+ sal_uInt32 maNumSpansPerScanline;
+ sal_Int32 *mpTable;
+ size_t maPitch;
+ };
+
+ ScanlineContainer::ScanlineContainer( sal_uInt32 dwNumScanlines,
+ sal_uInt32 dwNumSpansPerScanline ) : maNumScanlines(dwNumScanlines),
+ maNumSpansPerScanline(dwNumSpansPerScanline)
+ {
+ // #128002# add one scanline buffer at the end, as
+ // SpanIterator::Skip reads two bytes past the end.
+ ++dwNumScanlines;
+
+ // since each triangle could possibly add another span
+ // we can calculate the upper limit by [num scanlines * num triangles].
+ const sal_uInt32 dwNumPossibleRegions = dwNumScanlines*dwNumSpansPerScanline;
+
+ // calculate the number of bytes the span table will consume
+ const size_t dwTableSize = dwNumPossibleRegions*sizeof(span)+dwNumScanlines*(sizeof(sal_Int32)<<1);
+
+ // allocate the span table [on the stack]
+ mpTable = static_cast<sal_Int32 *>(rtl_allocateMemory(dwTableSize));
+
+ // calculate the table pitch, that is how many int's do i need to get from a scanline to the next.
+ maPitch = (dwNumSpansPerScanline*sizeof(span)/sizeof(sal_Int32))+2;
+
+ // we need to initialize the table here.
+ // the first *int* on each scanline tells us how many spans are on it.
+ sal_Int32 *pNumSpans = mpTable;
+ for(unsigned int i=0; i<dwNumScanlines; ++i)
+ {
+ pNumSpans[0] = 0;
+ pNumSpans[1] = 0;
+ pNumSpans += maPitch;
+ }
+
+ maNumberOfSpans = 0;
+ }
+
+ ScanlineContainer::~ScanlineContainer( void )
+ {
+ rtl_freeMemory(mpTable);
+ }
+
+ void ScanlineContainer::InsertSpan( sal_Int32 y, sal_Int32 lx, sal_Int32 rx )
+ {
+ // there's new incoming span which we need to store in the table.
+ // first see if its width contributes a valid span.
+ if(sal_Int32 dwSpanWidth = rx-lx)
+ {
+ // first select the appropriate scanline the new span.
+ sal_Int32 *pNumSpans = mpTable+(y*maPitch);
+ span *pSpanArray = reinterpret_cast<span *>(pNumSpans+2);
+
+ // retrieve the number of already contained spans.
+ sal_Int32 dwNumSpan = *pNumSpans;
+
+ // since we need to sort the spans from top to bottom
+ // and left to right, we need to find the correct location
+ // in the table.
+ sal_Int32 dwIndex = 0;
+ while(dwIndex<dwNumSpan)
+ {
+ // since we would like to avoid unnecessary spans
+ // we try to consolidate them if possible.
+ // consolidate with right neighbour
+ if(pSpanArray[dwIndex].x == rx)
+ {
+ pSpanArray[dwIndex].x = lx;
+ pSpanArray[dwIndex].w += dwSpanWidth;
+ return;
+ }
+
+ // consolidate with left neighbour
+ if((pSpanArray[dwIndex].x+pSpanArray[dwIndex].w) == lx)
+ {
+ pSpanArray[dwIndex].w += rx-lx;
+ return;
+ }
+
+ // no consolidation possible, either this is a completely
+ // seperate span or it is the first in the list.
+ if(pSpanArray[dwIndex].x > lx)
+ break;
+
+ // forward to next element in the list.
+ ++dwIndex;
+ }
+
+ // if we reach here, the new span needs to be stored
+ // in the table, increase the number of spans in the
+ // current scanline.
+ *pNumSpans = dwNumSpan+1;
+
+ // keep the list of spans in sorted order. 'dwIndex'
+ // is where we want to store the new span. 'dwNumSpan'
+ // is the number of spans already there. now we need
+ // to move the offending spans out of the way.
+ while(dwIndex != dwNumSpan)
+ {
+ pSpanArray[dwNumSpan].x = pSpanArray[dwNumSpan-1].x;
+ pSpanArray[dwNumSpan].w = pSpanArray[dwNumSpan-1].w;
+ --dwNumSpan;
+ }
+
+ // insert the new span
+ pSpanArray[dwIndex].x = lx;
+ pSpanArray[dwIndex].w = rx-lx;
+
+ // remember the total number of spans in the table.
+ ++maNumberOfSpans;
+ }
+ }
+
+ void ScanlineContainer::Consolidate( void )
+ {
+ sal_Int32 *pScanline = mpTable;
+
+ sal_Int32 dwRemaining = maNumScanlines;
+ while(dwRemaining)
+ {
+ sal_Int32 dwNumSpans = pScanline[0];
+ sal_Int32 *pSpanArray = pScanline+2;
+
+ sal_Int32 dwRest = dwRemaining-1;
+ sal_Int32 *pNext = pScanline;
+ while(dwRest)
+ {
+ pNext += maPitch;
+ sal_Int32 dwNumNextSpans = pNext[0];
+ sal_Int32 *pSpanArrayNext = pNext+2;
+ if(dwNumSpans != dwNumNextSpans)
+ break;
+
+ sal_Int32 dwCompare = dwNumSpans<<1;
+ while(dwCompare)
+ {
+ if(pSpanArray[dwCompare-1] != pSpanArrayNext[dwCompare-1])
+ break;
+ --dwCompare;
+ }
+ if(dwCompare)
+ break;
+
+ --dwRest;
+ }
+
+ const sal_Int32 dwNumEqualScanlines(dwRemaining-dwRest);
+ pScanline[1] = dwNumEqualScanlines;
+ pScanline += maPitch*dwNumEqualScanlines;
+ dwRemaining -= dwNumEqualScanlines;
+
+ // since we track the total number of spans to generate,
+ // we need to account for consolidated scanlines here.
+ if(dwNumEqualScanlines > 1)
+ maNumberOfSpans -= dwNumSpans * (dwNumEqualScanlines-1);
+ }
+ }
+}
+
+// TODO: we should consider passing a basegfx b2dpolypolygon here to
+// ensure that the signature isn't misleading.
+// if we could pass a b2dpolypolygon here, we could easily triangulate it.
+void OutputDevice::ImplSetTriangleClipRegion( const PolyPolygon &rPolyPolygon )
+{
+ DBG_TESTSOLARMUTEX();
+
+ if(!(IsDeviceOutputNecessary()))
+ return;
+ if(!(mpGraphics))
+ if(!(ImplGetGraphics()))
+ return;
+
+ if( mpGraphics->supportsOperation( OutDevSupport_B2DClip ) )
+ {
+#if 0
+ ::basegfx::B2DPolyPolygon aB2DPolyPolygon = rPolyPolygon.getB2DPolyPolygon();
+#else
+ // getB2DPolyPolygon() "optimizes away" some points
+ // which prevents reliable undoing of the "triangle thingy" parameter
+ // so the toolspoly -> b2dpoly conversion has to be done manually
+ ::basegfx::B2DPolyPolygon aB2DPolyPolygon;
+ for( USHORT nPolyIdx = 0; nPolyIdx < rPolyPolygon.Count(); ++nPolyIdx )
+ {
+ const Polygon& rPolygon = rPolyPolygon[ nPolyIdx ];
+ ::basegfx::B2DPolygon aB2DPoly;
+ for( USHORT nPointIdx = 0; nPointIdx < rPolygon.GetSize(); ++nPointIdx )
+ {
+ const Point& rPoint = rPolygon[ nPointIdx ];
+ const ::basegfx::B2DPoint aB2DPoint( rPoint.X(), rPoint.Y() );
+ aB2DPoly.append( aB2DPoint );
+ }
+ aB2DPolyPolygon.append( aB2DPoly );
+ }
+#endif
+
+ const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+ aB2DPolyPolygon.transform( aTransform );
+
+ // the rPolyPolygon argument is a "triangle thingy"
+ // so convert it to a normal polypolyon first
+ ::basegfx::B2DPolyPolygon aPolyTriangle;
+ const int nPolyCount = aB2DPolyPolygon.count();
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolygon rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
+ const int nPointCount = rPolygon.count();
+ for( int nPointIdx = 0; nPointIdx+2 < nPointCount; nPointIdx +=3 )
+ {
+ ::basegfx::B2DPolygon aTriangle;
+ aTriangle.append( rPolygon.getB2DPoint( nPointIdx+0 ) );
+ aTriangle.append( rPolygon.getB2DPoint( nPointIdx+1 ) );
+ aTriangle.append( rPolygon.getB2DPoint( nPointIdx+2 ) );
+ aPolyTriangle.append( aTriangle );
+ }
+ }
+
+ // now set the clip region with the real polypolygon
+ mpGraphics->BeginSetClipRegion( 0 );
+ mpGraphics->UnionClipRegion( aPolyTriangle, this );
+ mpGraphics->EndSetClipRegion();
+
+ // and mark the clip status as ready
+ mbOutputClipped = FALSE;
+ mbClipRegion = TRUE;
+ mbClipRegionSet = TRUE;
+ mbInitClipRegion = FALSE;
+ return;
+ }
+
+ sal_Int32 offset_x = 0;
+ sal_Int32 offset_y = 0;
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ offset_x = mnOutOffX+mnOutOffOrigX;
+ offset_y = mnOutOffY+mnOutOffOrigY;
+ }
+
+ // first of all we need to know the upper limit
+ // of the amount of possible clipping regions.
+ sal_Int32 maxy = SAL_MIN_INT32;
+ sal_Int32 miny = SAL_MAX_INT32;
+ sal_uInt32 dwNumTriangles = 0;
+ for(USHORT i=0; i<rPolyPolygon.Count(); ++i)
+ {
+ const Polygon &rPoly = rPolyPolygon.GetObject(i);
+ const sal_Int32 dwNumVertices = rPoly.GetSize();
+ if(!(dwNumVertices % 3))
+ {
+ for(USHORT j=0; j<rPoly.GetSize(); ++j)
+ {
+ const Point &p = rPoly.GetPoint(j);
+ if(p.Y() < miny)
+ miny = p.Y();
+ if(p.Y() > maxy)
+ maxy = p.Y();
+ }
+ dwNumTriangles += dwNumVertices / 3;
+ }
+ }
+
+ const sal_uInt32 dwNumScanlines = (maxy-miny);
+ if(!(dwNumScanlines))
+ {
+ // indicates that no output needs to be produced
+ // since the clipping region did not provide any
+ // visible areas.
+ mbOutputClipped = TRUE;
+
+ // indicates that a clip region has been
+ // presented to the output device.
+ mbClipRegion = TRUE;
+
+ // indicates that the set clipping region
+ // has been processed.
+ mbClipRegionSet = TRUE;
+
+ // under 'normal' circumstances a new clipping region
+ // needs to be processed by ImplInitClipRegion(),
+ // which we need to circumvent.
+ mbInitClipRegion = FALSE;
+ return;
+ }
+
+ // this container provides all services we need to
+ // efficiently store/retrieve spans from the table.
+ const sal_uInt32 dwNumSpansPerScanline = dwNumTriangles;
+ ScanlineContainer container(dwNumScanlines,dwNumSpansPerScanline);
+
+ // convert the incoming polypolygon to spans, we assume that
+ // the polypolygon has already been triangulated since we don't
+ // want to use the basegfx-types here. this could be leveraged
+ // after the tools-types had been removed.
+ for(USHORT i=0; i<rPolyPolygon.Count(); ++i)
+ {
+ const Polygon &rPoly = rPolyPolygon.GetObject(i);
+ const USHORT dwNumVertices = rPoly.GetSize();
+ if(!(dwNumVertices % 3))
+ {
+ for(USHORT j=0; j<dwNumVertices; j+=3)
+ {
+ const Point &p0 = rPoly.GetPoint(j+0);
+ const Point &p1 = rPoly.GetPoint(j+1);
+ const Point &p2 = rPoly.GetPoint(j+2);
+
+ // what now follows is an extremely fast triangle
+ // rasterizer from which all tricky and interesting
+ // parts were forcibly amputated.
+ // note: top.left fill-convention
+ vertex v0(p0);
+ vertex v1(p1);
+ vertex v2(p2);
+
+ //sprintf(string,"[%f,%f] [%f,%f] [%f,%f]\n",v0.x,v0.y,v1.x,v1.y,v2.x,v2.y);
+ //OSL_TRACE(string);
+
+ if(v0.y > v2.y) ::swap(v0, v2);
+ if(v1.y > v2.y) ::swap(v1, v2);
+ if(v0.y > v1.y) ::swap(v0, v1);
+
+ const float float2fixed(16.0f);
+
+ // vertex coordinates of the triangle [28.4 fixed-point]
+ const int i4x0 = iround(float2fixed * (v0.x - 0.5f));
+ const int i4y0 = iround(float2fixed * (v0.y - 0.5f));
+ const int i4x1 = iround(float2fixed * (v1.x - 0.5f));
+ const int i4y1 = iround(float2fixed * (v1.y - 0.5f));
+ const int i4x2 = iround(float2fixed * (v2.x - 0.5f));
+ const int i4y2 = iround(float2fixed * (v2.y - 0.5f));
+
+ // vertex coordinate deltas [28.4 fixed-point]
+ const int i4dx12 = i4x1-i4x0;
+ const int i4dy12 = i4y1-i4y0;
+ const int i4dx13 = i4x2-i4x0;
+ const int i4dy13 = i4y2-i4y0;
+ const int i4dx23 = i4x2-i4x1;
+ const int i4dy23 = i4y2-i4y1;
+
+ // slope of edges [quotient,remainder]
+ const int mq12 = floorDiv(i4dx12 << 4, i4dy12 << 4);
+ const int mq13 = floorDiv(i4dx13 << 4, i4dy13 << 4);
+ const int mq23 = floorDiv(i4dx23 << 4, i4dy23 << 4);
+ const int mr12 = floorMod(i4dx12 << 4, i4dy12 << 4);
+ const int mr13 = floorMod(i4dx13 << 4, i4dy13 << 4);
+ const int mr23 = floorMod(i4dx23 << 4, i4dy23 << 4);
+
+ // convert the vertical coordinates back to integers.
+ // according to the top-left fillrule we need to step
+ // the coordinates to the ceiling.
+ const int y0 = (i4y0+15)>>4;
+ const int y1 = (i4y1+15)>>4;
+ const int y2 = (i4y2+15)>>4;
+
+ // calculate the value of the horizontal coordinate
+ // from the edge that 'spans' the triangle.
+ const int x = ceilDiv(i4dx13*i4dy12 + i4x0*i4dy13, i4dy13);
+
+ // this will hold the horizontal coordinates
+ // of the seperate spans during the rasterization process.
+ int lx,rx;
+
+ // this pair will serve as the error accumulator while
+ // we step along the edges.
+ int ld,rd,lD,rD;
+
+ // these are the edge and error stepping values that
+ // will be used while stepping.
+ int lQ,rQ,lR,rR;
+
+ if(i4x1 < x)
+ {
+ lx = ceilDiv(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ ld = ceilMod(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ rx = ceilDiv(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ rd = ceilMod(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ lQ = mq12;
+ rQ = mq13;
+ lR = mr12;
+ rR = mr13;
+ lD = i4dy12 << 4;
+ rD = i4dy13 << 4;
+ }
+ else
+ {
+ lx = ceilDiv(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ ld = ceilMod(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ rx = ceilDiv(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ rd = ceilMod(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ lQ = mq13;
+ rQ = mq12;
+ lR = mr13;
+ rR = mr12;
+ lD = i4dy13 << 4;
+ rD = i4dy12 << 4;
+ }
+
+ for(signed int y=y0; y<y1; y++)
+ {
+ container.InsertSpan(y-miny,lx,rx);
+
+ lx += lQ; ld += lR;
+ if(ld > 0) { ld -= lD; lx += 1; }
+ rx += rQ; rd += rR;
+ if(rd > 0) { rd -= rD; rx += 1; }
+ }
+
+ if(i4x1 < x)
+ {
+ lx = ceilDiv(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ ld = ceilMod(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ rx = ceilDiv(i4dx13 * (ceilFix4(i4y1) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ rd = ceilMod(i4dx13 * (ceilFix4(i4y1) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ lQ = mq23;
+ lR = mr23;
+ lD = i4dy23 << 4;
+ }
+ else
+ {
+ rx = ceilDiv(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ rd = ceilMod(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ rQ = mq23;
+ rR = mr23;
+ rD = i4dy23 << 4;
+ }
+
+ for(signed int y=y1; y<y2; y++)
+ {
+ container.InsertSpan(y-miny,lx,rx);
+
+ lx += lQ; ld += lR;
+ if(ld > 0) { ld -= lD; lx += 1; }
+ rx += rQ; rd += rR;
+ if(rd > 0) { rd -= rD; rx += 1; }
+ }
+ }
+ }
+ }
+
+ // now try to consolidate as many scanlines as possible.
+ // please note that this will probably change the number
+ // of spans [at least this is why we do all this hassle].
+ // so, if you use 'consolidate' you should *use* this
+ // information during iteration, because the 'graphics'
+ // object we tell all those regions about is a bit,
+ // hm, how to say, *picky* if you supply not correctly
+ // the amount of regions.
+ container.Consolidate();
+
+ // now forward the spantable to the graphics handler.
+ SpanIterator it(container.Iterate());
+ mpGraphics->BeginSetClipRegion( container.GetNumSpans() );
+ while(miny < maxy)
+ {
+ const sal_Int32 dwNumEqual(it.GetNumEqualScanlines());
+ while(it.GetRemainingSpans())
+ {
+ // retrieve the next span [x-coordinate, width] from the current scanline.
+ std::pair<sal_Int32,sal_Int32> span(it.GetNextSpan());
+
+ // now forward this to the graphics object.
+ // the only part that is worth noting is that we use
+ // the number of equal spanlines [the current is always the
+ // first one of the equal bunch] as the height of the region.
+ mpGraphics->UnionClipRegion( offset_x+span.first,
+ offset_y+miny,
+ span.second,
+ dwNumEqual,
+ this );
+ }
+ it.Skip(dwNumEqual);
+ miny += dwNumEqual;
+ }
+ mpGraphics->EndSetClipRegion();
+
+ // indicates that no output needs to be produced
+ // since the clipping region did not provide any
+ // visible areas. the clip covers the whole area
+ // if there's not a single region.
+ mbOutputClipped = (container.GetNumSpans() == 0);
+
+ // indicates that a clip region has been
+ // presented to the output device.
+ mbClipRegion = TRUE;
+
+ // indicates that the set clipping region
+ // has been processed.
+ mbClipRegionSet = TRUE;
+
+ // under 'normal' circumstances a new clipping region
+ // needs to be processed by ImplInitClipRegion(),
+ // which we need to circumvent.
+ mbInitClipRegion = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetClipRegion()
+{
+ DBG_TRACE( "OutputDevice::SetClipRegion()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaClipRegionAction( Region(), FALSE ) );
+
+ ImplSetClipRegion( NULL );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetClipRegion();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetClipRegion( const Region& rRegion )
+{
+ DBG_TRACE( "OutputDevice::SetClipRegion( rRegion )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaClipRegionAction( rRegion, TRUE ) );
+
+ if ( rRegion.GetType() == REGION_NULL )
+ ImplSetClipRegion( NULL );
+ else
+ {
+ Region aRegion = LogicToPixel( rRegion );
+ ImplSetClipRegion( &aRegion );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetClipRegion( rRegion );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetTriangleClipRegion( const PolyPolygon &rPolyPolygon )
+{
+ DBG_TRACE( "OutputDevice::SetTriangleClipRegion( rPolyPolygon )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // in case the passed polypolygon is empty, use the
+ // existing SetClipRegion() method which gracefully
+ // unsets any previously set clipping region.
+ if(!(rPolyPolygon.Count()))
+ SetClipRegion();
+
+ sal_Int32 offset_x = 0;
+ sal_Int32 offset_y = 0;
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ offset_x = mnOutOffX+mnOutOffOrigX;
+ offset_y = mnOutOffY+mnOutOffOrigY;
+ }
+
+ // play nice with the rest of the system and provide an old-style region.
+ // the rest of this method does not rely on this.
+ maRegion = Region::GetRegionFromPolyPolygon( LogicToPixel(rPolyPolygon) );
+ maRegion.Move(offset_x,offset_x);
+
+ // feed region to metafile
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaClipRegionAction( maRegion, TRUE ) );
+
+ ImplSetTriangleClipRegion( rPolyPolygon );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTriangleClipRegion( rPolyPolygon );
+}
+
+// -----------------------------------------------------------------------
+
+Region OutputDevice::GetClipRegion() const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ return PixelToLogic( maRegion );
+}
+
+// -----------------------------------------------------------------------
+
+Region OutputDevice::GetActiveClipRegion() const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ Region aRegion( REGION_NULL );
+ Window* pWindow = (Window*)this;
+ if ( pWindow->mpWindowImpl->mbInPaint )
+ {
+ aRegion = *(pWindow->mpWindowImpl->mpPaintRegion);
+ aRegion.Move( -mnOutOffX, -mnOutOffY );
+ }
+ if ( mbClipRegion )
+ aRegion.Intersect( maRegion );
+ return PixelToLogic( aRegion );
+ }
+ else
+ return GetClipRegion();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::MoveClipRegion( long nHorzMove, long nVertMove )
+{
+ DBG_TRACE( "OutputDevice::MoveClipRegion()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mbClipRegion )
+ {
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaMoveClipRegionAction( nHorzMove, nVertMove ) );
+
+ maRegion.Move( ImplLogicWidthToDevicePixel( nHorzMove ),
+ ImplLogicHeightToDevicePixel( nVertMove ) );
+ mbInitClipRegion = TRUE;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->MoveClipRegion( nHorzMove, nVertMove );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::IntersectClipRegion( const Rectangle& rRect )
+{
+ DBG_TRACE( "OutputDevice::IntersectClipRegion( rRect )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaISectRectClipRegionAction( rRect ) );
+
+ Rectangle aRect = LogicToPixel( rRect );
+ maRegion.Intersect( aRect );
+ mbClipRegion = TRUE;
+ mbInitClipRegion = TRUE;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->IntersectClipRegion( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::IntersectClipRegion( const Region& rRegion )
+{
+ DBG_TRACE( "OutputDevice::IntersectClipRegion( rRegion )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+
+ RegionType eType = rRegion.GetType();
+
+ if ( eType != REGION_NULL )
+ {
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaISectRegionClipRegionAction( rRegion ) );
+
+ Region aRegion = LogicToPixel( rRegion );
+ maRegion.Intersect( aRegion );
+ mbClipRegion = TRUE;
+ mbInitClipRegion = TRUE;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->IntersectClipRegion( rRegion );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetDrawMode( ULONG nDrawMode )
+{
+ DBG_TRACE1( "OutputDevice::SetDrawMode( %lx )", nDrawMode );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ mnDrawMode = nDrawMode;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetDrawMode( nDrawMode );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetRasterOp( RasterOp eRasterOp )
+{
+ DBG_TRACE1( "OutputDevice::SetRasterOp( %d )", (int)eRasterOp );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaRasterOpAction( eRasterOp ) );
+
+ if ( meRasterOp != eRasterOp )
+ {
+ meRasterOp = eRasterOp;
+ mbInitLineColor = mbInitFillColor = TRUE;
+
+ if( mpGraphics || ImplGetGraphics() )
+ mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp), ROP_INVERT == meRasterOp );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetRasterOp( eRasterOp );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetLineColor()
+{
+ DBG_TRACE( "OutputDevice::SetLineColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaLineColorAction( Color(), FALSE ) );
+
+ if ( mbLineColor )
+ {
+ mbInitLineColor = TRUE;
+ mbLineColor = FALSE;
+ maLineColor = Color( COL_TRANSPARENT );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetLineColor();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetLineColor( const Color& rColor )
+{
+ DBG_TRACE1( "OutputDevice::SetLineColor( %lx )", rColor.GetColor() );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor( rColor );
+
+ if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
+ DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
+ DRAWMODE_SETTINGSLINE ) )
+ {
+ if( !ImplIsColorTransparent( aColor ) )
+ {
+ if( mnDrawMode & DRAWMODE_BLACKLINE )
+ {
+ aColor = Color( COL_BLACK );
+ }
+ else if( mnDrawMode & DRAWMODE_WHITELINE )
+ {
+ aColor = Color( COL_WHITE );
+ }
+ else if( mnDrawMode & DRAWMODE_GRAYLINE )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
+ {
+ aColor = GetSettings().GetStyleSettings().GetFontColor();
+ }
+
+ if( mnDrawMode & DRAWMODE_GHOSTEDLINE )
+ {
+ aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
+ ( aColor.GetGreen() >> 1 ) | 0x80,
+ ( aColor.GetBlue() >> 1 ) | 0x80);
+ }
+ }
+ }
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaLineColorAction( aColor, TRUE ) );
+
+ if( ImplIsColorTransparent( aColor ) )
+ {
+ if ( mbLineColor )
+ {
+ mbInitLineColor = TRUE;
+ mbLineColor = FALSE;
+ maLineColor = Color( COL_TRANSPARENT );
+ }
+ }
+ else
+ {
+ if( maLineColor != aColor )
+ {
+ mbInitLineColor = TRUE;
+ mbLineColor = TRUE;
+ maLineColor = aColor;
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetLineColor( COL_BLACK );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetFillColor()
+{
+ DBG_TRACE( "OutputDevice::SetFillColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaFillColorAction( Color(), FALSE ) );
+
+ if ( mbFillColor )
+ {
+ mbInitFillColor = TRUE;
+ mbFillColor = FALSE;
+ maFillColor = Color( COL_TRANSPARENT );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetFillColor();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetFillColor( const Color& rColor )
+{
+ DBG_TRACE1( "OutputDevice::SetFillColor( %lx )", rColor.GetColor() );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor( rColor );
+
+ if( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
+ DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
+ DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
+ {
+ if( !ImplIsColorTransparent( aColor ) )
+ {
+ if( mnDrawMode & DRAWMODE_BLACKFILL )
+ {
+ aColor = Color( COL_BLACK );
+ }
+ else if( mnDrawMode & DRAWMODE_WHITEFILL )
+ {
+ aColor = Color( COL_WHITE );
+ }
+ else if( mnDrawMode & DRAWMODE_GRAYFILL )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if( mnDrawMode & DRAWMODE_NOFILL )
+ {
+ aColor = Color( COL_TRANSPARENT );
+ }
+ else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
+ {
+ aColor = GetSettings().GetStyleSettings().GetWindowColor();
+ }
+
+ if( mnDrawMode & DRAWMODE_GHOSTEDFILL )
+ {
+ aColor = Color( (aColor.GetRed() >> 1) | 0x80,
+ (aColor.GetGreen() >> 1) | 0x80,
+ (aColor.GetBlue() >> 1) | 0x80);
+ }
+ }
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaFillColorAction( aColor, TRUE ) );
+
+ if ( ImplIsColorTransparent( aColor ) )
+ {
+ if ( mbFillColor )
+ {
+ mbInitFillColor = TRUE;
+ mbFillColor = FALSE;
+ maFillColor = Color( COL_TRANSPARENT );
+ }
+ }
+ else
+ {
+ if ( maFillColor != aColor )
+ {
+ mbInitFillColor = TRUE;
+ mbFillColor = TRUE;
+ maFillColor = aColor;
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetFillColor( COL_BLACK );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetBackground()
+{
+ DBG_TRACE( "OutputDevice::SetBackground()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ maBackground = Wallpaper();
+ mbBackground = FALSE;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetBackground();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetBackground( const Wallpaper& rBackground )
+{
+ DBG_TRACE( "OutputDevice::SetBackground( rBackground )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ maBackground = rBackground;
+
+ if( rBackground.GetStyle() == WALLPAPER_NULL )
+ mbBackground = FALSE;
+ else
+ mbBackground = TRUE;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetBackground( rBackground );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetRefPoint()
+{
+ DBG_TRACE( "OutputDevice::SetRefPoint()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaRefPointAction( Point(), FALSE ) );
+
+ mbRefPoint = FALSE;
+ maRefPoint.X() = maRefPoint.Y() = 0L;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetRefPoint();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetRefPoint( const Point& rRefPoint )
+{
+ DBG_TRACE( "OutputDevice::SetRefPoint( rRefPoint )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaRefPointAction( rRefPoint, TRUE ) );
+
+ mbRefPoint = TRUE;
+ maRefPoint = rRefPoint;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetRefPoint( rRefPoint );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt )
+{
+ DBG_TRACE( "OutputDevice::DrawLine()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt ) );
+
+ if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
+ return;
+
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ // #i101598# support AA and snap for lines, too
+ if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp()
+ && IsLineColor())
+ {
+ // at least transform with double precision to device coordinates; this will
+ // avoid pixel snap of single, appended lines
+ const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
+ const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
+ basegfx::B2DPolygon aB2DPolyLine;
+
+ aB2DPolyLine.append(basegfx::B2DPoint(rStartPt.X(), rStartPt.Y()));
+ aB2DPolyLine.append(basegfx::B2DPoint(rEndPt.X(), rEndPt.Y()));
+ aB2DPolyLine.transform( aTransform );
+
+ if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
+ {
+ aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
+ }
+
+ if( mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this))
+ {
+ return;
+ }
+ }
+
+ const Point aStartPt(ImplLogicToDevicePixel(rStartPt));
+ const Point aEndPt(ImplLogicToDevicePixel(rEndPt));
+
+ mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), this );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawLine( rStartPt, rEndPt );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::impPaintLineGeometryWithEvtlExpand(
+ const LineInfo& rInfo,
+ basegfx::B2DPolyPolygon aLinePolyPolygon)
+{
+ const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp()
+ && IsLineColor());
+ basegfx::B2DPolyPolygon aFillPolyPolygon;
+ const bool bDashUsed(LINE_DASH == rInfo.GetStyle());
+ const bool bLineWidthUsed(rInfo.GetWidth() > 1);
+
+ if(bDashUsed && aLinePolyPolygon.count())
+ {
+ ::std::vector< double > fDotDashArray;
+ const double fDashLen(rInfo.GetDashLen());
+ const double fDotLen(rInfo.GetDotLen());
+ const double fDistance(rInfo.GetDistance());
+
+ for(sal_uInt16 a(0); a < rInfo.GetDashCount(); a++)
+ {
+ fDotDashArray.push_back(fDashLen);
+ fDotDashArray.push_back(fDistance);
+ }
+
+ for(sal_uInt16 b(0); b < rInfo.GetDotCount(); b++)
+ {
+ fDotDashArray.push_back(fDotLen);
+ fDotDashArray.push_back(fDistance);
+ }
+
+ const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
+
+ if(fAccumulated > 0.0)
+ {
+ basegfx::B2DPolyPolygon aResult;
+
+ for(sal_uInt32 c(0); c < aLinePolyPolygon.count(); c++)
+ {
+ basegfx::B2DPolyPolygon aLineTraget;
+ basegfx::tools::applyLineDashing(
+ aLinePolyPolygon.getB2DPolygon(c),
+ fDotDashArray,
+ &aLineTraget);
+ aResult.append(aLineTraget);
+ }
+
+ aLinePolyPolygon = aResult;
+ }
+ }
+
+ if(bLineWidthUsed && aLinePolyPolygon.count())
+ {
+ const double fHalfLineWidth((rInfo.GetWidth() * 0.5) + 0.5);
+
+ if(aLinePolyPolygon.areControlPointsUsed())
+ {
+ // #i110768# When area geometry has to be created, do not
+ // use the fallback bezier decomposition inside createAreaGeometry,
+ // but one that is at least as good as ImplSubdivideBezier was.
+ // There, Polygon::AdaptiveSubdivide was used with default parameter
+ // 1.0 as quality index.
+ aLinePolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(aLinePolyPolygon, 1.0);
+ }
+
+ for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
+ {
+ aFillPolyPolygon.append(basegfx::tools::createAreaGeometry(
+ aLinePolyPolygon.getB2DPolygon(a),
+ fHalfLineWidth,
+ rInfo.GetLineJoin()));
+ }
+
+ aLinePolyPolygon.clear();
+ }
+
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ mpMetaFile = NULL;
+
+ if(aLinePolyPolygon.count())
+ {
+ for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
+ {
+ const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
+ bool bDone(false);
+
+ if(bTryAA)
+ {
+ bDone = mpGraphics->DrawPolyLine( aCandidate, 0.0, basegfx::B2DVector(1.0,1.0), basegfx::B2DLINEJOIN_NONE, this);
+ }
+
+ if(!bDone)
+ {
+ const Polygon aPolygon(aCandidate);
+ mpGraphics->DrawPolyLine(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this);
+ }
+ }
+ }
+
+ if(aFillPolyPolygon.count())
+ {
+ const Color aOldLineColor( maLineColor );
+ const Color aOldFillColor( maFillColor );
+
+ SetLineColor();
+ ImplInitLineColor();
+ SetFillColor( aOldLineColor );
+ ImplInitFillColor();
+
+ bool bDone(false);
+
+ if(bTryAA)
+ {
+ bDone = mpGraphics->DrawPolyPolygon(aFillPolyPolygon, 0.0, this);
+ }
+
+ if(!bDone)
+ {
+ for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
+ {
+ const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
+ mpGraphics->DrawPolygon(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this);
+ }
+ }
+
+ SetFillColor( aOldFillColor );
+ SetLineColor( aOldLineColor );
+ }
+
+ mpMetaFile = pOldMetaFile;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt,
+ const LineInfo& rLineInfo )
+{
+ DBG_TRACE( "OutputDevice::DrawLine()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( rLineInfo.IsDefault() )
+ {
+ DrawLine( rStartPt, rEndPt );
+ return;
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt, rLineInfo ) );
+
+ if ( !IsDeviceOutputNecessary() || !mbLineColor || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() )
+ return;
+
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( mbOutputClipped )
+ return;
+
+ const Point aStartPt( ImplLogicToDevicePixel( rStartPt ) );
+ const Point aEndPt( ImplLogicToDevicePixel( rEndPt ) );
+ const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) );
+ const bool bDashUsed(LINE_DASH == aInfo.GetStyle());
+ const bool bLineWidthUsed(aInfo.GetWidth() > 1);
+
+ if(bDashUsed || bLineWidthUsed)
+ {
+ basegfx::B2DPolygon aLinePolygon;
+ aLinePolygon.append(basegfx::B2DPoint(aStartPt.X(), aStartPt.Y()));
+ aLinePolygon.append(basegfx::B2DPoint(aEndPt.X(), aEndPt.Y()));
+
+ impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aLinePolygon));
+ }
+ else
+ {
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), this );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawLine( rStartPt, rEndPt, rLineInfo );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawRect( const Rectangle& rRect )
+{
+ DBG_TRACE( "OutputDevice::DrawRect()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaRectAction( rRect ) );
+
+ if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
+ return;
+
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+
+ if ( aRect.IsEmpty() )
+ return;
+ aRect.Justify();
+
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+
+ mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), this );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawRect( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPolyLine( const Polygon& rPoly )
+{
+ DBG_TRACE( "OutputDevice::DrawPolyLine()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPolyLineAction( rPoly ) );
+
+ USHORT nPoints = rPoly.GetSize();
+
+ if ( !IsDeviceOutputNecessary() || !mbLineColor || (nPoints < 2) || ImplIsRecordLayout() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp()
+ && IsLineColor());
+
+ // use b2dpolygon drawing if possible
+ if(bTryAA && ImpTryDrawPolyLineDirect(rPoly.getB2DPolygon(), 0.0, basegfx::B2DLINEJOIN_NONE))
+ {
+ basegfx::B2DPolygon aB2DPolyLine(rPoly.getB2DPolygon());
+ const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+ const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
+
+ // transform the polygon
+ aB2DPolyLine.transform( aTransform );
+
+ if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
+ {
+ aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
+ }
+
+ if(mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this))
+ {
+ return;
+ }
+ }
+
+ Polygon aPoly = ImplLogicToDevicePixel( rPoly );
+ const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
+
+ // #100127# Forward beziers to sal, if any
+ if( aPoly.HasFlags() )
+ {
+ const BYTE* pFlgAry = aPoly.GetConstFlagAry();
+ if( !mpGraphics->DrawPolyLineBezier( nPoints, pPtAry, pFlgAry, this ) )
+ {
+ aPoly = ImplSubdivideBezier(aPoly);
+ pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
+ mpGraphics->DrawPolyLine( aPoly.GetSize(), pPtAry, this );
+ }
+ }
+ else
+ {
+ mpGraphics->DrawPolyLine( nPoints, pPtAry, this );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPolyLine( rPoly );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPolyLine( const Polygon& rPoly, const LineInfo& rLineInfo )
+{
+ DBG_TRACE( "OutputDevice::DrawPolyLine()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+
+ if ( rLineInfo.IsDefault() )
+ {
+ DrawPolyLine( rPoly );
+ return;
+ }
+
+ // #i101491#
+ // Try direct Fallback to B2D-Version of DrawPolyLine
+ if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && LINE_SOLID == rLineInfo.GetStyle())
+ {
+ DrawPolyLine( rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), rLineInfo.GetLineJoin());
+ return;
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPolyLineAction( rPoly, rLineInfo ) );
+
+ ImpDrawPolyLineWithLineInfo(rPoly, rLineInfo);
+}
+
+void OutputDevice::ImpDrawPolyLineWithLineInfo(const Polygon& rPoly, const LineInfo& rLineInfo)
+{
+ USHORT nPoints(rPoly.GetSize());
+
+ if ( !IsDeviceOutputNecessary() || !mbLineColor || ( nPoints < 2 ) || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() )
+ return;
+
+ Polygon aPoly = ImplLogicToDevicePixel( rPoly );
+
+ // #100127# LineInfo is not curve-safe, subdivide always
+ //
+ // What shall this mean? It's wrong to subdivide here when the
+ // polygon is a fat line. In that case, the painted geometry
+ // WILL be much different.
+ // I also have no idea how this could be related to the given ID
+ // which reads 'consolidate boost versions' in the task description.
+ // Removing.
+ //
+ //if( aPoly.HasFlags() )
+ //{
+ // aPoly = ImplSubdivideBezier( aPoly );
+ // nPoints = aPoly.GetSize();
+ //}
+
+ // we need a graphics
+ if ( !mpGraphics && !ImplGetGraphics() )
+ return;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) );
+ const bool bDashUsed(LINE_DASH == aInfo.GetStyle());
+ const bool bLineWidthUsed(aInfo.GetWidth() > 1);
+
+ if(bDashUsed || bLineWidthUsed)
+ {
+ impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aPoly.getB2DPolygon()));
+ }
+ else
+ {
+ // #100127# the subdivision HAS to be done here since only a pointer
+ // to an array of points is given to the DrawPolyLine method, there is
+ // NO way to find out there that it's a curve.
+ if( aPoly.HasFlags() )
+ {
+ aPoly = ImplSubdivideBezier( aPoly );
+ nPoints = aPoly.GetSize();
+ }
+
+ mpGraphics->DrawPolyLine(nPoints, (const SalPoint*)aPoly.GetConstPointAry(), this);
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPolyLine( rPoly, rLineInfo );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPolygon( const Polygon& rPoly )
+{
+ DBG_TRACE( "OutputDevice::DrawPolygon()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rPoly, Polygon, NULL );
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
+
+ USHORT nPoints = rPoly.GetSize();
+
+ if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || (nPoints < 2) || ImplIsRecordLayout() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+
+ // use b2dpolygon drawing if possible
+ if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp()
+ && (IsLineColor() || IsFillColor()))
+ {
+ const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+ basegfx::B2DPolygon aB2DPolygon(rPoly.getB2DPolygon());
+ bool bSuccess(true);
+
+ // transform the polygon and ensure closed
+ aB2DPolygon.transform(aTransform);
+ aB2DPolygon.setClosed(true);
+
+ if(IsFillColor())
+ {
+ bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon), 0.0, this);
+ }
+
+ if(bSuccess && IsLineColor())
+ {
+ const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
+
+ if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
+ {
+ aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
+ }
+
+ bSuccess = mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
+ }
+
+ if(bSuccess)
+ {
+ return;
+ }
+ }
+
+ Polygon aPoly = ImplLogicToDevicePixel( rPoly );
+ const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
+
+ // #100127# Forward beziers to sal, if any
+ if( aPoly.HasFlags() )
+ {
+ const BYTE* pFlgAry = aPoly.GetConstFlagAry();
+ if( !mpGraphics->DrawPolygonBezier( nPoints, pPtAry, pFlgAry, this ) )
+ {
+ aPoly = ImplSubdivideBezier(aPoly);
+ pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
+ mpGraphics->DrawPolygon( aPoly.GetSize(), pPtAry, this );
+ }
+ }
+ else
+ {
+ mpGraphics->DrawPolygon( nPoints, pPtAry, this );
+ }
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPolygon( rPoly );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ DBG_TRACE( "OutputDevice::DrawPolyPolygon()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
+
+ USHORT nPoly = rPolyPoly.Count();
+
+ if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || !nPoly || ImplIsRecordLayout() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+
+ // use b2dpolygon drawing if possible
+ if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp()
+ && (IsLineColor() || IsFillColor()))
+ {
+ const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+ basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
+ bool bSuccess(true);
+
+ // transform the polygon and ensure closed
+ aB2DPolyPolygon.transform(aTransform);
+ aB2DPolyPolygon.setClosed(true);
+
+ if(IsFillColor())
+ {
+ bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
+ }
+
+ if(bSuccess && IsLineColor())
+ {
+ const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
+
+ if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
+ {
+ aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
+ }
+
+ for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++)
+ {
+ bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
+ }
+ }
+
+ if(bSuccess)
+ {
+ return;
+ }
+ }
+
+ if ( nPoly == 1 )
+ {
+ // #100127# Map to DrawPolygon
+ Polygon aPoly = rPolyPoly.GetObject( 0 );
+ if( aPoly.GetSize() >= 2 )
+ {
+ GDIMetaFile* pOldMF = mpMetaFile;
+ mpMetaFile = NULL;
+
+ DrawPolygon( aPoly );
+
+ mpMetaFile = pOldMF;
+ }
+ }
+ else
+ {
+ // #100127# moved real PolyPolygon draw to separate method,
+ // have to call recursively, avoiding duplicate
+ // ImplLogicToDevicePixel calls
+ ImplDrawPolyPolygon( nPoly, ImplLogicToDevicePixel( rPolyPoly ) );
+ }
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPolygon( const ::basegfx::B2DPolygon& rB2DPolygon)
+{
+ // AW: Do NOT paint empty polygons
+ if(rB2DPolygon.count())
+ {
+ ::basegfx::B2DPolyPolygon aPP( rB2DPolygon );
+ DrawPolyPolygon( aPP );
+ }
+}
+
+// -----------------------------------------------------------------------
+// Caution: This method is nearly the same as
+// OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency),
+// so when changes are made here do not forget to make change sthere, too
+
+void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+ DBG_TRACE( "OutputDevice::DrawPolyPolygon(B2D&)" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+#if 0
+ // MetaB2DPolyPolygonAction is not implemented yet:
+ // according to AW adding it is very dangerous since there is a lot
+ // of code that uses the metafile actions directly and unless every
+ // place that does this knows about the new action we need to fallback
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly ) );
+#else
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPolyPolygonAction( PolyPolygon( rB2DPolyPoly ) ) );
+#endif
+
+ // call helper
+ ImpDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly);
+}
+
+void OutputDevice::ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon& rB2DPolyPoly)
+{
+ // AW: Do NOT paint empty PolyPolygons
+ if(!rB2DPolyPoly.count())
+ return;
+
+ // we need a graphics
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return;
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
+
+ if( mbInitLineColor )
+ ImplInitLineColor();
+ if( mbInitFillColor )
+ ImplInitFillColor();
+
+ if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp()
+ && (IsLineColor() || IsFillColor()))
+ {
+ const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
+ basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
+ bool bSuccess(true);
+
+ // transform the polygon and ensure closed
+ aB2DPolyPolygon.transform(aTransform);
+ aB2DPolyPolygon.setClosed(true);
+
+ if(IsFillColor())
+ {
+ bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
+ }
+
+ if(bSuccess && IsLineColor())
+ {
+ const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
+
+ if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
+ {
+ aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
+ }
+
+ for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++)
+ {
+ bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
+ }
+ }
+
+ if(bSuccess)
+ {
+ return;
+ }
+ }
+
+ // fallback to old polygon drawing if needed
+ const PolyPolygon aToolsPolyPolygon( rB2DPolyPoly );
+ const PolyPolygon aPixelPolyPolygon = ImplLogicToDevicePixel( aToolsPolyPolygon );
+ ImplDrawPolyPolygon( aPixelPolyPolygon.Count(), aPixelPolyPolygon );
+}
+
+// -----------------------------------------------------------------------
+
+bool OutputDevice::ImpTryDrawPolyLineDirect(
+ const basegfx::B2DPolygon& rB2DPolygon,
+ double fLineWidth,
+ basegfx::B2DLineJoin eLineJoin)
+{
+ const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+ basegfx::B2DVector aB2DLineWidth(1.0, 1.0);
+
+ // transform the line width if used
+ if( fLineWidth != 0.0 )
+ {
+ aB2DLineWidth = aTransform * ::basegfx::B2DVector( fLineWidth, fLineWidth );
+ }
+
+ // transform the polygon
+ basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
+ aB2DPolygon.transform(aTransform);
+
+ if((mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
+ && aB2DPolygon.count() < 1000)
+ {
+ // #i98289#, #i101491#
+ // better to remove doubles on device coordinates. Also assume from a given amount
+ // of points that the single edges are not long enough to smooth
+ aB2DPolygon.removeDoublePoints();
+ aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
+ }
+
+ // draw the polyline
+ return mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, eLineJoin, this);
+}
+
+void OutputDevice::DrawPolyLine(
+ const basegfx::B2DPolygon& rB2DPolygon,
+ double fLineWidth,
+ basegfx::B2DLineJoin eLineJoin)
+{
+ DBG_TRACE( "OutputDevice::DrawPolyLine(B2D&)" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ (void)eLineJoin; // ATM used in UNX, but not in WNT, access it for warning-free
+
+#if 0 // MetaB2DPolyLineAction is not implemented yet:
+ // according to AW adding it is very dangerous since there is a lot
+ // of code that uses the metafile actions directly and unless every
+ // place that does this knows about the new action we need to fallback
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaB2DPolyLineAction( rB2DPolygon ) );
+#else
+ if( mpMetaFile )
+ {
+ LineInfo aLineInfo;
+ if( fLineWidth != 0.0 )
+ aLineInfo.SetWidth( static_cast<long>(fLineWidth+0.5) );
+ const Polygon aToolsPolygon( rB2DPolygon );
+ mpMetaFile->AddAction( new MetaPolyLineAction( aToolsPolygon, aLineInfo ) );
+ }
+#endif
+
+ // AW: Do NOT paint empty PolyPolygons
+ if(!rB2DPolygon.count())
+ return;
+
+ // we need a graphics
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return;
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
+
+ if( mbInitLineColor )
+ ImplInitLineColor();
+
+ const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp()
+ && IsLineColor());
+
+ // use b2dpolygon drawing if possible
+ if(bTryAA && ImpTryDrawPolyLineDirect(rB2DPolygon, fLineWidth, eLineJoin))
+ {
+ return;
+ }
+
+ // #i101491#
+ // no output yet; fallback to geometry decomposition and use filled polygon paint
+ // when line is fat and not too complex. ImpDrawPolyPolygonWithB2DPolyPolygon
+ // will do internal needed AA checks etc.
+ if(fLineWidth >= 2.5
+ && rB2DPolygon.count()
+ && rB2DPolygon.count() <= 1000)
+ {
+ const double fHalfLineWidth((fLineWidth * 0.5) + 0.5);
+ const basegfx::B2DPolyPolygon aAreaPolyPolygon(basegfx::tools::createAreaGeometry(
+ rB2DPolygon, fHalfLineWidth, eLineJoin));
+
+ const Color aOldLineColor(maLineColor);
+ const Color aOldFillColor(maFillColor);
+
+ SetLineColor();
+ ImplInitLineColor();
+ SetFillColor(aOldLineColor);
+ ImplInitFillColor();
+
+ // draw usig a loop; else the topology will paint a PolyPolygon
+ for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++)
+ {
+ ImpDrawPolyPolygonWithB2DPolyPolygon(
+ basegfx::B2DPolyPolygon(aAreaPolyPolygon.getB2DPolygon(a)));
+ }
+
+ SetLineColor(aOldLineColor);
+ ImplInitLineColor();
+ SetFillColor(aOldFillColor);
+ ImplInitFillColor();
+
+ if(bTryAA)
+ {
+ // when AA it is necessary to also paint the filled polygon's outline
+ // to avoid optical gaps
+ for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++)
+ {
+ ImpTryDrawPolyLineDirect(aAreaPolyPolygon.getB2DPolygon(a), 0.0, basegfx::B2DLINEJOIN_NONE);
+ }
+ }
+ }
+ else
+ {
+ // fallback to old polygon drawing if needed
+ const Polygon aToolsPolygon( rB2DPolygon );
+ LineInfo aLineInfo;
+ if( fLineWidth != 0.0 )
+ aLineInfo.SetWidth( static_cast<long>(fLineWidth+0.5) );
+ ImpDrawPolyLineWithLineInfo( aToolsPolygon, aLineInfo );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::Push( USHORT nFlags )
+{
+ DBG_TRACE( "OutputDevice::Push()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPushAction( nFlags ) );
+
+ ImplObjStack* pData = new ImplObjStack;
+ pData->mpPrev = mpObjStack;
+ mpObjStack = pData;
+
+ pData->mnFlags = nFlags;
+
+ if ( nFlags & PUSH_LINECOLOR )
+ {
+ if ( mbLineColor )
+ pData->mpLineColor = new Color( maLineColor );
+ else
+ pData->mpLineColor = NULL;
+ }
+ if ( nFlags & PUSH_FILLCOLOR )
+ {
+ if ( mbFillColor )
+ pData->mpFillColor = new Color( maFillColor );
+ else
+ pData->mpFillColor = NULL;
+ }
+ if ( nFlags & PUSH_FONT )
+ pData->mpFont = new Font( maFont );
+ if ( nFlags & PUSH_TEXTCOLOR )
+ pData->mpTextColor = new Color( GetTextColor() );
+ if ( nFlags & PUSH_TEXTFILLCOLOR )
+ {
+ if ( IsTextFillColor() )
+ pData->mpTextFillColor = new Color( GetTextFillColor() );
+ else
+ pData->mpTextFillColor = NULL;
+ }
+ if ( nFlags & PUSH_TEXTLINECOLOR )
+ {
+ if ( IsTextLineColor() )
+ pData->mpTextLineColor = new Color( GetTextLineColor() );
+ else
+ pData->mpTextLineColor = NULL;
+ }
+ if ( nFlags & PUSH_OVERLINECOLOR )
+ {
+ if ( IsOverlineColor() )
+ pData->mpOverlineColor = new Color( GetOverlineColor() );
+ else
+ pData->mpOverlineColor = NULL;
+ }
+ if ( nFlags & PUSH_TEXTALIGN )
+ pData->meTextAlign = GetTextAlign();
+ if( nFlags & PUSH_TEXTLAYOUTMODE )
+ pData->mnTextLayoutMode = GetLayoutMode();
+ if( nFlags & PUSH_TEXTLANGUAGE )
+ pData->meTextLanguage = GetDigitLanguage();
+ if ( nFlags & PUSH_RASTEROP )
+ pData->meRasterOp = GetRasterOp();
+ if ( nFlags & PUSH_MAPMODE )
+ {
+ if ( mbMap )
+ pData->mpMapMode = new MapMode( maMapMode );
+ else
+ pData->mpMapMode = NULL;
+ }
+ if ( nFlags & PUSH_CLIPREGION )
+ {
+ if ( mbClipRegion )
+ pData->mpClipRegion = new Region( maRegion );
+ else
+ pData->mpClipRegion = NULL;
+ }
+ if ( nFlags & PUSH_REFPOINT )
+ {
+ if ( mbRefPoint )
+ pData->mpRefPoint = new Point( maRefPoint );
+ else
+ pData->mpRefPoint = NULL;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->Push();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::Pop()
+{
+ DBG_TRACE( "OutputDevice::Pop()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPopAction() );
+
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ ImplObjStack* pData = mpObjStack;
+ mpMetaFile = NULL;
+
+ if ( !pData )
+ {
+ DBG_ERRORFILE( "OutputDevice::Pop() without OutputDevice::Push()" );
+ return;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->Pop();
+
+ mpObjStack = pData->mpPrev;
+
+ if ( pData->mnFlags & PUSH_LINECOLOR )
+ {
+ if ( pData->mpLineColor )
+ SetLineColor( *pData->mpLineColor );
+ else
+ SetLineColor();
+ }
+ if ( pData->mnFlags & PUSH_FILLCOLOR )
+ {
+ if ( pData->mpFillColor )
+ SetFillColor( *pData->mpFillColor );
+ else
+ SetFillColor();
+ }
+ if ( pData->mnFlags & PUSH_FONT )
+ SetFont( *pData->mpFont );
+ if ( pData->mnFlags & PUSH_TEXTCOLOR )
+ SetTextColor( *pData->mpTextColor );
+ if ( pData->mnFlags & PUSH_TEXTFILLCOLOR )
+ {
+ if ( pData->mpTextFillColor )
+ SetTextFillColor( *pData->mpTextFillColor );
+ else
+ SetTextFillColor();
+ }
+ if ( pData->mnFlags & PUSH_TEXTLINECOLOR )
+ {
+ if ( pData->mpTextLineColor )
+ SetTextLineColor( *pData->mpTextLineColor );
+ else
+ SetTextLineColor();
+ }
+ if ( pData->mnFlags & PUSH_OVERLINECOLOR )
+ {
+ if ( pData->mpOverlineColor )
+ SetOverlineColor( *pData->mpOverlineColor );
+ else
+ SetOverlineColor();
+ }
+ if ( pData->mnFlags & PUSH_TEXTALIGN )
+ SetTextAlign( pData->meTextAlign );
+ if( pData->mnFlags & PUSH_TEXTLAYOUTMODE )
+ SetLayoutMode( pData->mnTextLayoutMode );
+ if( pData->mnFlags & PUSH_TEXTLANGUAGE )
+ SetDigitLanguage( pData->meTextLanguage );
+ if ( pData->mnFlags & PUSH_RASTEROP )
+ SetRasterOp( pData->meRasterOp );
+ if ( pData->mnFlags & PUSH_MAPMODE )
+ {
+ if ( pData->mpMapMode )
+ SetMapMode( *pData->mpMapMode );
+ else
+ SetMapMode();
+ }
+ if ( pData->mnFlags & PUSH_CLIPREGION )
+ ImplSetClipRegion( pData->mpClipRegion );
+ if ( pData->mnFlags & PUSH_REFPOINT )
+ {
+ if ( pData->mpRefPoint )
+ SetRefPoint( *pData->mpRefPoint );
+ else
+ SetRefPoint();
+ }
+
+ ImplDeleteObjStack( pData );
+
+ mpMetaFile = pOldMetaFile;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetConnectMetaFile( GDIMetaFile* pMtf )
+{
+ mpMetaFile = pMtf;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::EnableOutput( BOOL bEnable )
+{
+ mbOutput = (bEnable != 0);
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->EnableOutput( bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetSettings( const AllSettings& rSettings )
+{
+ maSettings = rSettings;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetSettings( rSettings );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT OutputDevice::GetBitCount() const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( meOutDevType == OUTDEV_VIRDEV )
+ return ((VirtualDevice*)this)->mnBitCount;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !((OutputDevice*)this)->ImplGetGraphics() )
+ return 0;
+ }
+
+ return (USHORT)mpGraphics->GetBitCount();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT OutputDevice::GetAlphaBitCount() const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( meOutDevType == OUTDEV_VIRDEV &&
+ mpAlphaVDev != NULL )
+ {
+ return mpAlphaVDev->GetBitCount();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG OutputDevice::GetColorCount() const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ const USHORT nBitCount = GetBitCount();
+ return( ( nBitCount > 31 ) ? ULONG_MAX : ( ( (ULONG) 1 ) << nBitCount) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::HasAlpha()
+{
+ return mpAlphaVDev != NULL;
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics > OutputDevice::CreateUnoGraphics()
+{
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
+ return pWrapper ? pWrapper->CreateGraphics( this ) : ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >();
+}
+
+// -----------------------------------------------------------------------
+
+SystemGraphicsData OutputDevice::GetSystemGfxData() const
+{
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return SystemGraphicsData();
+ }
+
+ return mpGraphics->GetGraphicsData();
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Any OutputDevice::GetSystemGfxDataAny() const
+{
+ ::com::sun::star::uno::Any aRet;
+ const SystemGraphicsData aSysData = GetSystemGfxData();
+ ::com::sun::star::uno::Sequence< sal_Int8 > aSeq( (sal_Int8*)&aSysData,
+ aSysData.nSize );
+
+ return uno::makeAny(aSeq);
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > OutputDevice::GetCanvas() const
+{
+ uno::Sequence< uno::Any > aArg(6);
+
+ aArg[ 0 ] = uno::makeAny( reinterpret_cast<sal_Int64>(this) );
+ aArg[ 2 ] = uno::makeAny( ::com::sun::star::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ) );
+ aArg[ 3 ] = uno::makeAny( sal_False );
+ aArg[ 5 ] = GetSystemGfxDataAny();
+
+ uno::Reference<lang::XMultiServiceFactory> xFactory = vcl::unohelper::GetMultiServiceFactory();
+
+ uno::Reference<rendering::XCanvas> xCanvas;
+
+ // Create canvas instance with window handle
+ // =========================================
+ if ( xFactory.is() )
+ {
+ static uno::Reference<lang::XMultiServiceFactory> xCanvasFactory(
+ xFactory->createInstance(
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star."
+ "rendering.CanvasFactory") ) ),
+ uno::UNO_QUERY );
+ if(xCanvasFactory.is())
+ {
+ xCanvas.set(
+ xCanvasFactory->createInstanceWithArguments(
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.rendering.Canvas" )),
+ aArg ),
+ uno::UNO_QUERY );
+ }
+ }
+
+ return xCanvas;
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/source/gdi/outdev2.cxx b/vcl/source/gdi/outdev2.cxx
new file mode 100644
index 000000000000..bea307a4c38d
--- /dev/null
+++ b/vcl/source/gdi/outdev2.cxx
@@ -0,0 +1,2263 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salbmp.hxx>
+#include <vcl/salgdi.hxx>
+#include <vcl/impbmp.hxx>
+#include <tools/debug.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/window.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/outdata.hxx>
+#include <vcl/outdev.h>
+#include <vcl/bmpacc.hxx>
+#include <vcl/region.h>
+#include <vcl/outdev.hxx>
+#include <vcl/window.hxx>
+#include <vcl/window.h>
+#include <vcl/sallayout.hxx>
+#include <vcl/image.h>
+#include <vcl/image.hxx>
+#include <vcl/bmpfast.hxx>
+
+#define BAND_MAX_SIZE 512000
+
+// =======================================================================
+
+DBG_NAMEEX( OutputDevice )
+
+// =======================================================================
+
+// -----------
+// - Defines -
+// -----------
+
+#define OUTDEV_INIT() \
+{ \
+ if ( !IsDeviceOutputNecessary() ) \
+ return; \
+ \
+ if ( !mpGraphics ) \
+ if ( !ImplGetGraphics() ) \
+ return; \
+ \
+ if ( mbInitClipRegion ) \
+ ImplInitClipRegion(); \
+ \
+ if ( mbOutputClipped ) \
+ return; \
+}
+
+#define TwoRect SalTwoRect
+
+// -------------
+// - externals -
+// -------------
+
+extern ULONG nVCLRLut[ 6 ];
+extern ULONG nVCLGLut[ 6 ];
+extern ULONG nVCLBLut[ 6 ];
+extern ULONG nVCLDitherLut[ 256 ];
+extern ULONG nVCLLut[ 256 ];
+
+// =======================================================================
+
+ULONG ImplAdjustTwoRect( TwoRect& rTwoRect, const Size& rSizePix )
+{
+ ULONG nMirrFlags = 0;
+
+ if ( rTwoRect.mnDestWidth < 0 )
+ {
+ rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth;
+ rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth;
+ rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1;
+ nMirrFlags |= BMP_MIRROR_HORZ;
+ }
+
+ if ( rTwoRect.mnDestHeight < 0 )
+ {
+ rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight;
+ rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight;
+ rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1;
+ nMirrFlags |= BMP_MIRROR_VERT;
+ }
+
+ if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) ||
+ ( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) ||
+ ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) ||
+ ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) )
+ {
+ const Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
+ Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
+ Rectangle aCropRect( aSourceRect );
+
+ aCropRect.Intersection( Rectangle( Point(), rSizePix ) );
+
+ if( aCropRect.IsEmpty() )
+ rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
+ else
+ {
+ const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? (double) ( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
+ const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? (double) ( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
+
+ const long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
+ const long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
+ const long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
+ const long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
+
+ rTwoRect.mnSrcX = aCropRect.Left();
+ rTwoRect.mnSrcY = aCropRect.Top();
+ rTwoRect.mnSrcWidth = aCropRect.GetWidth();
+ rTwoRect.mnSrcHeight = aCropRect.GetHeight();
+ rTwoRect.mnDestX = nDstX1;
+ rTwoRect.mnDestY = nDstY1;
+ rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
+ rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
+ }
+ }
+
+ return nMirrFlags;
+}
+
+// =======================================================================
+
+void OutputDevice::ImplDrawOutDevDirect( const OutputDevice* pSrcDev, void* pVoidPosAry )
+{
+ TwoRect* pPosAry = (TwoRect*)pVoidPosAry;
+ SalGraphics* pGraphics2;
+
+ if ( pPosAry->mnSrcWidth && pPosAry->mnSrcHeight && pPosAry->mnDestWidth && pPosAry->mnDestHeight )
+ {
+ if ( this == pSrcDev )
+ pGraphics2 = NULL;
+ else
+ {
+ if ( (GetOutDevType() != pSrcDev->GetOutDevType()) ||
+ (GetOutDevType() != OUTDEV_WINDOW) )
+ {
+ if ( !pSrcDev->mpGraphics )
+ {
+ if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
+ return;
+ }
+ pGraphics2 = pSrcDev->mpGraphics;
+ }
+ else
+ {
+ if ( ((Window*)this)->mpWindowImpl->mpFrameWindow == ((Window*)pSrcDev)->mpWindowImpl->mpFrameWindow )
+ pGraphics2 = NULL;
+ else
+ {
+ if ( !pSrcDev->mpGraphics )
+ {
+ if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
+ return;
+ }
+ pGraphics2 = pSrcDev->mpGraphics;
+
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+ DBG_ASSERT( mpGraphics && pSrcDev->mpGraphics,
+ "OutputDevice::DrawOutDev(): We need more than one Graphics" );
+ }
+ }
+ }
+
+ // #102532# Offset only has to be pseudo window offset
+ Rectangle aSrcOutRect( Point( pSrcDev->mnOutOffX, pSrcDev->mnOutOffY ),
+ Size( pSrcDev->mnOutWidth, pSrcDev->mnOutHeight ) );
+ Rectangle aSrcRect( Point( pPosAry->mnSrcX, pPosAry->mnSrcY ),
+ Size( pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) );
+ const long nOldRight = aSrcRect.Right();
+ const long nOldBottom = aSrcRect.Bottom();
+
+ if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
+ {
+ if ( (pPosAry->mnSrcX+pPosAry->mnSrcWidth-1) > aSrcOutRect.Right() )
+ {
+ const long nOldWidth = pPosAry->mnSrcWidth;
+ pPosAry->mnSrcWidth -= (nOldRight - aSrcRect.Right());
+ pPosAry->mnDestWidth = pPosAry->mnDestWidth * pPosAry->mnSrcWidth / nOldWidth;
+ }
+
+ if ( (pPosAry->mnSrcY+pPosAry->mnSrcHeight-1) > aSrcOutRect.Bottom() )
+ {
+ const long nOldHeight = pPosAry->mnSrcHeight;
+ pPosAry->mnSrcHeight -= (nOldBottom - aSrcRect.Bottom());
+ pPosAry->mnDestHeight = pPosAry->mnDestHeight * pPosAry->mnSrcHeight / nOldHeight;
+ }
+
+ // --- RTL --- if this is no window, but pSrcDev is a window
+ // mirroring may be required
+ // because only windows have a SalGraphicsLayout
+ // mirroring is performed here
+ if( (GetOutDevType() != OUTDEV_WINDOW) && pGraphics2 && (pGraphics2->GetLayout() & SAL_LAYOUT_BIDI_RTL) )
+ {
+ SalTwoRect pPosAry2 = *pPosAry;
+ pGraphics2->mirror( pPosAry2.mnSrcX, pPosAry2.mnSrcWidth, pSrcDev );
+ mpGraphics->CopyBits( &pPosAry2, pGraphics2, this, pSrcDev );
+ }
+ else
+ mpGraphics->CopyBits( pPosAry, pGraphics2, this, pSrcDev );
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPt, const Size& rSrcSize )
+{
+ DBG_TRACE( "OutputDevice::DrawOutDev()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ if ( meOutDevType == OUTDEV_PRINTER )
+ return;
+
+ if ( ROP_INVERT == meRasterOp )
+ {
+ DrawRect( Rectangle( rDestPt, rDestSize ) );
+ return;
+ }
+
+ if ( mpMetaFile )
+ {
+ const Bitmap aBmp( GetBitmap( rSrcPt, rSrcSize ) );
+ mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
+ }
+
+ OUTDEV_INIT();
+
+ TwoRect aPosAry;
+ aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
+ aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
+ aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
+ aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
+
+ if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
+ {
+ aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() );
+ aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() );
+ aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
+ aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
+
+ Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) );
+ Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
+ Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
+ long nOldRight = aSrcRect.Right();
+ long nOldBottom = aSrcRect.Bottom();
+
+ if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
+ {
+ if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
+ {
+ long nOldWidth = aPosAry.mnSrcWidth;
+ aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
+ aPosAry.mnDestWidth = aPosAry.mnDestWidth*aPosAry.mnSrcWidth/nOldWidth;
+ }
+
+ if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
+ {
+ long nOldHeight = aPosAry.mnSrcHeight;
+ aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
+ aPosAry.mnDestHeight = aPosAry.mnDestHeight*aPosAry.mnSrcHeight/nOldHeight;
+ }
+
+ mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize );
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPt, const Size& rSrcSize,
+ const OutputDevice& rOutDev )
+{
+ DBG_TRACE( "OutputDevice::DrawOutDev()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rOutDev, OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
+ DBG_ASSERT( rOutDev.meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
+
+ if ( (meOutDevType == OUTDEV_PRINTER) || (rOutDev.meOutDevType == OUTDEV_PRINTER) || ImplIsRecordLayout() )
+ return;
+
+ if ( ROP_INVERT == meRasterOp )
+ {
+ DrawRect( Rectangle( rDestPt, rDestSize ) );
+ return;
+ }
+
+ if ( mpMetaFile )
+ {
+ const Bitmap aBmp( rOutDev.GetBitmap( rSrcPt, rSrcSize ) );
+ mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
+ }
+
+ OUTDEV_INIT();
+
+ TwoRect aPosAry;
+ aPosAry.mnSrcX = rOutDev.ImplLogicXToDevicePixel( rSrcPt.X() );
+ aPosAry.mnSrcY = rOutDev.ImplLogicYToDevicePixel( rSrcPt.Y() );
+ aPosAry.mnSrcWidth = rOutDev.ImplLogicWidthToDevicePixel( rSrcSize.Width() );
+ aPosAry.mnSrcHeight = rOutDev.ImplLogicHeightToDevicePixel( rSrcSize.Height() );
+ aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
+ aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
+ aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
+ aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
+
+ if( mpAlphaVDev )
+ {
+ if( rOutDev.mpAlphaVDev )
+ {
+ // alpha-blend source over destination
+ DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
+
+ // This would be mode SOURCE:
+ // copy source alpha channel to our alpha channel
+ //mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize, *rOutDev.mpAlphaVDev );
+ }
+ else
+ {
+ ImplDrawOutDevDirect( &rOutDev, &aPosAry );
+
+ // #i32109#: make destination rectangle opaque - source has no alpha
+ mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
+ }
+ }
+ else
+ {
+ if( rOutDev.mpAlphaVDev )
+ {
+ // alpha-blend source over destination
+ DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
+ }
+ else
+ {
+ // no alpha at all, neither in source nor destination device
+ ImplDrawOutDevDirect( &rOutDev, &aPosAry );
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::CopyArea( const Point& rDestPt,
+ const Point& rSrcPt, const Size& rSrcSize,
+ USHORT nFlags )
+{
+ DBG_TRACE( "OutputDevice::CopyArea()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::CopyArea(...) with printer devices!" );
+
+ if ( meOutDevType == OUTDEV_PRINTER || ImplIsRecordLayout() )
+ return;
+
+ RasterOp eOldRop = GetRasterOp();
+ SetRasterOp( ROP_OVERPAINT );
+
+ OUTDEV_INIT();
+
+ TwoRect aPosAry;
+ aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
+ aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
+
+ if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight )
+ {
+ aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() );
+ aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() );
+ aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
+ aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
+
+ Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) );
+ Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
+ Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
+ long nOldRight = aSrcRect.Right();
+ long nOldBottom = aSrcRect.Bottom();
+
+ if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
+ {
+ if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
+ aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
+
+ if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
+ aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
+
+ if ( (meOutDevType == OUTDEV_WINDOW) && (nFlags & COPYAREA_WINDOWINVALIDATE) )
+ {
+ ((Window*)this)->ImplMoveAllInvalidateRegions( aSrcRect,
+ aPosAry.mnDestX-aPosAry.mnSrcX,
+ aPosAry.mnDestY-aPosAry.mnSrcY,
+ FALSE );
+
+ mpGraphics->CopyArea( aPosAry.mnDestX, aPosAry.mnDestY,
+ aPosAry.mnSrcX, aPosAry.mnSrcY,
+ aPosAry.mnSrcWidth, aPosAry.mnSrcHeight,
+ SAL_COPYAREA_WINDOWINVALIDATE, this );
+ }
+ else
+ {
+ aPosAry.mnDestWidth = aPosAry.mnSrcWidth;
+ aPosAry.mnDestHeight = aPosAry.mnSrcHeight;
+ mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
+ }
+ }
+ }
+
+ SetRasterOp( eOldRop );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->CopyArea( rDestPt, rSrcPt, rSrcSize, nFlags );
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
+ const OutputDevice& rOutDev, const Region& rRegion )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ BOOL bOldMap = mbMap;
+ RasterOp eOldROP = GetRasterOp();
+ mpMetaFile = NULL;
+ mbMap = FALSE;
+ SetRasterOp( ROP_OVERPAINT );
+
+ if ( !IsDeviceOutputNecessary() )
+ return;
+
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ // ClipRegion zuruecksetzen
+ if ( rRegion.IsNull() )
+ mpGraphics->ResetClipRegion();
+ else
+ ImplSelectClipRegion( rRegion );
+
+ TwoRect aPosAry;
+ aPosAry.mnSrcX = rDevPt.X();
+ aPosAry.mnSrcY = rDevPt.Y();
+ aPosAry.mnSrcWidth = rDevSize.Width();
+ aPosAry.mnSrcHeight = rDevSize.Height();
+ aPosAry.mnDestX = rPt.X();
+ aPosAry.mnDestY = rPt.Y();
+ aPosAry.mnDestWidth = rDevSize.Width();
+ aPosAry.mnDestHeight = rDevSize.Height();
+ ImplDrawOutDevDirect( &rOutDev, &aPosAry );
+
+ // Dafuer sorgen, das ClipRegion neu berechnet und gesetzt wird
+ mbInitClipRegion = TRUE;
+
+ SetRasterOp( eOldROP );
+ mbMap = bOldMap;
+ mpMetaFile = pOldMetaFile;
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
+ OutputDevice& rDev )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ BOOL bOldMap = mbMap;
+ mbMap = FALSE;
+ rDev.DrawOutDev( rDevPt, rDevSize, rPt, rDevSize, *this );
+ mbMap = bOldMap;
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
+{
+ DBG_TRACE( "OutputDevice::DrawBitmap()" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ const Size aSizePix( rBitmap.GetSizePixel() );
+ ImplDrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION );
+
+ if( mpAlphaVDev )
+ {
+ // #i32109#: Make bitmap area opaque
+ mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, PixelToLogic( aSizePix )) );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
+{
+ DBG_TRACE( "OutputDevice::DrawBitmap( Size )" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ ImplDrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION );
+
+ if( mpAlphaVDev )
+ {
+ // #i32109#: Make bitmap area opaque
+ mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap )
+{
+ DBG_TRACE( "OutputDevice::DrawBitmap( Point, Size )" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ ImplDrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, META_BMPSCALEPART_ACTION );
+
+ if( mpAlphaVDev )
+ {
+ // #i32109#: Make bitmap area opaque
+ mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void OutputDevice::ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const ULONG nAction )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Bitmap aBmp( rBitmap );
+
+ if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) )
+ return;
+ else if ( ROP_INVERT == meRasterOp )
+ {
+ DrawRect( Rectangle( rDestPt, rDestSize ) );
+ return;
+ }
+ else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
+ DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
+ {
+ if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
+ {
+ BYTE cCmpVal;
+
+ if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
+ cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
+ else
+ cCmpVal = 255;
+
+ Color aCol( cCmpVal, cCmpVal, cCmpVal );
+ Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ SetLineColor( aCol );
+ SetFillColor( aCol );
+ DrawRect( Rectangle( rDestPt, rDestSize ) );
+ Pop();
+ return;
+ }
+ else if( !!aBmp )
+ {
+ if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
+ aBmp.Convert( BMP_CONVERSION_8BIT_GREYS );
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
+ aBmp.Convert( BMP_CONVERSION_GHOSTED );
+ }
+ }
+
+ if ( mpMetaFile )
+ {
+ switch( nAction )
+ {
+ case( META_BMP_ACTION ):
+ mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) );
+ break;
+
+ case( META_BMPSCALE_ACTION ):
+ mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
+ break;
+
+ case( META_BMPSCALEPART_ACTION ):
+ mpMetaFile->AddAction( new MetaBmpScalePartAction(
+ rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) );
+ break;
+ }
+ }
+
+ OUTDEV_INIT();
+
+ if( !aBmp.IsEmpty() )
+ {
+ TwoRect aPosAry;
+
+ aPosAry.mnSrcX = rSrcPtPixel.X();
+ aPosAry.mnSrcY = rSrcPtPixel.Y();
+ aPosAry.mnSrcWidth = rSrcSizePixel.Width();
+ aPosAry.mnSrcHeight = rSrcSizePixel.Height();
+ aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
+ aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
+ aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
+ aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
+
+ const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmp.GetSizePixel() );
+
+ if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
+ {
+ if ( nMirrFlags )
+ aBmp.Mirror( nMirrFlags );
+
+ /* #i75264# (corrected with #i81576#)
+ * sometimes a bitmap is scaled to a ridiculous size and drawn
+ * to a quite normal VDev, so only a very small part of
+ * the scaled bitmap will be visible. However actually scaling
+ * the bitmap will use so much memory that we end with a crash.
+ * Workaround: since only a small part of the scaled bitmap will
+ * be actually drawn anyway (because of clipping on the device
+ * boundary), limit the destination and source rectangles so
+ * that the destination rectangle will overlap the device but only
+ * be reasonably (say factor 2) larger than the device itself.
+ */
+ if( aPosAry.mnDestWidth > 2048 || aPosAry.mnDestHeight > 2048 )
+ {
+ if( meOutDevType == OUTDEV_WINDOW ||
+ (meOutDevType == OUTDEV_VIRDEV && mpPDFWriter == 0 ) )
+ {
+ // #i81576# do the following trick only if there is overlap at all
+ // else the formulae don't work
+ // theoretically in this case we wouldn't need to draw the bitmap at all
+ // however there are some esoteric case where that is needed
+ if( aPosAry.mnDestX + aPosAry.mnDestWidth >= 0
+ && aPosAry.mnDestX < mnOutWidth
+ && aPosAry.mnDestY + aPosAry.mnDestHeight >= 0
+ && aPosAry.mnDestY < mnOutHeight )
+ {
+ // reduce scaling to something reasonable taking into account the output size
+ if( aPosAry.mnDestWidth > 3*mnOutWidth && aPosAry.mnSrcWidth )
+ {
+ const double nScaleX = aPosAry.mnDestWidth/double(aPosAry.mnSrcWidth);
+
+ if( aPosAry.mnDestX + aPosAry.mnDestWidth > mnOutWidth )
+ {
+ aPosAry.mnDestWidth = Max(long(0),mnOutWidth-aPosAry.mnDestX);
+ }
+ if( aPosAry.mnDestX < 0 )
+ {
+ aPosAry.mnDestWidth += aPosAry.mnDestX;
+ aPosAry.mnSrcX -= sal::static_int_cast<long>(aPosAry.mnDestX / nScaleX);
+ aPosAry.mnDestX = 0;
+ }
+
+ aPosAry.mnSrcWidth = sal::static_int_cast<long>(aPosAry.mnDestWidth / nScaleX);
+ }
+
+ if( aPosAry.mnDestHeight > 3*mnOutHeight && aPosAry.mnSrcHeight != 0 )
+ {
+ const double nScaleY = aPosAry.mnDestHeight/double(aPosAry.mnSrcHeight);
+
+ if( aPosAry.mnDestY + aPosAry.mnDestHeight > mnOutHeight )
+ {
+ aPosAry.mnDestHeight = Max(long(0),mnOutHeight-aPosAry.mnDestY);
+ }
+ if( aPosAry.mnDestY < 0 )
+ {
+ aPosAry.mnDestHeight += aPosAry.mnDestY;
+ aPosAry.mnSrcY -= sal::static_int_cast<long>(aPosAry.mnDestY / nScaleY);
+ aPosAry.mnDestY = 0;
+ }
+
+ aPosAry.mnSrcHeight = sal::static_int_cast<long>(aPosAry.mnDestHeight / nScaleY);
+ }
+ }
+ }
+ }
+
+ if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
+ mpGraphics->DrawBitmap( &aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap(), this );
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawBitmapEx( const Point& rDestPt,
+ const BitmapEx& rBitmapEx )
+{
+ DBG_TRACE( "OutputDevice::DrawBitmapEx()" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
+ DrawBitmap( rDestPt, rBitmapEx.GetBitmap() );
+ else
+ {
+ const Size aSizePix( rBitmapEx.GetSizePixel() );
+ ImplDrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const BitmapEx& rBitmapEx )
+{
+ DBG_TRACE( "OutputDevice::DrawBitmapEx( Size )" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
+ DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() );
+ else
+ ImplDrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION );
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx )
+{
+ DBG_TRACE( "OutputDevice::DrawBitmapEx( Point, Size )" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
+ DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() );
+ else
+ ImplDrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx, META_BMPEXSCALEPART_ACTION );
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx, const ULONG nAction )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ BitmapEx aBmpEx( rBitmapEx );
+
+ if ( mnDrawMode & DRAWMODE_NOBITMAP )
+ return;
+ else if ( ROP_INVERT == meRasterOp )
+ {
+ DrawRect( Rectangle( rDestPt, rDestSize ) );
+ return;
+ }
+ else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
+ DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
+ {
+ if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
+ {
+ Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 );
+ BYTE cCmpVal;
+
+ if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
+ cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
+ else
+ cCmpVal = 255;
+
+ aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
+
+ if( aBmpEx.IsAlpha() )
+ {
+ // Create one-bit mask out of alpha channel, by
+ // thresholding it at alpha=0.5. As
+ // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
+ // output, having alpha-induced grey levels is not
+ // acceptable.
+ Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() );
+ aMask.MakeMono( 128 );
+ aBmpEx = BitmapEx( aColorBmp, aMask );
+ }
+ else
+ {
+ aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
+ }
+ }
+ else if( !!aBmpEx )
+ {
+ if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
+ aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
+ aBmpEx.Convert( BMP_CONVERSION_GHOSTED );
+ }
+ }
+
+ if ( mpMetaFile )
+ {
+ switch( nAction )
+ {
+ case( META_BMPEX_ACTION ):
+ mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
+ break;
+
+ case( META_BMPEXSCALE_ACTION ):
+ mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
+ break;
+
+ case( META_BMPEXSCALEPART_ACTION ):
+ mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
+ rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
+ break;
+ }
+ }
+
+ OUTDEV_INIT();
+
+ if( OUTDEV_PRINTER == meOutDevType )
+ {
+ if( aBmpEx.IsAlpha() )
+ {
+ // #107169# For true alpha bitmaps, no longer masking the
+ // bitmap, but perform a full alpha blend against a white
+ // background here.
+ Bitmap aBmp( aBmpEx.GetBitmap() );
+ aBmp.Blend( aBmpEx.GetAlpha(), Color( COL_WHITE) );
+ DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
+ }
+ else
+ {
+ Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() );
+ aBmp.Replace( aMask, Color( COL_WHITE ) );
+ ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
+ }
+ return;
+ }
+ else if( aBmpEx.IsAlpha() )
+ {
+ ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
+ return;
+ }
+
+ if( !( !aBmpEx ) )
+ {
+ TwoRect aPosAry;
+
+ aPosAry.mnSrcX = rSrcPtPixel.X();
+ aPosAry.mnSrcY = rSrcPtPixel.Y();
+ aPosAry.mnSrcWidth = rSrcSizePixel.Width();
+ aPosAry.mnSrcHeight = rSrcSizePixel.Height();
+ aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
+ aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
+ aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
+ aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
+
+ const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() );
+
+ if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
+ {
+
+ if( nMirrFlags )
+ aBmpEx.Mirror( nMirrFlags );
+
+ const ImpBitmap* pImpBmp = aBmpEx.ImplGetBitmapImpBitmap();
+ const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap();
+
+ if ( pMaskBmp )
+ {
+ // #4919452# reduce operation area to bounds of
+ // cliprect. since masked transparency involves
+ // creation of a large vdev and copying the screen
+ // content into that (slooow read from framebuffer),
+ // that should considerably increase performance for
+ // large bitmaps and small clippings.
+
+ // Note that this optimisation is a workaround for a
+ // Writer peculiarity, namely, to decompose background
+ // graphics into myriads of disjunct, tiny
+ // rectangles. That otherwise kills us here, since for
+ // transparent output, SAL always prepares the whole
+ // bitmap, if aPosAry contains the whole bitmap (and
+ // it's _not_ to blame for that).
+
+ // Note the call to ImplPixelToDevicePixel(), since
+ // aPosAry already contains the mnOutOff-offsets, they
+ // also have to be applied to the region
+ Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
+
+ // TODO: Also respect scaling (that's a bit tricky,
+ // since the source points have to move fractional
+ // amounts (which is not possible, thus has to be
+ // emulated by increases copy area)
+ // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
+ // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
+
+ // for now, only identity scales allowed
+ if( !aClipRegionBounds.IsEmpty() &&
+ aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
+ aPosAry.mnDestHeight == aPosAry.mnSrcHeight )
+ {
+ // now intersect dest rect with clip region
+ aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX,
+ aPosAry.mnDestY,
+ aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
+ aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) );
+
+ // Note: I could theoretically optimize away the
+ // DrawBitmap below, if the region is empty
+ // here. Unfortunately, cannot rule out that
+ // somebody relies on the side effects.
+ if( !aClipRegionBounds.IsEmpty() )
+ {
+ aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
+ aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
+ aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
+ aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
+
+ aPosAry.mnDestX = aClipRegionBounds.Left();
+ aPosAry.mnDestY = aClipRegionBounds.Top();
+ aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
+ aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
+ }
+ }
+
+ mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
+ *pMaskBmp->ImplGetSalBitmap(),
+ this );
+
+ // #110958# Paint mask to alpha channel. Luckily, the
+ // black and white representation of the mask maps to
+ // the alpha channel
+
+ // #i25167# Restrict mask painting to _opaque_ areas
+ // of the mask, otherwise we spoil areas where no
+ // bitmap content was ever visible. Interestingly
+ // enough, this can be achieved by taking the mask as
+ // the transparency mask of itself
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawBitmapEx( rDestPt,
+ rDestSize,
+ BitmapEx( aBmpEx.GetMask(),
+ aBmpEx.GetMask() ) );
+ }
+ else
+ {
+ mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(), this );
+
+ if( mpAlphaVDev )
+ {
+ // #i32109#: Make bitmap area opaque
+ mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawMask( const Point& rDestPt,
+ const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ DBG_TRACE( "OutputDevice::DrawMask()" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ const Size aSizePix( rBitmap.GetSizePixel() );
+ ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION );
+
+ if( mpAlphaVDev )
+ {
+ const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
+
+ // #i25167# Restrict mask painting to _opaque_ areas
+ // of the mask, otherwise we spoil areas where no
+ // bitmap content was ever visible. Interestingly
+ // enough, this can be achieved by taking the mask as
+ // the transparency mask of itself
+ mpAlphaVDev->DrawBitmapEx( rDestPt,
+ PixelToLogic( aSizePix ),
+ BitmapEx( rMask, rMask ) );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ DBG_TRACE( "OutputDevice::DrawMask( Size )" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION );
+
+ // TODO: Use mask here
+ if( mpAlphaVDev )
+ {
+ const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
+
+ // #i25167# Restrict mask painting to _opaque_ areas
+ // of the mask, otherwise we spoil areas where no
+ // bitmap content was ever visible. Interestingly
+ // enough, this can be achieved by taking the mask as
+ // the transparency mask of itself
+ mpAlphaVDev->DrawBitmapEx( rDestPt,
+ rDestSize,
+ BitmapEx( rMask, rMask ) );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" );
+
+ if( ImplIsRecordLayout() )
+ return;
+
+ ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION );
+
+ // TODO: Use mask here
+ if( mpAlphaVDev )
+ {
+ const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
+
+ // #i25167# Restrict mask painting to _opaque_ areas
+ // of the mask, otherwise we spoil areas where no
+ // bitmap content was ever visible. Interestingly
+ // enough, this can be achieved by taking the mask as
+ // the transparency mask of itself
+ mpAlphaVDev->DrawBitmapEx( rDestPt,
+ rDestSize,
+ rSrcPtPixel,
+ rSrcSizePixel,
+ BitmapEx( rMask, rMask ) );
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const Color& rMaskColor,
+ const ULONG nAction )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( ROP_INVERT == meRasterOp )
+ {
+ DrawRect( Rectangle( rDestPt, rDestSize ) );
+ return;
+ }
+
+ if ( mpMetaFile )
+ {
+ switch( nAction )
+ {
+ case( META_MASK_ACTION ):
+ mpMetaFile->AddAction( new MetaMaskAction( rDestPt,
+ rBitmap, rMaskColor ) );
+ break;
+
+ case( META_MASKSCALE_ACTION ):
+ mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt,
+ rDestSize, rBitmap, rMaskColor ) );
+ break;
+
+ case( META_MASKSCALEPART_ACTION ):
+ mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize,
+ rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) );
+ break;
+ }
+ }
+
+ OUTDEV_INIT();
+
+ if ( OUTDEV_PRINTER == meOutDevType )
+ {
+ ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
+ return;
+ }
+
+ const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
+ if ( pImpBmp )
+ {
+ TwoRect aPosAry;
+
+ aPosAry.mnSrcX = rSrcPtPixel.X();
+ aPosAry.mnSrcY = rSrcPtPixel.Y();
+ aPosAry.mnSrcWidth = rSrcSizePixel.Width();
+ aPosAry.mnSrcHeight = rSrcSizePixel.Height();
+ aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
+ aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
+ aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
+ aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
+
+ // spiegeln via Koordinaten wollen wir nicht
+ const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() );
+
+ // check if output is necessary
+ if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
+ {
+
+ if( nMirrFlags )
+ {
+ Bitmap aTmp( rBitmap );
+ aTmp.Mirror( nMirrFlags );
+ mpGraphics->DrawMask( &aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(),
+ ImplColorToSal( rMaskColor ) , this);
+ }
+ else
+ mpGraphics->DrawMask( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
+ ImplColorToSal( rMaskColor ), this );
+
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, USHORT nStyle )
+{
+ DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
+
+ if( !rImage.mpImplData || ImplIsRecordLayout() )
+ return;
+
+ switch( rImage.mpImplData->meType )
+ {
+ case IMAGETYPE_BITMAP:
+ DrawBitmap( rPos, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
+ break;
+
+ case IMAGETYPE_IMAGE:
+ {
+ ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
+
+ if( !pData->mpImageBitmap )
+ {
+ const Size aSize( pData->maBmpEx.GetSizePixel() );
+
+ pData->mpImageBitmap = new ImplImageBmp;
+ pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
+ }
+
+ pData->mpImageBitmap->Draw( 0, this, rPos, nStyle );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
+ const Image& rImage, USHORT nStyle )
+{
+ DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
+
+ if( rImage.mpImplData && !ImplIsRecordLayout() )
+ {
+ switch( rImage.mpImplData->meType )
+ {
+ case IMAGETYPE_BITMAP:
+ DrawBitmap( rPos, rSize, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
+ break;
+
+ case IMAGETYPE_IMAGE:
+ {
+ ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
+
+ if ( !pData->mpImageBitmap )
+ {
+ const Size aSize( pData->maBmpEx.GetSizePixel() );
+
+ pData->mpImageBitmap = new ImplImageBmp;
+ pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
+ }
+
+ pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+
+Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Bitmap aBmp;
+ long nX = ImplLogicXToDevicePixel( rSrcPt.X() );
+ long nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
+ long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
+ long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
+
+ if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() )
+ {
+ if ( nWidth && nHeight )
+ {
+ Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ BOOL bClipped = FALSE;
+
+ // X-Koordinate ausserhalb des Bereichs?
+ if ( nX < mnOutOffX )
+ {
+ nWidth -= ( mnOutOffX - nX );
+ nX = mnOutOffX;
+ bClipped = TRUE;
+ }
+
+ // Y-Koordinate ausserhalb des Bereichs?
+ if ( nY < mnOutOffY )
+ {
+ nHeight -= ( mnOutOffY - nY );
+ nY = mnOutOffY;
+ bClipped = TRUE;
+ }
+
+ // Breite ausserhalb des Bereichs?
+ if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
+ {
+ nWidth = mnOutOffX + mnOutWidth - nX;
+ bClipped = TRUE;
+ }
+
+ // Hoehe ausserhalb des Bereichs?
+ if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
+ {
+ nHeight = mnOutOffY + mnOutHeight - nY;
+ bClipped = TRUE;
+ }
+
+ if ( bClipped )
+ {
+ // Falls auf den sichtbaren Bereich geclipped wurde,
+ // muessen wir eine Bitmap in der rchtigen Groesse
+ // erzeugen, in die die geclippte Bitmap an die angepasste
+ // Position kopiert wird
+ VirtualDevice aVDev( *this );
+
+ if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) )
+ {
+ if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() )
+ {
+ TwoRect aPosAry;
+
+ aPosAry.mnSrcX = nX;
+ aPosAry.mnSrcY = nY;
+ aPosAry.mnSrcWidth = nWidth;
+ aPosAry.mnSrcHeight = nHeight;
+ aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L;
+ aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L;
+ aPosAry.mnDestWidth = nWidth;
+ aPosAry.mnDestHeight = nHeight;
+
+ if ( (nWidth > 0) && (nHeight > 0) )
+ (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( &aPosAry, mpGraphics, this, this );
+
+ aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
+ }
+ else
+ bClipped = FALSE;
+ }
+ else
+ bClipped = FALSE;
+ }
+
+ if ( !bClipped )
+ {
+ SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
+
+ if( pSalBmp )
+ {
+ ImpBitmap* pImpBmp = new ImpBitmap;
+ pImpBmp->ImplSetSalBitmap( pSalBmp );
+ aBmp.ImplSetImpBitmap( pImpBmp );
+ }
+ }
+ }
+ }
+
+ return aBmp;
+}
+
+// ------------------------------------------------------------------
+
+BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // #110958# Extract alpha value from VDev, if any
+ if( mpAlphaVDev )
+ {
+ Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
+
+ // ensure 8 bit alpha
+ if( aAlphaBitmap.GetBitCount() > 8 )
+ aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
+
+ return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
+ }
+ else
+ return GetBitmap( rSrcPt, rSize );
+}
+
+// ------------------------------------------------------------------
+
+void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize,
+ Bitmap& rBitmap ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ BOOL bOldMap = mbMap;
+ ((OutputDevice*)this)->mbMap = FALSE;
+ rBitmap = GetBitmap( rDestPt, rSize );
+ ((OutputDevice*)this)->mbMap = bOldMap;
+}
+
+// ------------------------------------------------------------------
+
+Color OutputDevice::GetPixel( const Point& rPt ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor;
+
+ if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
+ {
+ if ( mbInitClipRegion )
+ ((OutputDevice*)this)->ImplInitClipRegion();
+
+ if ( !mbOutputClipped )
+ {
+ const long nX = ImplLogicXToDevicePixel( rPt.X() );
+ const long nY = ImplLogicYToDevicePixel( rPt.Y() );
+ const SalColor aSalCol = mpGraphics->GetPixel( nX, nY, this );
+ aColor.SetRed( SALCOLOR_RED( aSalCol ) );
+ aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
+ aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
+ }
+ }
+ return aColor;
+}
+
+// ------------------------------------------------------------------
+
+Color* OutputDevice::GetPixel( const Polygon& rPts ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color* pColors = NULL;
+ const USHORT nSize = rPts.GetSize();
+
+ if( nSize )
+ {
+ if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
+ {
+ if ( mbInitClipRegion )
+ ((OutputDevice*)this)->ImplInitClipRegion();
+
+ if ( !mbOutputClipped )
+ {
+ pColors = new Color[ nSize ];
+
+ for( USHORT i = 0; i < nSize; i++ )
+ {
+ Color& rCol = pColors[ i ];
+ const Point& rPt = rPts[ i ];
+ const SalColor aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ),
+ ImplLogicYToDevicePixel( rPt.Y() ) , this) );
+
+ rCol.SetRed( SALCOLOR_RED( aSalCol ) );
+ rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) );
+ rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) );
+ }
+ }
+ }
+ }
+
+ return pColors;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPixel( const Point& rPt )
+{
+ DBG_TRACE( "OutputDevice::DrawPixel()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPointAction( rPt ) );
+
+ if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
+ return;
+
+ Point aPt = ImplLogicToDevicePixel( rPt );
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPixel( rPt );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
+{
+ DBG_TRACE( "OutputDevice::DrawPixel()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor( rColor );
+
+ if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
+ DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
+ DRAWMODE_SETTINGSLINE ) )
+ {
+ if( !ImplIsColorTransparent( aColor ) )
+ {
+ if( mnDrawMode & DRAWMODE_BLACKLINE )
+ {
+ aColor = Color( COL_BLACK );
+ }
+ else if( mnDrawMode & DRAWMODE_WHITELINE )
+ {
+ aColor = Color( COL_WHITE );
+ }
+ else if( mnDrawMode & DRAWMODE_GRAYLINE )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
+ {
+ aColor = GetSettings().GetStyleSettings().GetFontColor();
+ }
+
+ if( mnDrawMode & DRAWMODE_GHOSTEDLINE )
+ {
+ aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
+ ( aColor.GetGreen() >> 1 ) | 0x80,
+ ( aColor.GetBlue() >> 1 ) | 0x80 );
+ }
+ }
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );
+
+ if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
+ return;
+
+ Point aPt = ImplLogicToDevicePixel( rPt );
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPixel( rPt );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
+{
+ if ( !pColors )
+ DrawPixel( rPts, GetLineColor() );
+ else
+ {
+ DBG_TRACE( "OutputDevice::DrawPixel()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );
+
+ const USHORT nSize = rPts.GetSize();
+
+ if ( nSize )
+ {
+ if ( mpMetaFile )
+ for ( USHORT i = 0; i < nSize; i++ )
+ mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );
+
+ if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ // we need a graphics
+ if ( mpGraphics || ImplGetGraphics() )
+ {
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( mbOutputClipped )
+ return;
+
+ for ( USHORT i = 0; i < nSize; i++ )
+ {
+ const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
+ mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
+ }
+ }
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPixel( rPts, pColors );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
+{
+ if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
+ {
+ const USHORT nSize = rPts.GetSize();
+ Color* pColArray = new Color[ nSize ];
+
+ for( USHORT i = 0; i < nSize; i++ )
+ pColArray[ i ] = rColor;
+
+ DrawPixel( rPts, pColArray );
+ delete[] pColArray;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPixel( rPts, rColor );
+}
+
+// ------------------------------------------------------------------------
+
+namespace
+{
+ BYTE lcl_calcColor( const BYTE nSourceColor, const BYTE nSourceOpaq, const BYTE nDestColor )
+ {
+ int c = ( (int)nDestColor * ( 255 - nSourceOpaq ) )
+ + (int)nSourceOpaq * (int)nSourceColor;
+ return BYTE( c / 255 );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap aBmp,
+ BitmapReadAccess* pP,
+ BitmapReadAccess* pA,
+ const Rectangle& aDstRect,
+ const sal_Int32 nOffY,
+ const sal_Int32 nDstHeight,
+ const sal_Int32 nOffX,
+ const sal_Int32 nDstWidth,
+ const long* pMapX,
+ const long* pMapY )
+{
+ BitmapColor aDstCol,aSrcCol;
+ Bitmap res;
+ int nX, nOutX, nY, nOutY;
+
+ OSL_ENSURE(mpAlphaVDev,
+ "ImplBlendWithAlpha(): call me only with valid alpha VDev!" );
+
+ BOOL bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
+ mpAlphaVDev->EnableMapMode(FALSE);
+
+ Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
+ BitmapWriteAccess* pAlphaW = aAlphaBitmap.AcquireWriteAccess();
+
+ if( GetBitCount() <= 8 )
+ {
+ Bitmap aDither( aBmp.GetSizePixel(), 8 );
+ BitmapColor aIndex( 0 );
+ BitmapReadAccess* pB = aBmp.AcquireReadAccess();
+ BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
+
+ if( pB && pP && pA && pW && pAlphaW )
+ {
+ for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
+ {
+ const long nMapY = pMapY[ nY ];
+ const long nModY = ( nOutY & 0x0FL ) << 4L;
+
+ for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
+ {
+ const long nMapX = pMapX[ nX ];
+ const ULONG nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
+
+ aSrcCol = pP->GetColor( nMapY, nMapX );
+ aDstCol = pB->GetColor( nY, nX );
+ const BYTE nSrcOpaq = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
+ const BYTE nDstOpaq = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
+
+ aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
+ aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
+ aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
+
+ aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
+ nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
+ nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
+ pW->SetPixel( nY, nX, aIndex );
+
+ // Have to perform the compositing 'algebra' in
+ // the inverse alpha space (with 255 meaning
+ // opaque), otherwise, transitivity is not
+ // achieved.
+ const BYTE nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (BYTE)nDstOpaq, nSrcOpaq );
+
+ aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
+ nVCLGLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
+ nVCLBLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] ) );
+ pAlphaW->SetPixel( nY, nX, aIndex );
+ }
+ }
+ }
+
+ aBmp.ReleaseAccess( pB );
+ aDither.ReleaseAccess( pW );
+ res = aDither;
+ }
+ else
+ {
+ BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
+ if( pP && pA && pB )
+ {
+ for( nY = 0; nY < nDstHeight; nY++ )
+ {
+ const long nMapY = pMapY[ nY ];
+
+ for( nX = 0; nX < nDstWidth; nX++ )
+ {
+ const long nMapX = pMapX[ nX ];
+
+ aSrcCol = pP->GetColor( nMapY, nMapX );
+ aDstCol = pB->GetColor( nY, nX );
+ const BYTE nSrcOpaq = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
+ const BYTE nDstOpaq = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
+
+ aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
+ aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
+ aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
+
+ pB->SetPixel( nY, nX, aDstCol );
+
+ // Have to perform the compositing 'algebra' in
+ // the inverse alpha space (with 255 meaning
+ // opaque), otherwise, transitivity is not
+ // achieved.
+ const BYTE nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (BYTE)nDstOpaq, nSrcOpaq );
+
+ pAlphaW->SetPixel( nY, nX, Color(nSrcAlpha, nSrcAlpha, nSrcAlpha) );
+ }
+ }
+ }
+
+ aBmp.ReleaseAccess( pB );
+ res = aBmp;
+ }
+
+ aAlphaBitmap.ReleaseAccess( pAlphaW );
+ mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
+ mpAlphaVDev->EnableMapMode( bOldMapMode );
+
+ return res;
+}
+
+// ------------------------------------------------------------------------
+
+Bitmap OutputDevice::ImplBlend( Bitmap aBmp,
+ BitmapReadAccess* pP,
+ BitmapReadAccess* pA,
+ const sal_Int32 nOffY,
+ const sal_Int32 nDstHeight,
+ const sal_Int32 nOffX,
+ const sal_Int32 nDstWidth,
+ const Rectangle& aBmpRect,
+ const Size& aOutSz,
+ const bool bHMirr,
+ const bool bVMirr,
+ const long* pMapX,
+ const long* pMapY )
+{
+ BitmapColor aDstCol;
+ Bitmap res;
+ int nX, nOutX, nY, nOutY;
+
+ if( GetBitCount() <= 8 )
+ {
+ Bitmap aDither( aBmp.GetSizePixel(), 8 );
+ BitmapColor aIndex( 0 );
+ BitmapReadAccess* pB = aBmp.AcquireReadAccess();
+ BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
+
+ if( pB && pP && pA && pW )
+ {
+ for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
+ {
+ const long nMapY = pMapY[ nY ];
+ const long nModY = ( nOutY & 0x0FL ) << 4L;
+
+ for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
+ {
+ const long nMapX = pMapX[ nX ];
+ const ULONG nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
+
+ aDstCol = pB->GetColor( nY, nX );
+ aDstCol.Merge( pP->GetColor( nMapY, nMapX ), (BYTE) pA->GetPixel( nMapY, nMapX ) );
+ aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
+ nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
+ nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
+ pW->SetPixel( nY, nX, aIndex );
+ }
+ }
+ }
+
+ aBmp.ReleaseAccess( pB );
+ aDither.ReleaseAccess( pW );
+ res = aDither;
+ }
+ else
+ {
+ BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
+
+ bool bFastBlend = false;
+ if( pP && pA && pB )
+ {
+ SalTwoRect aTR;
+ aTR.mnSrcX = aBmpRect.Left();
+ aTR.mnSrcY = aBmpRect.Top();
+ aTR.mnSrcWidth = aBmpRect.GetWidth();
+ aTR.mnSrcHeight = aBmpRect.GetHeight();
+ aTR.mnDestX = nOffX;
+ aTR.mnDestY = nOffY;
+ aTR.mnDestWidth = aOutSz.Width();
+ aTR.mnDestHeight= aOutSz.Height();
+
+ if( !bHMirr || !bVMirr )
+ bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
+ }
+
+ if( pP && pA && pB && !bFastBlend )
+ {
+ switch( pP->GetScanlineFormat() )
+ {
+ case( BMP_FORMAT_8BIT_PAL ):
+ {
+ for( nY = 0; nY < nDstHeight; nY++ )
+ {
+ const long nMapY = pMapY[ nY ];
+ Scanline pPScan = pP->GetScanline( nMapY );
+ Scanline pAScan = pA->GetScanline( nMapY );
+
+ for( nX = 0; nX < nDstWidth; nX++ )
+ {
+ const long nMapX = pMapX[ nX ];
+ aDstCol = pB->GetPixel( nY, nX );
+ pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ),
+ pAScan[ nMapX ] ) );
+ }
+ }
+ }
+ break;
+
+ case( BMP_FORMAT_24BIT_TC_BGR ):
+ {
+ for( nY = 0; nY < nDstHeight; nY++ )
+ {
+ const long nMapY = pMapY[ nY ];
+ Scanline pPScan = pP->GetScanline( nMapY );
+ Scanline pAScan = pA->GetScanline( nMapY );
+
+ for( nX = 0; nX < nDstWidth; nX++ )
+ {
+ const long nMapX = pMapX[ nX ];
+ Scanline pTmp = pPScan + nMapX * 3;
+
+ aDstCol = pB->GetPixel( nY, nX );
+ pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
+ pAScan[ nMapX ] ) );
+ }
+ }
+ }
+ break;
+
+ case( BMP_FORMAT_24BIT_TC_RGB ):
+ {
+ for( nY = 0; nY < nDstHeight; nY++ )
+ {
+ const long nMapY = pMapY[ nY ];
+ Scanline pPScan = pP->GetScanline( nMapY );
+ Scanline pAScan = pA->GetScanline( nMapY );
+
+ for( nX = 0; nX < nDstWidth; nX++ )
+ {
+ const long nMapX = pMapX[ nX ];
+ Scanline pTmp = pPScan + nMapX * 3;
+
+ aDstCol = pB->GetPixel( nY, nX );
+ pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
+ pAScan[ nMapX ] ) );
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ for( nY = 0; nY < nDstHeight; nY++ )
+ {
+ const long nMapY = pMapY[ nY ];
+ Scanline pAScan = pA->GetScanline( nMapY );
+
+ for( nX = 0; nX < nDstWidth; nX++ )
+ {
+ const long nMapX = pMapX[ nX ];
+ aDstCol = pB->GetPixel( nY, nX );
+ pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ),
+ pAScan[ nMapX ] ) );
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ aBmp.ReleaseAccess( pB );
+ res = aBmp;
+ }
+
+ return res;
+}
+
+// ------------------------------------------------------------------------
+
+void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel )
+{
+ const Point aNullPt;
+ Point aOutPt( LogicToPixel( rDestPt ) );
+ Size aOutSz( LogicToPixel( rDestSize ) );
+ Rectangle aDstRect( aNullPt, GetOutputSizePixel() );
+ const BOOL bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0;
+
+ if( OUTDEV_WINDOW == meOutDevType )
+ {
+ const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
+
+ if( !aPaintRgn.IsNull() )
+ aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) );
+ }
+
+ if( bHMirr )
+ {
+ aOutSz.Width() = -aOutSz.Width();
+ aOutPt.X() -= ( aOutSz.Width() - 1L );
+ }
+
+ if( bVMirr )
+ {
+ aOutSz.Height() = -aOutSz.Height();
+ aOutPt.Y() -= ( aOutSz.Height() - 1L );
+ }
+
+ if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
+ {
+ bool bNativeAlpha = false;
+ static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
+ // #i83087# Naturally, system alpha blending cannot work with
+ // separate alpha VDev
+ if( !mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr )
+ {
+ Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
+ SalTwoRect aTR = {
+ rSrcPtPixel.X(), rSrcPtPixel.Y(),
+ rSrcSizePixel.Width(), rSrcSizePixel.Height(),
+ aRelPt.X(), aRelPt.Y(),
+ aOutSz.Width(), aOutSz.Height()
+ };
+ SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
+ SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
+ bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this );
+ }
+
+ VirtualDevice* pOldVDev = mpAlphaVDev;
+
+ Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() );
+ if( !bNativeAlpha
+ && !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() )
+ {
+ GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = NULL;
+ const BOOL bOldMap = mbMap; mbMap = FALSE;
+ Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
+
+ // #109044# The generated bitmap need not necessarily be
+ // of aDstRect dimensions, it's internally clipped to
+ // window bounds. Thus, we correct the dest size here,
+ // since we later use it (in nDstWidth/Height) for pixel
+ // access)
+ // #i38887# reading from screen may sometimes fail
+ if( aBmp.ImplGetImpBitmap() )
+ aDstRect.SetSize( aBmp.GetSizePixel() );
+
+ BitmapColor aDstCol;
+ const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
+ const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
+ const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
+ const long nOffX = aDstRect.Left() - aOutPt.X(), nOffY = aDstRect.Top() - aOutPt.Y();
+ long nX, nOutX, nY, nOutY;
+ long nMirrOffX = 0;
+ long nMirrOffY = 0;
+ long* pMapX = new long[ nDstWidth ];
+ long* pMapY = new long[ nDstHeight ];
+
+ // create horizontal mapping table
+ if( bHMirr )
+ nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
+
+ for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
+ {
+ pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
+
+ if( bHMirr )
+ pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
+ }
+
+ // create vertical mapping table
+ if( bVMirr )
+ nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
+
+ for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
+ {
+ pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
+
+ if( bVMirr )
+ pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
+ }
+
+ BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
+ BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
+
+ DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
+ pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
+ "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
+
+ // #i38887# reading from screen may sometimes fail
+ if( aBmp.ImplGetImpBitmap() )
+ {
+ Bitmap aTmp;
+
+ if( mpAlphaVDev )
+ {
+ aTmp = ImplBlendWithAlpha(
+ aBmp,pP,pA,
+ aDstRect,
+ nOffY,nDstHeight,
+ nOffX,nDstWidth,
+ pMapX,pMapY );
+ }
+ else
+ {
+ aTmp = ImplBlend(
+ aBmp,pP,pA,
+ nOffY,nDstHeight,
+ nOffX,nDstWidth,
+ aBmpRect,aOutSz,
+ bHMirr,bVMirr,
+ pMapX,pMapY );
+ }
+
+ // #110958# Disable alpha VDev, we're doing the necessary
+ // stuff explicitely furher below
+ if( mpAlphaVDev )
+ mpAlphaVDev = NULL;
+
+ DrawBitmap( aDstRect.TopLeft(),
+ aTmp );
+
+ // #110958# Enable alpha VDev again
+ mpAlphaVDev = pOldVDev;
+ }
+
+ ( (Bitmap&) rBmp ).ReleaseAccess( pP );
+ ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
+
+ delete[] pMapX;
+ delete[] pMapY;
+ mbMap = bOldMap;
+ mpMetaFile = pOldMetaFile;
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel )
+{
+ Point aPt;
+ Point aDestPt( LogicToPixel( rDestPt ) );
+ Size aDestSz( LogicToPixel( rDestSize ) );
+ Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
+
+ aSrcRect.Justify();
+
+ if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
+ {
+ Bitmap aPaint( rBmp ), aMask( rMask );
+ ULONG nMirrFlags = 0UL;
+
+ if( aMask.GetBitCount() > 1 )
+ aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+
+ // mirrored horizontically
+ if( aDestSz.Width() < 0L )
+ {
+ aDestSz.Width() = -aDestSz.Width();
+ aDestPt.X() -= ( aDestSz.Width() - 1L );
+ nMirrFlags |= BMP_MIRROR_HORZ;
+ }
+
+ // mirrored vertically
+ if( aDestSz.Height() < 0L )
+ {
+ aDestSz.Height() = -aDestSz.Height();
+ aDestPt.Y() -= ( aDestSz.Height() - 1L );
+ nMirrFlags |= BMP_MIRROR_VERT;
+ }
+
+ // source cropped?
+ if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) )
+ {
+ aPaint.Crop( aSrcRect );
+ aMask.Crop( aSrcRect );
+ }
+
+ // destination mirrored
+ if( nMirrFlags )
+ {
+ aPaint.Mirror( nMirrFlags );
+ aMask.Mirror( nMirrFlags );
+ }
+
+ // we always want to have a mask
+ if( aMask.IsEmpty() )
+ {
+ aMask = Bitmap( aSrcRect.GetSize(), 1 );
+ aMask.Erase( Color( COL_BLACK ) );
+ }
+
+ // do painting
+ const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
+ long nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
+ long* pMapX = new long[ nSrcWidth + 1 ];
+ long* pMapY = new long[ nSrcHeight + 1 ];
+ const BOOL bOldMap = mbMap;
+
+ mbMap = FALSE;
+
+ // create forward mapping tables
+ for( nX = 0L; nX <= nSrcWidth; nX++ )
+ pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
+
+ for( nY = 0L; nY <= nSrcHeight; nY++ )
+ pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
+
+ // walk through all rectangles of mask
+ Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
+ ImplRegionInfo aInfo;
+ BOOL bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
+
+ while( bRgnRect )
+ {
+ Bitmap aBandBmp( aPaint );
+ const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) );
+ const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
+ const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
+
+ aBandBmp.Crop( aBandRect );
+ ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION );
+ bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
+ }
+
+ mbMap = bOldMap;
+
+ delete[] pMapX;
+ delete[] pMapY;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel )
+{
+ Point aPt;
+ Point aDestPt( LogicToPixel( rDestPt ) );
+ Size aDestSz( LogicToPixel( rDestSize ) );
+ Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
+
+ aSrcRect.Justify();
+
+ if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
+ {
+ Bitmap aMask( rMask );
+ ULONG nMirrFlags = 0UL;
+
+ if( aMask.GetBitCount() > 1 )
+ aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+
+ // mirrored horizontically
+ if( aDestSz.Width() < 0L )
+ {
+ aDestSz.Width() = -aDestSz.Width();
+ aDestPt.X() -= ( aDestSz.Width() - 1L );
+ nMirrFlags |= BMP_MIRROR_HORZ;
+ }
+
+ // mirrored vertically
+ if( aDestSz.Height() < 0L )
+ {
+ aDestSz.Height() = -aDestSz.Height();
+ aDestPt.Y() -= ( aDestSz.Height() - 1L );
+ nMirrFlags |= BMP_MIRROR_VERT;
+ }
+
+ // source cropped?
+ if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) )
+ aMask.Crop( aSrcRect );
+
+ // destination mirrored
+ if( nMirrFlags )
+ aMask.Mirror( nMirrFlags );
+
+ // do painting
+ const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
+ long nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
+ long* pMapX = new long[ nSrcWidth + 1 ];
+ long* pMapY = new long[ nSrcHeight + 1 ];
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ const BOOL bOldMap = mbMap;
+
+ mpMetaFile = NULL;
+ mbMap = FALSE;
+ Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
+ SetLineColor( rMaskColor );
+ SetFillColor( rMaskColor );
+ ImplInitLineColor();
+ ImplInitFillColor();
+
+ // create forward mapping tables
+ for( nX = 0L; nX <= nSrcWidth; nX++ )
+ pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
+
+ for( nY = 0L; nY <= nSrcHeight; nY++ )
+ pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
+
+ // walk through all rectangles of mask
+ Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
+ ImplRegionInfo aInfo;
+ BOOL bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
+
+ while( bRgnRect )
+ {
+ const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
+ const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
+
+ DrawRect( Rectangle( aMapPt, aMapSz ) );
+ bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
+ }
+
+ Pop();
+ delete[] pMapX;
+ delete[] pMapY;
+ mbMap = bOldMap;
+ mpMetaFile = pOldMetaFile;
+ }
+}
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
new file mode 100644
index 000000000000..bf1cc2728bf1
--- /dev/null
+++ b/vcl/source/gdi/outdev3.cxx
@@ -0,0 +1,8022 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <cstring>
+#include <i18npool/mslangid.hxx>
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salgdi.hxx>
+#include <vcl/sallayout.hxx>
+#include <rtl/tencinfo.h>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/impfont.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/outdata.hxx>
+#include <vcl/outfont.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <tools/poly.hxx>
+#include <vcl/outdev.h>
+#include <vcl/virdev.hxx>
+#include <vcl/print.hxx>
+#include <vcl/event.hxx>
+#include <vcl/window.h>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/bmpacc.hxx>
+#include <unotools/fontcvt.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/edit.hxx>
+#include <unotools/fontcfg.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/textlayout.hxx>
+#ifndef _OSL_FILE_H
+#include <osl/file.h>
+#endif
+#ifdef ENABLE_GRAPHITE
+#include <vcl/graphite_features.hxx>
+#endif
+#ifdef USE_BUILTIN_RASTERIZER
+#include <vcl/glyphcache.hxx>
+#endif
+
+#include <vcl/unohelp.hxx>
+#include <pdfwriter_impl.hxx>
+#include <vcl/controllayout.hxx>
+#include <rtl/logfile.hxx>
+
+#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUES_HDL_
+#include <com/sun/star/beans/PropertyValues.hdl>
+#endif
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceManager.hpp>
+
+#if defined UNX
+#define GLYPH_FONT_HEIGHT 128
+#elif defined OS2
+#define GLYPH_FONT_HEIGHT 176
+#else
+#define GLYPH_FONT_HEIGHT 256
+#endif
+
+#include <sal/alloca.h>
+
+#include <cmath>
+#include <cstring>
+
+#include <memory>
+#include <algorithm>
+
+
+// =======================================================================
+
+DBG_NAMEEX( OutputDevice )
+DBG_NAMEEX( Font )
+
+// =======================================================================
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::rtl;
+using namespace ::vcl;
+using namespace ::utl;
+
+// =======================================================================
+
+#define TEXT_DRAW_ELLIPSIS (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
+
+// =======================================================================
+
+#define UNDERLINE_LAST UNDERLINE_BOLDWAVE
+#define STRIKEOUT_LAST STRIKEOUT_X
+
+// =======================================================================
+
+static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
+ int nOrientation )
+{
+ if ( (nOrientation >= 0) && !(nOrientation % 900) )
+ {
+ if ( (nOrientation >= 3600) )
+ nOrientation %= 3600;
+
+ if ( nOrientation )
+ {
+ rX -= nOriginX;
+ rY -= nOriginY;
+
+ if ( nOrientation == 900 )
+ {
+ long nTemp = rX;
+ rX = rY;
+ rY = -nTemp;
+ }
+ else if ( nOrientation == 1800 )
+ {
+ rX = -rX;
+ rY = -rY;
+ }
+ else /* ( nOrientation == 2700 ) */
+ {
+ long nTemp = rX;
+ rX = -rY;
+ rY = nTemp;
+ }
+
+ rX += nOriginX;
+ rY += nOriginY;
+ }
+ }
+ else
+ {
+ double nRealOrientation = nOrientation*F_PI1800;
+ double nCos = cos( nRealOrientation );
+ double nSin = sin( nRealOrientation );
+
+ // Translation...
+ long nX = rX-nOriginX;
+ long nY = rY-nOriginY;
+
+ // Rotation...
+ rX = +((long)(nCos*nX + nSin*nY)) + nOriginX;
+ rY = -((long)(nSin*nX - nCos*nY)) + nOriginY;
+ }
+}
+
+// =======================================================================
+
+void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
+{
+ // the currently selected logical font is no longer needed
+ if ( mpFontEntry )
+ {
+ mpFontCache->Release( mpFontEntry );
+ mpFontEntry = NULL;
+ }
+
+ mbInitFont = true;
+ mbNewFont = true;
+
+ if ( bNewFontLists )
+ {
+ if ( mpGetDevFontList )
+ {
+ delete mpGetDevFontList;
+ mpGetDevFontList = NULL;
+ }
+ if ( mpGetDevSizeList )
+ {
+ delete mpGetDevSizeList;
+ mpGetDevSizeList = NULL;
+ }
+
+ // release all physically selected fonts on this device
+ if( ImplGetGraphics() )
+ mpGraphics->ReleaseFonts();
+ }
+
+ if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
+ mpFontCache->Invalidate();
+
+ if ( bNewFontLists )
+ {
+ // we need a graphics
+ if ( ImplGetGraphics() )
+ {
+ if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
+ mpFontList->Clear();
+
+ if( mpPDFWriter )
+ {
+ if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
+ delete mpFontList;
+ if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
+ delete mpFontCache;
+ mpFontList = mpPDFWriter->filterDevFontList( pSVData->maGDIData.mpScreenFontList );
+ mpFontCache = new ImplFontCache( FALSE );
+ }
+ else
+ {
+ if( mpOutDevData )
+ mpOutDevData->maDevFontSubst.Clear();
+ mpGraphics->GetDevFontList( mpFontList );
+ mpGraphics->GetDevFontSubstList( this );
+ }
+ }
+ }
+ }
+
+ // also update child windows if needed
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->ImplUpdateFontData( true );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // update all windows
+ Window* pFrame = pSVData->maWinData.mpFirstFrame;
+ while ( pFrame )
+ {
+ pFrame->ImplUpdateFontData( bNewFontLists );
+
+ Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pSysWin )
+ {
+ pSysWin->ImplUpdateFontData( bNewFontLists );
+ pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
+ }
+
+ pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+
+ // update all virtual devices
+ VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
+ while ( pVirDev )
+ {
+ pVirDev->ImplUpdateFontData( bNewFontLists );
+ pVirDev = pVirDev->mpNext;
+ }
+
+ // update all printers
+ Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
+ while ( pPrinter )
+ {
+ pPrinter->ImplUpdateFontData( bNewFontLists );
+ pPrinter = pPrinter->mpNext;
+ }
+
+ // clear global font lists to have them updated
+ pSVData->maGDIData.mpScreenFontCache->Invalidate();
+ if ( bNewFontLists )
+ {
+ pSVData->maGDIData.mpScreenFontList->Clear();
+ pFrame = pSVData->maWinData.mpFirstFrame;
+ if ( pFrame )
+ {
+ if ( pFrame->ImplGetGraphics() )
+ // MT: Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler.
+ ((OutputDevice*)pFrame)->mpGraphics->GetDevFontList( pFrame->mpWindowImpl->mpFrameData->mpFontList );
+ }
+ }
+}
+
+// =======================================================================
+
+
+// =======================================================================
+
+// TODO: remove this method when the CWS-gfbfcfg dust has settled
+void ImplFreeOutDevFontData()
+{}
+
+// =======================================================================
+
+void OutputDevice::BeginFontSubstitution()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maGDIData.mbFontSubChanged = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::EndFontSubstitution()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maGDIData.mbFontSubChanged )
+ {
+ ImplUpdateAllFontData( false );
+
+ Application* pApp = GetpApp();
+ DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
+ pApp->DataChanged( aDCEvt );
+ pApp->NotifyAllWindows( aDCEvt );
+ pSVData->maGDIData.mbFontSubChanged = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::AddFontSubstitute( const XubString& rFontName,
+ const XubString& rReplaceFontName,
+ USHORT nFlags )
+{
+ ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
+ if( !rpSubst )
+ rpSubst = new ImplDirectFontSubstitution();
+ rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
+ ImplGetSVData()->maGDIData.mbFontSubChanged = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDirectFontSubstitution::AddFontSubstitute( const String& rFontName,
+ const String& rSubstFontName, USHORT nFlags )
+{
+ maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontSubstEntry::ImplFontSubstEntry( const String& rFontName,
+ const String& rSubstFontName, USHORT nSubstFlags )
+: maName( rFontName )
+, maReplaceName( rSubstFontName )
+, mnFlags( nSubstFlags )
+{
+ maSearchName = rFontName;
+ maSearchReplaceName = rSubstFontName;
+ GetEnglishSearchFontName( maSearchName );
+ GetEnglishSearchFontName( maSearchReplaceName );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplAddDevFontSubstitute( const XubString& rFontName,
+ const XubString& rReplaceFontName,
+ USHORT nFlags )
+{
+ ImplInitOutDevData();
+ mpOutDevData->maDevFontSubst.AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::RemoveFontSubstitute( USHORT n )
+{
+ ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
+ if( pSubst )
+ pSubst->RemoveFontSubstitute( n );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
+{
+ FontSubstList::iterator it = maFontSubstList.begin();
+ for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
+ if( it != maFontSubstList.end() )
+ maFontSubstList.erase( it );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT OutputDevice::GetFontSubstituteCount()
+{
+ const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
+ if( !pSubst )
+ return 0;
+ int nCount = pSubst->GetFontSubstituteCount();
+ return (USHORT)nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::GetFontSubstitute( USHORT n,
+ XubString& rFontName,
+ XubString& rReplaceFontName,
+ USHORT& rFlags )
+{
+ const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
+ if( pSubst )
+ pSubst->GetFontSubstitute( n, rFontName, rReplaceFontName, rFlags );
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplDirectFontSubstitution::GetFontSubstitute( int nIndex,
+ String& rFontName, String& rSubstFontName, USHORT& rFlags ) const
+{
+ FontSubstList::const_iterator it = maFontSubstList.begin();
+ for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
+ if( it == maFontSubstList.end() )
+ return false;
+
+ const ImplFontSubstEntry* pEntry = &(*it);
+ rFontName = pEntry->maName;
+ rSubstFontName = pEntry->maReplaceName;
+ rFlags = pEntry->mnFlags;
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplDirectFontSubstitution::FindFontSubstitute( String& rSubstName,
+ const String& rSearchName, USHORT nFlags ) const
+{
+ // TODO: get rid of O(N) searches
+ FontSubstList::const_iterator it = maFontSubstList.begin();
+ for(; it != maFontSubstList.end(); ++it )
+ {
+ const ImplFontSubstEntry& rEntry = *it;
+ if( ((rEntry.mnFlags & nFlags) || !nFlags)
+ && (rEntry.maSearchName == rSearchName) )
+ {
+ rSubstName = rEntry.maSearchReplaceName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplFontSubstitute( String& rFontName,
+ USHORT nFlags, ImplDirectFontSubstitution* pDevSpecific )
+{
+#ifdef DBG_UTIL
+ String aTempName = rFontName;
+ GetEnglishSearchFontName( aTempName );
+ DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" );
+#endif
+
+ String aSubstFontName;
+
+ // apply user-configurable font replacement (eg, from the list in Tools->Options)
+ const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
+ if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
+ {
+ rFontName = aSubstFontName;
+ return;
+ }
+
+ // apply device specific font replacement (e.g. to use printer builtin fonts)
+ if( !pDevSpecific )
+ return;
+
+ if( pDevSpecific->FindFontSubstitute( aSubstFontName, rFontName, nFlags ) )
+ {
+ rFontName = aSubstFontName;
+ return;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Font OutputDevice::GetDefaultFont( USHORT nType, LanguageType eLang,
+ ULONG nFlags, const OutputDevice* pOutDev )
+{
+ DBG_TRACE( "OutputDevice::GetDefaultFont()" );
+
+ com::sun::star::lang::Locale aLocale;
+ if( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW )
+ {
+ aLocale = Application::GetSettings().GetUILocale();
+ }
+ else
+ {
+ MsLangId::convertLanguageToLocale( eLang, aLocale );
+ }
+
+ utl::DefaultFontConfiguration& rDefaults = *utl::DefaultFontConfiguration::get();
+ String aSearch = rDefaults.getUserInterfaceFont( aLocale ); // ensure a fallback
+ String aDefault = rDefaults.getDefaultFont( aLocale, nType );
+ if( aDefault.Len() )
+ aSearch = aDefault;
+
+ int nDefaultHeight = 12;
+
+ Font aFont;
+ aFont.SetPitch( PITCH_VARIABLE );
+
+ switch ( nType )
+ {
+ case DEFAULTFONT_SANS_UNICODE:
+ case DEFAULTFONT_UI_SANS:
+ aFont.SetFamily( FAMILY_SWISS );
+ break;
+
+ case DEFAULTFONT_SANS:
+ case DEFAULTFONT_LATIN_HEADING:
+ case DEFAULTFONT_LATIN_SPREADSHEET:
+ case DEFAULTFONT_LATIN_DISPLAY:
+ aFont.SetFamily( FAMILY_SWISS );
+ break;
+
+ case DEFAULTFONT_SERIF:
+ case DEFAULTFONT_LATIN_TEXT:
+ case DEFAULTFONT_LATIN_PRESENTATION:
+ aFont.SetFamily( FAMILY_ROMAN );
+ break;
+
+ case DEFAULTFONT_FIXED:
+ case DEFAULTFONT_LATIN_FIXED:
+ case DEFAULTFONT_UI_FIXED:
+ aFont.SetPitch( PITCH_FIXED );
+ aFont.SetFamily( FAMILY_MODERN );
+ break;
+
+ case DEFAULTFONT_SYMBOL:
+ aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
+ break;
+
+ case DEFAULTFONT_CJK_TEXT:
+ case DEFAULTFONT_CJK_PRESENTATION:
+ case DEFAULTFONT_CJK_SPREADSHEET:
+ case DEFAULTFONT_CJK_HEADING:
+ case DEFAULTFONT_CJK_DISPLAY:
+ aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
+ break;
+
+ case DEFAULTFONT_CTL_TEXT:
+ case DEFAULTFONT_CTL_PRESENTATION:
+ case DEFAULTFONT_CTL_SPREADSHEET:
+ case DEFAULTFONT_CTL_HEADING:
+ case DEFAULTFONT_CTL_DISPLAY:
+ aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
+ break;
+ }
+
+ if ( aSearch.Len() )
+ {
+ aFont.SetHeight( nDefaultHeight );
+ aFont.SetWeight( WEIGHT_NORMAL );
+ aFont.SetLanguage( eLang );
+
+ if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
+ aFont.SetCharSet( gsl_getSystemTextEncoding() );
+
+ // Should we only return available fonts on the given device
+ if ( pOutDev )
+ {
+ pOutDev->ImplInitFontList();
+
+ // Search Font in the FontList
+ String aName;
+ String aSearchName;
+ xub_StrLen nIndex = 0;
+ do
+ {
+ aSearchName = GetNextFontToken( aSearch, nIndex );
+ GetEnglishSearchFontName( aSearchName );
+ ImplDevFontListData* pFontFamily = pOutDev->mpFontList->ImplFindBySearchName( aSearchName );
+ if( pFontFamily )
+ {
+ AddTokenFontName( aName, pFontFamily->GetFamilyName() );
+ if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
+ break;
+ }
+ }
+ while ( nIndex != STRING_NOTFOUND );
+ aFont.SetName( aName );
+ }
+
+ // No Name, than set all names
+ if ( !aFont.GetName().Len() )
+ {
+ xub_StrLen nIndex = 0;
+ if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
+ {
+ //aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
+ if( !pOutDev )
+ pOutDev = (const OutputDevice *)ImplGetSVData()->mpDefaultWin;
+ if( !pOutDev )
+ aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
+ else
+ {
+ pOutDev->ImplInitFontList();
+
+ aFont.SetName( aSearch );
+
+ // convert to pixel height
+ Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
+ if ( !aSize.Height() )
+ {
+ // use default pixel height only when logical height is zero
+ if ( aFont.GetHeight() )
+ aSize.Height() = 1;
+ else
+ aSize.Height() = (12*pOutDev->mnDPIY)/72;
+ }
+
+ // use default width only when logical width is zero
+ if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
+ aSize.Width() = 1;
+
+ // get the name of the first available font
+ float fExactHeight = static_cast<float>(aSize.Height());
+ ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontList, aFont, aSize, fExactHeight, pOutDev->mpOutDevData ? &pOutDev->mpOutDevData->maDevFontSubst : NULL );
+ if( pEntry->maFontSelData.mpFontData )
+ aFont.SetName( pEntry->maFontSelData.mpFontData->maName );
+ else
+ aFont.SetName( pEntry->maFontSelData.maTargetName );
+ }
+ }
+ else
+ aFont.SetName( aSearch );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ const char* s = "DEFAULTFONT_SANS_UNKNOWN";
+ switch ( nType )
+ {
+ case DEFAULTFONT_SANS_UNICODE: s = "DEFAULTFONT_SANS_UNICODE"; break;
+ case DEFAULTFONT_UI_SANS: s = "DEFAULTFONT_UI_SANS"; break;
+
+ case DEFAULTFONT_SANS: s = "DEFAULTFONT_SANS"; break;
+ case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
+ case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
+ case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
+
+ case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
+ case DEFAULTFONT_LATIN_TEXT: s = "DEFAULTFONT_LATIN_TEXT"; break;
+ case DEFAULTFONT_LATIN_PRESENTATION: s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
+
+ case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
+ case DEFAULTFONT_LATIN_FIXED: s = "DEFAULTFONT_LATIN_FIXED"; break;
+ case DEFAULTFONT_UI_FIXED: s = "DEFAULTFONT_UI_FIXED"; break;
+
+ case DEFAULTFONT_SYMBOL: s = "DEFAULTFONT_SYMBOL"; break;
+
+ case DEFAULTFONT_CJK_TEXT: s = "DEFAULTFONT_CJK_TEXT"; break;
+ case DEFAULTFONT_CJK_PRESENTATION: s = "DEFAULTFONT_CJK_PRESENTATION"; break;
+ case DEFAULTFONT_CJK_SPREADSHEET: s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
+ case DEFAULTFONT_CJK_HEADING: s = "DEFAULTFONT_CJK_HEADING"; break;
+ case DEFAULTFONT_CJK_DISPLAY: s = "DEFAULTFONT_CJK_DISPLAY"; break;
+
+ case DEFAULTFONT_CTL_TEXT: s = "DEFAULTFONT_CTL_TEXT"; break;
+ case DEFAULTFONT_CTL_PRESENTATION: s = "DEFAULTFONT_CTL_PRESENTATION"; break;
+ case DEFAULTFONT_CTL_SPREADSHEET: s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
+ case DEFAULTFONT_CTL_HEADING: s = "DEFAULTFONT_CTL_HEADING"; break;
+ case DEFAULTFONT_CTL_DISPLAY: s = "DEFAULTFONT_CTL_DISPLAY"; break;
+ }
+ fprintf( stderr, " OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
+ s, eLang, nFlags,
+ OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
+ );
+#endif
+
+ return aFont;
+}
+
+// =======================================================================
+
+static unsigned ImplIsCJKFont( const String& rFontName )
+{
+ // Test, if Fontname includes CJK characters --> In this case we
+ // mention that it is a CJK font
+ const sal_Unicode* pStr = rFontName.GetBuffer();
+ while ( *pStr )
+ {
+ // japanese
+ if ( ((*pStr >= 0x3040) && (*pStr <= 0x30FF)) ||
+ ((*pStr >= 0x3190) && (*pStr <= 0x319F)) )
+ return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
+
+ // korean
+ if ( ((*pStr >= 0xAC00) && (*pStr <= 0xD7AF)) ||
+ ((*pStr >= 0x3130) && (*pStr <= 0x318F)) ||
+ ((*pStr >= 0x1100) && (*pStr <= 0x11FF)) )
+ return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
+
+ // chinese
+ if ( ((*pStr >= 0x3400) && (*pStr <= 0x9FFF)) )
+ return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
+
+ // cjk
+ if ( ((*pStr >= 0x3000) && (*pStr <= 0xD7AF)) ||
+ ((*pStr >= 0xFF00) && (*pStr <= 0xFFEE)) )
+ return IMPL_FONT_ATTR_CJK;
+
+ pStr++;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCalcType( ULONG& rType, FontWeight& rWeight, FontWidth& rWidth,
+ FontFamily eFamily, const FontNameAttr* pFontAttr )
+{
+ if ( eFamily != FAMILY_DONTKNOW )
+ {
+ if ( eFamily == FAMILY_SWISS )
+ rType |= IMPL_FONT_ATTR_SANSSERIF;
+ else if ( eFamily == FAMILY_ROMAN )
+ rType |= IMPL_FONT_ATTR_SERIF;
+ else if ( eFamily == FAMILY_SCRIPT )
+ rType |= IMPL_FONT_ATTR_SCRIPT;
+ else if ( eFamily == FAMILY_MODERN )
+ rType |= IMPL_FONT_ATTR_FIXED;
+ else if ( eFamily == FAMILY_DECORATIVE )
+ rType |= IMPL_FONT_ATTR_DECORATIVE;
+ }
+
+ if ( pFontAttr )
+ {
+ rType |= pFontAttr->Type;
+
+ if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) &&
+ (pFontAttr->Weight != WEIGHT_DONTKNOW) )
+ rWeight = pFontAttr->Weight;
+ if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) &&
+ (pFontAttr->Width != WIDTH_DONTKNOW) )
+ rWidth = pFontAttr->Width;
+ }
+}
+
+// =======================================================================
+
+ImplFontData::ImplFontData( const ImplDevFontAttributes& rDFA, int nMagic )
+: ImplDevFontAttributes( rDFA ),
+ mnWidth(0),
+ mnHeight(0),
+ mnMagic( nMagic ),
+ mpNext( NULL )
+{
+ // StarSymbol is a unicode font, but it still deserves the symbol flag
+ if( !mbSymbolFlag )
+ if( 0 == GetFamilyName().CompareIgnoreCaseToAscii( "starsymbol", 10)
+ || 0 == GetFamilyName().CompareIgnoreCaseToAscii( "opensymbol", 10) )
+ mbSymbolFlag = true;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare ImplFontData::CompareIgnoreSize( const ImplFontData& rOther ) const
+{
+ // compare their width, weight, italic and style name
+ if( meWidthType < rOther.meWidthType )
+ return COMPARE_LESS;
+ else if( meWidthType > rOther.meWidthType )
+ return COMPARE_GREATER;
+
+ if( meWeight < rOther.meWeight )
+ return COMPARE_LESS;
+ else if( meWeight > rOther.meWeight )
+ return COMPARE_GREATER;
+
+ if( meItalic < rOther.meItalic )
+ return COMPARE_LESS;
+ else if( meItalic > rOther.meItalic )
+ return COMPARE_GREATER;
+
+ StringCompare eCompare = maName.CompareTo( rOther.maName );
+ return eCompare;
+}
+
+// -----------------------------------------------------------------------
+
+StringCompare ImplFontData::CompareWithSize( const ImplFontData& rOther ) const
+{
+ StringCompare eCompare = CompareIgnoreSize( rOther );
+ if( eCompare != COMPARE_EQUAL )
+ return eCompare;
+
+ if( mnHeight < rOther.mnHeight )
+ return COMPARE_LESS;
+ else if( mnHeight > rOther.mnHeight )
+ return COMPARE_GREATER;
+
+ if( mnWidth < rOther.mnWidth )
+ return COMPARE_LESS;
+ else if( mnWidth > rOther.mnWidth )
+ return COMPARE_GREATER;
+
+ return COMPARE_EQUAL;
+}
+
+// -----------------------------------------------------------------------
+
+struct FontMatchStatus
+{
+public:
+ int mnFaceMatch;
+ int mnHeightMatch;
+ int mnWidthMatch;
+ const xub_Unicode* mpTargetStyleName;
+};
+
+bool ImplFontData::IsBetterMatch( const ImplFontSelectData& rFSD, FontMatchStatus& rStatus ) const
+{
+ int nMatch = 0;
+
+ const String& rFontName = rFSD.maTargetName;
+ if( (rFontName == maName) || rFontName.EqualsIgnoreCaseAscii( maName ) )
+ nMatch += 240000;
+
+ if( rStatus.mpTargetStyleName
+ && maStyleName.EqualsIgnoreCaseAscii( rStatus.mpTargetStyleName ) )
+ nMatch += 120000;
+
+ if( (rFSD.mePitch != PITCH_DONTKNOW) && (rFSD.mePitch == mePitch) )
+ nMatch += 20000;
+
+ // prefer NORMAL font width
+ // TODO: change when the upper layers can tell their width preference
+ if( meWidthType == WIDTH_NORMAL )
+ nMatch += 400;
+ else if( (meWidthType == WIDTH_SEMI_EXPANDED) || (meWidthType == WIDTH_SEMI_CONDENSED) )
+ nMatch += 300;
+
+ if( rFSD.meWeight != WEIGHT_DONTKNOW )
+ {
+ // if not bold prefer light fonts to bold fonts
+ int nReqWeight = (int)rFSD.meWeight;
+ if ( rFSD.meWeight > WEIGHT_MEDIUM )
+ nReqWeight += 100;
+
+ int nGivenWeight = (int)meWeight;
+ if( meWeight > WEIGHT_MEDIUM )
+ nGivenWeight += 100;
+
+ int nWeightDiff = nReqWeight - nGivenWeight;
+
+ if ( nWeightDiff == 0 )
+ nMatch += 1000;
+ else if ( nWeightDiff == +1 || nWeightDiff == -1 )
+ nMatch += 700;
+ else if ( nWeightDiff < +50 && nWeightDiff > -50)
+ nMatch += 200;
+ }
+ else // requested weight == WEIGHT_DONTKNOW
+ {
+ // prefer NORMAL font weight
+ // TODO: change when the upper layers can tell their weight preference
+ if( meWeight == WEIGHT_NORMAL )
+ nMatch += 450;
+ else if( meWeight == WEIGHT_MEDIUM )
+ nMatch += 350;
+ else if( (meWeight == WEIGHT_SEMILIGHT) || (meWeight == WEIGHT_SEMIBOLD) )
+ nMatch += 200;
+ else if( meWeight == WEIGHT_LIGHT )
+ nMatch += 150;
+ }
+
+ if ( rFSD.meItalic == ITALIC_NONE )
+ {
+ if( meItalic == ITALIC_NONE )
+ nMatch += 900;
+ }
+ else
+ {
+ if( rFSD.meItalic == meItalic )
+ nMatch += 900;
+ else if( meItalic != ITALIC_NONE )
+ nMatch += 600;
+ }
+
+ if( mbDevice )
+ nMatch += 1;
+
+ int nHeightMatch = 0;
+ int nWidthMatch = 0;
+
+ if( IsScalable() )
+ {
+ if( rFSD.mnOrientation != 0 )
+ nMatch += 80;
+ else if( rFSD.mnWidth != 0 )
+ nMatch += 25;
+ else
+ nMatch += 5;
+ }
+ else
+ {
+ if( rFSD.mnHeight == mnHeight )
+ {
+ nMatch += 20;
+ if( rFSD.mnWidth == mnWidth )
+ nMatch += 10;
+ }
+ else
+ {
+ // for non-scalable fonts the size difference is very important
+ // prefer the smaller font face because of clipping/overlapping issues
+ int nHeightDiff = (rFSD.mnHeight - mnHeight) * 1000;
+ nHeightMatch = (nHeightDiff >= 0) ? -nHeightDiff : 100+nHeightDiff;
+ if( rFSD.mnHeight )
+ nHeightMatch /= rFSD.mnHeight;
+
+ if( (rFSD.mnWidth != 0) && (mnWidth != 0) && (rFSD.mnWidth != mnWidth) )
+ {
+ int nWidthDiff = (rFSD.mnWidth - mnWidth) * 100;
+ nWidthMatch = (nWidthDiff >= 0) ? -nWidthDiff : +nWidthDiff;
+ }
+ }
+ }
+
+ if( rStatus.mnFaceMatch > nMatch )
+ return false;
+ else if( rStatus.mnFaceMatch < nMatch )
+ {
+ rStatus.mnFaceMatch = nMatch;
+ rStatus.mnHeightMatch = nHeightMatch;
+ rStatus.mnWidthMatch = nWidthMatch;
+ return true;
+ }
+
+ // when two fonts are still competing prefer the
+ // one with the best matching height
+ if( rStatus.mnHeightMatch > nHeightMatch )
+ return false;
+ else if( rStatus.mnHeightMatch < nHeightMatch )
+ {
+ rStatus.mnHeightMatch = nHeightMatch;
+ rStatus.mnWidthMatch = nWidthMatch;
+ return true;
+ }
+
+ if( rStatus.mnWidthMatch > nWidthMatch )
+ return false;
+
+ rStatus.mnWidthMatch = nWidthMatch;
+ return true;
+}
+
+// =======================================================================
+
+ImplFontEntry::ImplFontEntry( const ImplFontSelectData& rFontSelData )
+: maFontSelData( rFontSelData ),
+ maMetric( rFontSelData ),
+ mpConversion( NULL ),
+ mnRefCount( 1 ),
+ mnSetFontFlags( 0 ),
+ mnOwnOrientation( 0 ),
+ mnOrientation( 0 ),
+ mbInit( false ),
+ mpUnicodeFallbackList( NULL )
+{
+ maFontSelData.mpFontEntry = this;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry::~ImplFontEntry()
+{
+ delete mpUnicodeFallbackList;
+}
+
+// -----------------------------------------------------------------------
+
+size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
+{
+ std::hash<sal_UCS4> a;
+ std::hash<int > b;
+ return a(rData.first) ^ b(rData.second);
+}
+
+inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
+{
+ if( !mpUnicodeFallbackList )
+ mpUnicodeFallbackList = new UnicodeFallbackList;
+ (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
+}
+
+// -----------------------------------------------------------------------
+
+inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, String* pFontName ) const
+{
+ if( !mpUnicodeFallbackList )
+ return false;
+
+ UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
+ if( it == mpUnicodeFallbackList->end() )
+ return false;
+
+ *pFontName = (*it).second;
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
+{
+// DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
+ UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
+// DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
+ if( it == mpUnicodeFallbackList->end() )
+ return;
+ if( (*it).second == rFontName )
+ mpUnicodeFallbackList->erase( it );
+}
+
+// =======================================================================
+
+ImplDevFontListData::ImplDevFontListData( const String& rSearchName )
+: mpFirst( NULL ),
+ maSearchName( rSearchName ),
+ mnTypeFaces( 0 ),
+ mnMatchType( 0 ),
+ meMatchWeight( WEIGHT_DONTKNOW ),
+ meMatchWidth( WIDTH_DONTKNOW ),
+ meFamily( FAMILY_DONTKNOW ),
+ mePitch( PITCH_DONTKNOW ),
+ mnMinQuality( -1 )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData::~ImplDevFontListData()
+{
+ // release all physical font faces
+ while( mpFirst )
+ {
+ ImplFontData* pFace = mpFirst;
+ mpFirst = pFace->GetNextFace();
+ delete pFace;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplDevFontListData::AddFontFace( ImplFontData* pNewData )
+{
+ pNewData->mpNext = NULL;
+
+ if( !mpFirst )
+ {
+ maName = pNewData->maName;
+ maMapNames = pNewData->maMapNames;
+ meFamily = pNewData->meFamily;
+ mePitch = pNewData->mePitch;
+ mnMinQuality = pNewData->mnQuality;
+ }
+ else
+ {
+ if( meFamily == FAMILY_DONTKNOW )
+ meFamily = pNewData->meFamily;
+ if( mePitch == PITCH_DONTKNOW )
+ mePitch = pNewData->mePitch;
+ if( mnMinQuality > pNewData->mnQuality )
+ mnMinQuality = pNewData->mnQuality;
+ }
+
+ // set attributes for attribute based font matching
+ if( pNewData->IsScalable() )
+ mnTypeFaces |= IMPL_DEVFONT_SCALABLE;
+
+ if( pNewData->IsSymbolFont() )
+ mnTypeFaces |= IMPL_DEVFONT_SYMBOL;
+ else
+ mnTypeFaces |= IMPL_DEVFONT_NONESYMBOL;
+
+ if( pNewData->meWeight != WEIGHT_DONTKNOW )
+ {
+ if( pNewData->meWeight >= WEIGHT_SEMIBOLD )
+ mnTypeFaces |= IMPL_DEVFONT_BOLD;
+ else if( pNewData->meWeight <= WEIGHT_SEMILIGHT )
+ mnTypeFaces |= IMPL_DEVFONT_LIGHT;
+ else
+ mnTypeFaces |= IMPL_DEVFONT_NORMAL;
+ }
+
+ if( pNewData->meItalic == ITALIC_NONE )
+ mnTypeFaces |= IMPL_DEVFONT_NONEITALIC;
+ else if( (pNewData->meItalic == ITALIC_NORMAL)
+ || (pNewData->meItalic == ITALIC_OBLIQUE) )
+ mnTypeFaces |= IMPL_DEVFONT_ITALIC;
+
+ if( (meMatchWeight == WEIGHT_DONTKNOW)
+ || (meMatchWidth == WIDTH_DONTKNOW)
+ || (mnMatchType == 0) )
+ {
+ // TODO: is it cheaper to calc matching attributes now or on demand?
+ // calc matching attributes if other entries are already initialized
+
+ // MT: Perform05: Do lazy, quite expensive, not needed in start-up!
+ // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
+ // InitMatchData( rFontSubst, maSearchName );
+ // mbMatchData=true; // Somewhere else???
+ }
+
+ // reassign name (sharing saves memory)
+ if( pNewData->maName == maName )
+ pNewData->maName = maName;
+
+ // insert new physical font face into linked list
+ // TODO: get rid of linear search?
+ ImplFontData* pData;
+ ImplFontData** ppHere = &mpFirst;
+ for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext )
+ {
+ StringCompare eComp = pNewData->CompareWithSize( *pData );
+ if( eComp == COMPARE_GREATER )
+ continue;
+ if( eComp == COMPARE_LESS )
+ break;
+
+ // ignore duplicate if its quality is worse
+ if( pNewData->mnQuality < pData->mnQuality )
+ return false;
+
+ // keep the device font if its quality is good enough
+ if( (pNewData->mnQuality == pData->mnQuality)
+ && (pData->mbDevice || !pNewData->mbDevice) )
+ return false;
+
+ // replace existing font face with a better one
+ pNewData->mpNext = pData->mpNext;
+ *ppHere = pNewData;
+ delete pData;
+ return true;
+ }
+
+ // insert into or append to list of physical font faces
+ pNewData->mpNext = pData;
+ *ppHere = pNewData;
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+// get font attributes using the normalized font family name
+void ImplDevFontListData::InitMatchData( const utl::FontSubstConfiguration& rFontSubst,
+ const String& rSearchName )
+{
+ String aShortName;
+ // get font attributes from the decorated font name
+ rFontSubst.getMapName( rSearchName, aShortName, maMatchFamilyName,
+ meMatchWeight, meMatchWidth, mnMatchType );
+ const FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName );
+ // eventually use the stripped name
+ if( !pFontAttr )
+ if( aShortName != rSearchName )
+ pFontAttr = rFontSubst.getSubstInfo( aShortName );
+ ImplCalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr );
+ mnMatchType |= ImplIsCJKFont( maName );
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontData* ImplDevFontListData::FindBestFontFace( const ImplFontSelectData& rFSD ) const
+{
+ if( !mpFirst )
+ return NULL;
+ if( !mpFirst->GetNextFace() )
+ return mpFirst;
+
+ // FontName+StyleName should map to FamilyName+StyleName
+ const String& rSearchName = rFSD.maTargetName;
+ const xub_Unicode* pTargetStyleName = NULL;
+ if( (rSearchName.Len() > maSearchName.Len())
+ && rSearchName.Equals( maSearchName, 0, maSearchName.Len() ) )
+ pTargetStyleName = rSearchName.GetBuffer() + maSearchName.Len() + 1;
+
+ // linear search, TODO: improve?
+ ImplFontData* pFontFace = mpFirst;
+ ImplFontData* pBestFontFace = pFontFace;
+ FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName};
+ for(; pFontFace; pFontFace = pFontFace->GetNextFace() )
+ if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
+ pBestFontFace = pFontFace;
+
+ return pBestFontFace;
+}
+
+// -----------------------------------------------------------------------
+
+// update device font list with unique font faces, with uniqueness
+// meaning different font attributes, but not different fonts sizes
+void ImplDevFontListData::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const
+{
+ ImplFontData* pPrevFace = NULL;
+ for( ImplFontData* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
+ {
+ if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) )
+ rDevFontList.Add( pFace );
+ pPrevFace = pFace;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontListData::GetFontHeights( std::set<int>& rHeights ) const
+{
+ // add all available font heights
+ for( const ImplFontData* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
+ rHeights.insert( pFace->GetHeight() );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontListData::UpdateCloneFontList( ImplDevFontList& rDevFontList,
+ bool bScalable, bool bEmbeddable ) const
+{
+ for( ImplFontData* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
+ {
+ if( bScalable && !pFace->IsScalable() )
+ continue;
+ if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() )
+ continue;
+
+ ImplFontData* pClonedFace = pFace->Clone();
+ rDevFontList.Add( pClonedFace );
+ }
+}
+
+// =======================================================================
+
+ImplDevFontList::ImplDevFontList()
+: mbMatchData( false )
+, mbMapNames( false )
+, mpPreMatchHook( NULL )
+, mpFallbackHook( NULL )
+, mpFallbackList( NULL )
+, mnFallbackCount( -1 )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontList::~ImplDevFontList()
+{
+ Clear();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontList::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
+{
+ mpPreMatchHook = pHook;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontList::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
+{
+ mpFallbackHook = pHook;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontList::Clear()
+{
+ // remove fallback lists
+ delete[] mpFallbackList;
+ mpFallbackList = NULL;
+ mnFallbackCount = -1;
+
+ // clear all entries in the device font list
+ DevFontList::iterator it = maDevFontList.begin();
+ for(; it != maDevFontList.end(); ++it )
+ {
+ ImplDevFontListData* pEntry = (*it).second;
+ delete pEntry;
+ }
+
+ maDevFontList.clear();
+
+ // match data must be recalculated too
+ mbMatchData = false;
+}
+
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontList::InitGenericGlyphFallback( void ) const
+{
+ // normalized family names of fonts suited for glyph fallback
+ // if a font is available related fonts can be ignored
+ // TODO: implement dynamic lists
+ static const char* aGlyphFallbackList[] = {
+ // empty strings separate the names of unrelated fonts
+ "eudc", "",
+ "arialunicodems", "cyberbit", "code2000", "",
+ "andalesansui", "",
+ "starsymbol", "opensymbol", "",
+ "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
+ "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
+ "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
+ "tahoma", "dejavusans", "timesnewroman", "lucidatypewriter", "lucidasans", "nimbussansl", "",
+ "shree", "mangal", "",
+ "raavi", "shruti", "tunga", "",
+ "latha", "gautami", "kartika", "vrinda", "",
+ "shayyalmt", "naskmt", "",
+ "david", "nachlieli", "lucidagrande", "",
+ "norasi", "angsanaupc", "",
+ "khmerossystem", "",
+ "muktinarrow", "",
+ "phetsarathot", "",
+ "padauk", "pinlonmyanmar", "",
+ "iskoolapota", "lklug", "",
+ 0
+ };
+
+ bool bHasEudc = false;
+ int nMaxLevel = 0;
+ int nBestQuality = 0;
+ ImplDevFontListData** pFallbackList = NULL;
+ for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
+ {
+ // advance to next sub-list when end-of-sublist marker
+ if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
+ {
+ if( nBestQuality > 0 )
+ if( ++nMaxLevel >= MAX_FALLBACK )
+ break;
+ if( !ppNames[1] )
+ break;
+ nBestQuality = 0;
+ continue;
+ }
+
+ // test if the glyph fallback candidate font is available and scalable
+ String aTokenName( *ppNames, RTL_TEXTENCODING_UTF8 );
+ ImplDevFontListData* pFallbackFont = FindFontFamily( aTokenName );
+ if( !pFallbackFont )
+ continue;
+ if( !pFallbackFont->IsScalable() )
+ continue;
+
+ // keep the best font of the glyph fallback sub-list
+ if( nBestQuality < pFallbackFont->GetMinQuality() )
+ {
+ nBestQuality = pFallbackFont->GetMinQuality();
+ // store available glyph fallback fonts
+ if( !pFallbackList )
+ pFallbackList = new ImplDevFontListData*[ MAX_FALLBACK ];
+ pFallbackList[ nMaxLevel ] = pFallbackFont;
+ if( !bHasEudc && !nMaxLevel )
+ bHasEudc = !strncmp( *ppNames, "eudc", 5 );
+ }
+ }
+
+ // sort the list of fonts for glyph fallback by quality (highest first)
+ // #i33947# keep the EUDC font at the front of the list
+ // an insertion sort is good enough for this short list
+ const int nSortStart = bHasEudc ? 1 : 0;
+ for( int i = nSortStart+1, j; i < nMaxLevel; ++i )
+ {
+ ImplDevFontListData* pTestFont = pFallbackList[ i ];
+ int nTestQuality = pTestFont->GetMinQuality();
+ for( j = i; --j >= nSortStart; )
+ if( nTestQuality > pFallbackList[j]->GetMinQuality() )
+ pFallbackList[ j+1 ] = pFallbackList[ j ];
+ else
+ break;
+ pFallbackList[ j+1 ] = pTestFont;
+ }
+
+#if defined(HDU_DEBUG)
+ for( int i = 0; i < nMaxLevel; ++i )
+ {
+ ImplDevFontListData* pFont = pFallbackList[ i ];
+ ByteString aFontName( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 );
+ fprintf( stderr, "GlyphFallbackFont[%d] (quality=%05d): \"%s\"\n",
+ i, pFont->GetMinQuality(), aFontName.GetBuffer() );
+ }
+#endif
+
+ mnFallbackCount = nMaxLevel;
+ mpFallbackList = pFallbackList;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( ImplFontSelectData& rFontSelData,
+ rtl::OUString& rMissingCodes, int nFallbackLevel ) const
+{
+ ImplDevFontListData* pFallbackData = NULL;
+
+ // find a matching font candidate for platform specific glyph fallback
+ if( mpFallbackHook )
+ {
+ // check cache for the first matching entry
+ // to avoid calling the expensive fallback hook (#i83491#)
+ sal_UCS4 cChar = 0;
+ bool bCached = true;
+ sal_Int32 nStrIndex = 0;
+ while( nStrIndex < rMissingCodes.getLength() )
+ {
+ cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
+ bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
+ // ignore entries which don't have a fallback
+ if( !bCached || (rFontSelData.maSearchName.Len() != 0) )
+ break;
+ }
+
+ if( bCached )
+ {
+ // there is a matching fallback in the cache
+ // so update rMissingCodes with codepoints not yet resolved by this fallback
+ int nRemainingLength = 0;
+ sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) );
+ String aFontName;
+ while( nStrIndex < rMissingCodes.getLength() )
+ {
+ cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
+ bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
+ if( !bCached || (rFontSelData.maSearchName != aFontName) )
+ pRemainingCodes[ nRemainingLength++ ] = cChar;
+ }
+ rMissingCodes = rtl::OUString( pRemainingCodes, nRemainingLength );
+ }
+ else
+ {
+ rtl::OUString aOldMissingCodes = rMissingCodes;
+ // call the hook to query the best matching glyph fallback font
+ if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
+ // apply outdev3.cxx specific fontname normalization
+ GetEnglishSearchFontName( rFontSelData.maSearchName );
+ else
+ rFontSelData.maSearchName = String();
+
+ // cache the result even if there was no match
+ for(;;)
+ {
+ if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
+ rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
+ if( nStrIndex >= aOldMissingCodes.getLength() )
+ break;
+ cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
+ }
+ if( rFontSelData.maSearchName.Len() != 0 )
+ {
+ // remove cache entries that were still not resolved
+ for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
+ rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
+ }
+ }
+ }
+
+ // find the matching device font
+ if( rFontSelData.maSearchName.Len() != 0 )
+ pFallbackData = FindFontFamily( rFontSelData.maSearchName );
+ }
+
+ // else find a matching font candidate for generic glyph fallback
+ if( !pFallbackData )
+ {
+ // initialize font candidates for generic glyph fallback if needed
+ if( mnFallbackCount < 0 )
+ InitGenericGlyphFallback();
+ // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
+ if( nFallbackLevel < mnFallbackCount )
+ pFallbackData = mpFallbackList[ nFallbackLevel ];
+ }
+
+ return pFallbackData;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontList::Add( ImplFontData* pNewData )
+{
+ int nAliasQuality = pNewData->mnQuality - 100;
+ String aMapNames = pNewData->maMapNames;
+ pNewData->maMapNames = String();
+
+ bool bKeepNewData = false;
+ for( xub_StrLen nMapNameIndex = 0; nMapNameIndex != STRING_NOTFOUND; )
+ {
+ String aSearchName = pNewData->maName;
+ GetEnglishSearchFontName( aSearchName );
+
+ DevFontList::const_iterator it = maDevFontList.find( aSearchName );
+ ImplDevFontListData* pFoundData = NULL;
+ if( it != maDevFontList.end() )
+ pFoundData = (*it).second;
+
+ if( !pFoundData )
+ {
+ pFoundData = new ImplDevFontListData( aSearchName );
+ maDevFontList[ aSearchName ] = pFoundData;
+ }
+
+ bKeepNewData = pFoundData->AddFontFace( pNewData );
+
+ // add font alias if available
+ // a font alias should never win against an original font with similar quality
+ if( aMapNames.Len() >= nMapNameIndex )
+ break;
+ if( bKeepNewData ) // try to recycle obsoleted object
+ pNewData = pNewData->CreateAlias();
+ bKeepNewData = false;
+ pNewData->mnQuality = nAliasQuality;
+ pNewData->maName = GetNextFontToken( aMapNames, nMapNameIndex );
+ }
+
+ if( !bKeepNewData )
+ delete pNewData;
+}
+
+// -----------------------------------------------------------------------
+
+// find the font from the normalized font family name
+ImplDevFontListData* ImplDevFontList::ImplFindBySearchName( const String& rSearchName ) const
+{
+#ifdef DEBUG
+ String aTempName = rSearchName;
+ GetEnglishSearchFontName( aTempName );
+ DBG_ASSERT( aTempName == rSearchName, "ImplDevFontList::ImplFindBySearchName() called with non-normalized name" );
+#endif
+
+ DevFontList::const_iterator it = maDevFontList.find( rSearchName );
+ if( it == maDevFontList.end() )
+ return NULL;
+
+ ImplDevFontListData* pFoundData = (*it).second;
+ return pFoundData;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::ImplFindByAliasName( const String& rSearchName, const String& rShortName ) const
+{
+ // short circuit for impossible font name alias
+ if( !rSearchName.Len() )
+ return NULL;
+
+ // short circuit if no alias names are available
+ if( !mbMapNames )
+ return NULL;
+
+ // use the font's alias names to find the font
+ // TODO: get rid of linear search
+ DevFontList::const_iterator it = maDevFontList.begin();
+ while( it != maDevFontList.end() )
+ {
+ ImplDevFontListData* pData = (*it).second;
+ if( !pData->maMapNames.Len() )
+ continue;
+
+ // if one alias name matches we found a matching font
+ String aTempName;
+ xub_StrLen nIndex = 0;
+ do
+ {
+ aTempName = GetNextFontToken( pData->maMapNames, nIndex );
+ // Test, if the Font name match with one of the mapping names
+ if ( (aTempName == rSearchName) || (aTempName == rShortName) )
+ return pData;
+ }
+ while ( nIndex != STRING_NOTFOUND );
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::FindFontFamily( const String& rFontName ) const
+{
+ // normalize the font fomily name and
+ String aName = rFontName;
+ GetEnglishSearchFontName( aName );
+ ImplDevFontListData* pFound = ImplFindBySearchName( aName );
+ return pFound;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::ImplFindByTokenNames( const String& rTokenStr ) const
+{
+ ImplDevFontListData* pFoundData = NULL;
+
+ // use normalized font name tokens to find the font
+ for( xub_StrLen nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
+ {
+ String aSearchName = GetNextFontToken( rTokenStr, nTokenPos );
+ if( !aSearchName.Len() )
+ continue;
+ GetEnglishSearchFontName( aSearchName );
+ pFoundData = ImplFindBySearchName( aSearchName );
+ if( pFoundData )
+ break;
+ }
+
+ return pFoundData;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
+{
+ ImplDevFontListData* pFoundData = NULL;
+
+ // use the font substitutions suggested by the FontNameAttr to find the font
+ ::std::vector< String >::const_iterator it = rFontAttr.Substitutions.begin();
+ for(; it != rFontAttr.Substitutions.end(); ++it )
+ {
+ String aSearchName( *it );
+ GetEnglishSearchFontName( aSearchName );
+
+ pFoundData = ImplFindBySearchName( aSearchName );
+ if( pFoundData )
+ break;
+ }
+
+ return pFoundData;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDevFontList::InitMatchData() const
+{
+ // short circuit if already done
+ if( mbMatchData )
+ return;
+ mbMatchData = true;
+
+ // calculate MatchData for all entries
+ const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
+
+ DevFontList::const_iterator it = maDevFontList.begin();
+ for(; it != maDevFontList.end(); ++it )
+ {
+ const String& rSearchName = (*it).first;
+ ImplDevFontListData* pEntry = (*it).second;
+
+ pEntry->InitMatchData( rFontSubst, rSearchName );
+ }
+}
+
+//----------------------------------------------------------------------------
+ImplDevFontListData* ImplDevFontList::ImplFindByLocale(com::sun::star::lang::Locale lc) const
+{
+ // get the default font for a specified locale
+ const DefaultFontConfiguration& rDefaults = *DefaultFontConfiguration::get();
+ String aDefault = rDefaults.getUserInterfaceFont( lc );
+ ImplDevFontListData* pFontData = ImplFindByTokenNames( aDefault );
+ if( pFontData )
+ return pFontData;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::ImplFindByAttributes( ULONG nSearchType,
+ FontWeight eSearchWeight, FontWidth eSearchWidth, FontFamily /*eSearchFamily*/,
+ FontItalic eSearchItalic, const String& rSearchFamilyName ) const
+{
+ if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
+ nSearchType |= IMPL_FONT_ATTR_ITALIC;
+
+ // don't bother to match attributes if the attributes aren't worth matching
+ if( !nSearchType
+ && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
+ && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
+ return NULL;
+
+ InitMatchData();
+ ImplDevFontListData* pFoundData = NULL;
+
+ long nTestMatch;
+ long nBestMatch = 40000;
+ ULONG nBestType = 0;
+
+ DevFontList::const_iterator it = maDevFontList.begin();
+ for(; it != maDevFontList.end(); ++it )
+ {
+ ImplDevFontListData* pData = (*it).second;
+
+ // Get all information about the matching font
+ ULONG nMatchType = pData->mnMatchType;
+ FontWeight eMatchWeight= pData->meMatchWeight;
+ FontWidth eMatchWidth = pData->meMatchWidth;
+
+ // Calculate Match Value
+ // 1000000000
+ // 100000000
+ // 10000000 CJK, CTL, None-Latin, Symbol
+ // 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
+ // Titling, Capitals, Outline, Shadow
+ // 100000 Match FamilyName, Serif, SansSerif, Italic,
+ // Width, Weight
+ // 10000 Scalable, Standard, Default,
+ // full, Normal, Knownfont,
+ // Otherstyle, +Special, +Decorative,
+ // 1000 Typewriter, Rounded, Gothic, Schollbook
+ // 100
+ nTestMatch = 0;
+
+ // test CJK script attributes
+ if ( nSearchType & IMPL_FONT_ATTR_CJK )
+ {
+ // Matching language
+ if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) )
+ nTestMatch += 10000000*3;
+ if( nMatchType & IMPL_FONT_ATTR_CJK )
+ nTestMatch += 10000000*2;
+ if( nMatchType & IMPL_FONT_ATTR_FULL )
+ nTestMatch += 10000000;
+ }
+ else if ( nMatchType & IMPL_FONT_ATTR_CJK )
+ nTestMatch -= 10000000;
+
+ // test CTL script attributes
+ if( nSearchType & IMPL_FONT_ATTR_CTL )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_CTL )
+ nTestMatch += 10000000*2;
+ if( nMatchType & IMPL_FONT_ATTR_FULL )
+ nTestMatch += 10000000;
+ }
+ else if ( nMatchType & IMPL_FONT_ATTR_CTL )
+ nTestMatch -= 10000000;
+
+ // test LATIN script attributes
+ if( nSearchType & IMPL_FONT_ATTR_NONELATIN )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_NONELATIN )
+ nTestMatch += 10000000*2;
+ if( nMatchType & IMPL_FONT_ATTR_FULL )
+ nTestMatch += 10000000;
+ }
+
+ // test SYMBOL attributes
+ if ( nSearchType & IMPL_FONT_ATTR_SYMBOL )
+ {
+ const String& rSearchName = it->first;
+ // prefer some special known symbol fonts
+ if ( rSearchName.EqualsAscii( "starsymbol" ) )
+ nTestMatch += 10000000*6+(10000*3);
+ else if ( rSearchName.EqualsAscii( "opensymbol" ) )
+ nTestMatch += 10000000*6;
+ else if ( rSearchName.EqualsAscii( "starbats" )
+ || rSearchName.EqualsAscii( "wingdings" )
+ || rSearchName.EqualsAscii( "monotypesorts" )
+ || rSearchName.EqualsAscii( "dingbats" )
+ || rSearchName.EqualsAscii( "zapfdingbats" ) )
+ nTestMatch += 10000000*5;
+ else if ( pData->mnTypeFaces & IMPL_DEVFONT_SYMBOL )
+ nTestMatch += 10000000*4;
+ else
+ {
+ if( nMatchType & IMPL_FONT_ATTR_SYMBOL )
+ nTestMatch += 10000000*2;
+ if( nMatchType & IMPL_FONT_ATTR_FULL )
+ nTestMatch += 10000000;
+ }
+ }
+ else if ( (pData->mnTypeFaces & (IMPL_DEVFONT_SYMBOL | IMPL_DEVFONT_NONESYMBOL)) == IMPL_DEVFONT_SYMBOL )
+ nTestMatch -= 10000000;
+ else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL )
+ nTestMatch -= 10000;
+
+ // match stripped family name
+ if( rSearchFamilyName.Len() && (rSearchFamilyName == pData->maMatchFamilyName) )
+ nTestMatch += 1000000*3;
+
+ // match ALLSCRIPT? attribute
+ if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
+ nTestMatch += 1000000*2;
+ if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT )
+ {
+ if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) )
+ nTestMatch += 1000000*2;
+ if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) )
+ nTestMatch -= 1000000;
+ }
+ }
+ else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
+ nTestMatch -= 1000000;
+
+ // test MONOSPACE+TYPEWRITER attributes
+ if( nSearchType & IMPL_FONT_ATTR_FIXED )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_FIXED )
+ nTestMatch += 1000000*2;
+ // a typewriter attribute is even better
+ if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
+ nTestMatch += 10000*2;
+ }
+ else if( nMatchType & IMPL_FONT_ATTR_FIXED )
+ nTestMatch -= 1000000;
+
+ // test SPECIAL attribute
+ if( nSearchType & IMPL_FONT_ATTR_SPECIAL )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_SPECIAL )
+ nTestMatch += 10000;
+ else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_SERIF )
+ nTestMatch += 1000*2;
+ else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
+ nTestMatch += 1000;
+ }
+ }
+ else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) )
+ nTestMatch -= 1000000;
+
+ // test DECORATIVE attribute
+ if( nSearchType & IMPL_FONT_ATTR_DECORATIVE )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
+ nTestMatch += 10000;
+ else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_SERIF )
+ nTestMatch += 1000*2;
+ else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
+ nTestMatch += 1000;
+ }
+ }
+ else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
+ nTestMatch -= 1000000;
+
+ // test TITLE+CAPITALS attributes
+ if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
+ {
+ if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
+ nTestMatch += 1000000*2;
+ if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)))
+ nTestMatch += 1000000;
+ else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))
+ && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
+ nTestMatch += 1000000;
+ }
+ else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
+ nTestMatch -= 1000000;
+
+ // test OUTLINE+SHADOW attributes
+ if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
+ {
+ if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
+ nTestMatch += 1000000*2;
+ if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) )
+ nTestMatch += 1000000;
+ else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW))
+ && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
+ nTestMatch += 1000000;
+ }
+ else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
+ nTestMatch -= 1000000;
+
+ // test font name substrings
+ // TODO: calculate name matching score using e.g. Levenstein distance
+ if( (rSearchFamilyName.Len() >= 4) && (pData->maMatchFamilyName.Len() >= 4)
+ && ((rSearchFamilyName.Search( pData->maMatchFamilyName ) != STRING_NOTFOUND)
+ || (pData->maMatchFamilyName.Search( rSearchFamilyName ) != STRING_NOTFOUND)) )
+ nTestMatch += 5000;
+
+ // test SERIF attribute
+ if( nSearchType & IMPL_FONT_ATTR_SERIF )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_SERIF )
+ nTestMatch += 1000000*2;
+ else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
+ nTestMatch -= 1000000;
+ }
+
+ // test SANSERIF attribute
+ if( nSearchType & IMPL_FONT_ATTR_SANSSERIF )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
+ nTestMatch += 1000000;
+ else if ( nMatchType & IMPL_FONT_ATTR_SERIF )
+ nTestMatch -= 1000000;
+ }
+
+ // test ITALIC attribute
+ if( nSearchType & IMPL_FONT_ATTR_ITALIC )
+ {
+ if( pData->mnTypeFaces & IMPL_DEVFONT_ITALIC )
+ nTestMatch += 1000000*3;
+ if( nMatchType & IMPL_FONT_ATTR_ITALIC )
+ nTestMatch += 1000000;
+ }
+ else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT)
+ && ((nMatchType & IMPL_FONT_ATTR_ITALIC)
+ || !(pData->mnTypeFaces & IMPL_DEVFONT_NONEITALIC)) )
+ nTestMatch -= 1000000*2;
+
+ // test WIDTH attribute
+ if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
+ {
+ if( eSearchWidth < WIDTH_NORMAL )
+ {
+ if( eSearchWidth == eMatchWidth )
+ nTestMatch += 1000000*3;
+ else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
+ nTestMatch += 1000000;
+ }
+ else
+ {
+ if( eSearchWidth == eMatchWidth )
+ nTestMatch += 1000000*3;
+ else if( eMatchWidth > WIDTH_NORMAL )
+ nTestMatch += 1000000;
+ }
+ }
+ else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
+ nTestMatch -= 1000000;
+
+ // test WEIGHT attribute
+ if( (eSearchWeight != WEIGHT_DONTKNOW) && (eSearchWeight != WEIGHT_NORMAL) && (eSearchWeight != WEIGHT_MEDIUM) )
+ {
+ if( eSearchWeight < WEIGHT_NORMAL )
+ {
+ if( pData->mnTypeFaces & IMPL_DEVFONT_LIGHT )
+ nTestMatch += 1000000;
+ if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
+ nTestMatch += 1000000;
+ }
+ else
+ {
+ if( pData->mnTypeFaces & IMPL_DEVFONT_BOLD )
+ nTestMatch += 1000000;
+ if( eMatchWeight > WEIGHT_BOLD )
+ nTestMatch += 1000000;
+ }
+ }
+ else if( ((eMatchWeight != WEIGHT_DONTKNOW) && (eMatchWeight != WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_MEDIUM))
+ || !(pData->mnTypeFaces & IMPL_DEVFONT_NORMAL) )
+ nTestMatch -= 1000000;
+
+ // prefer scalable fonts
+ if( pData->mnTypeFaces & IMPL_DEVFONT_SCALABLE )
+ nTestMatch += 10000*4;
+ else
+ nTestMatch -= 10000*4;
+
+ // test STANDARD+DEFAULT+FULL+NORMAL attributes
+ if( nMatchType & IMPL_FONT_ATTR_STANDARD )
+ nTestMatch += 10000*2;
+ if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
+ nTestMatch += 10000;
+ if( nMatchType & IMPL_FONT_ATTR_FULL )
+ nTestMatch += 10000;
+ if( nMatchType & IMPL_FONT_ATTR_NORMAL )
+ nTestMatch += 10000;
+
+ // test OTHERSTYLE attribute
+ if( nMatchType & IMPL_FONT_ATTR_OTHERSTYLE )
+ {
+ if( !(nMatchType & IMPL_FONT_ATTR_OTHERSTYLE) )
+ nTestMatch -= 10000;
+ }
+ else if( nMatchType & IMPL_FONT_ATTR_OTHERSTYLE )
+ nTestMatch -= 10000;
+
+ // test ROUNDED attribute
+ if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) )
+ nTestMatch += 1000;
+
+ // test TYPEWRITER attribute
+ if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
+ nTestMatch += 1000;
+
+ // test GOTHIC attribute
+ if( nSearchType & IMPL_FONT_ATTR_GOTHIC )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_GOTHIC )
+ nTestMatch += 1000*3;
+ if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
+ nTestMatch += 1000*2;
+ }
+
+ // test SCHOOLBOOK attribute
+ if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK )
+ {
+ if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK )
+ nTestMatch += 1000*3;
+ if( nMatchType & IMPL_FONT_ATTR_SERIF )
+ nTestMatch += 1000*2;
+ }
+
+ // compare with best matching font yet
+ if ( nTestMatch > nBestMatch )
+ {
+ pFoundData = pData;
+ nBestMatch = nTestMatch;
+ nBestType = nMatchType;
+ }
+ else if( nTestMatch == nBestMatch )
+ {
+ // some fonts are more suitable defaults
+ if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
+ {
+ pFoundData = pData;
+ nBestType = nMatchType;
+ }
+ else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) &&
+ !(nBestType & IMPL_FONT_ATTR_DEFAULT) )
+ {
+ pFoundData = pData;
+ nBestType = nMatchType;
+ }
+ }
+ }
+
+ return pFoundData;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::FindDefaultFont() const
+{
+ // try to find one of the default fonts of the
+ // UNICODE, SANSSERIF, SERIF or FIXED default font lists
+ const DefaultFontConfiguration& rDefaults = *DefaultFontConfiguration::get();
+ com::sun::star::lang::Locale aLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
+ String aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS_UNICODE );
+ ImplDevFontListData* pFoundData = ImplFindByTokenNames( aFontname );
+ if( pFoundData )
+ return pFoundData;
+
+ aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS );
+ pFoundData = ImplFindByTokenNames( aFontname );
+ if( pFoundData )
+ return pFoundData;
+
+ aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SERIF );
+ pFoundData = ImplFindByTokenNames( aFontname );
+ if( pFoundData )
+ return pFoundData;
+
+ aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_FIXED );
+ pFoundData = ImplFindByTokenNames( aFontname );
+ if( pFoundData )
+ return pFoundData;
+
+ // now try to find a reasonable non-symbol font
+
+ InitMatchData();
+
+ DevFontList::const_iterator it = maDevFontList.begin();
+ for(; it != maDevFontList.end(); ++it )
+ {
+ ImplDevFontListData* pData = (*it).second;
+ if( pData->mnMatchType & IMPL_FONT_ATTR_SYMBOL )
+ continue;
+ pFoundData = pData;
+ if( pData->mnMatchType & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) )
+ break;
+ }
+ if( pFoundData )
+ return pFoundData;
+
+ // finding any font is better than finding no font at all
+ it = maDevFontList.begin();
+ if( it != maDevFontList.end() )
+ pFoundData = (*it).second;
+
+ return pFoundData;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontList* ImplDevFontList::Clone( bool bScalable, bool bEmbeddable ) const
+{
+ ImplDevFontList* pClonedList = new ImplDevFontList;
+// pClonedList->mbMatchData = mbMatchData;
+ pClonedList->mbMapNames = mbMapNames;
+ pClonedList->mpPreMatchHook = mpPreMatchHook;
+ pClonedList->mpFallbackHook = mpFallbackHook;
+
+ // TODO: clone the config-font attributes too?
+ pClonedList->mbMatchData = false;
+
+ DevFontList::const_iterator it = maDevFontList.begin();
+ for(; it != maDevFontList.end(); ++it )
+ {
+ const ImplDevFontListData* pFontFace = (*it).second;
+ pFontFace->UpdateCloneFontList( *pClonedList, bScalable, bEmbeddable );
+ }
+
+ return pClonedList;
+}
+
+// -----------------------------------------------------------------------
+
+ImplGetDevFontList* ImplDevFontList::GetDevFontList() const
+{
+ ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList;
+
+ DevFontList::const_iterator it = maDevFontList.begin();
+ for(; it != maDevFontList.end(); ++it )
+ {
+ const ImplDevFontListData* pFontFamily = (*it).second;
+ pFontFamily->UpdateDevFontList( *pGetDevFontList );
+ }
+
+ return pGetDevFontList;
+}
+
+// -----------------------------------------------------------------------
+
+ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) const
+{
+ ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName );
+
+ ImplDevFontListData* pFontFamily = FindFontFamily( rFontName );
+ if( pFontFamily != NULL )
+ {
+ std::set<int> rHeights;
+ pFontFamily->GetFontHeights( rHeights );
+
+ std::set<int>::const_iterator it = rHeights.begin();
+ for(; it != rHeights.begin(); ++it )
+ pGetDevSizeList->Add( *it );
+ }
+
+ return pGetDevSizeList;
+}
+
+// =======================================================================
+
+ImplFontSelectData::ImplFontSelectData( const Font& rFont,
+ const String& rSearchName, const Size& rSize, float fExactHeight)
+: maSearchName( rSearchName ),
+ mnWidth( rSize.Width() ),
+ mnHeight( rSize.Height() ),
+ mfExactHeight( fExactHeight),
+ mnOrientation( rFont.GetOrientation() ),
+ meLanguage( rFont.GetLanguage() ),
+ mbVertical( rFont.IsVertical() ),
+ mbNonAntialiased( false ),
+ mpFontData( NULL ),
+ mpFontEntry( NULL )
+{
+ maTargetName = maName;
+
+ rFont.GetFontAttributes( *this );
+
+ // normalize orientation between 0 and 3600
+ if( 3600 <= (unsigned)mnOrientation )
+ {
+ if( mnOrientation >= 0 )
+ mnOrientation %= 3600;
+ else
+ mnOrientation = 3600 - (-mnOrientation % 3600);
+ }
+
+ // normalize width and height
+ if( mnHeight < 0 )
+ mnHeight = -mnHeight;
+ if( mnWidth < 0 )
+ mnWidth = -mnWidth;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontSelectData::ImplFontSelectData( const ImplFontData& rFontData,
+ const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
+: ImplFontAttributes( rFontData ),
+ mnWidth( rSize.Width() ),
+ mnHeight( rSize.Height() ),
+ mfExactHeight( fExactHeight ),
+ mnOrientation( nOrientation ),
+ meLanguage( 0 ),
+ mbVertical( bVertical ),
+ mbNonAntialiased( false ),
+ mpFontData( &rFontData ),
+ mpFontEntry( NULL )
+{
+ maTargetName = maSearchName = maName;
+ // NOTE: no normalization for width/height/orientation
+}
+
+// =======================================================================
+
+size_t ImplFontCache::IFSD_Hash::operator()( const ImplFontSelectData& rFSD ) const
+{
+ // TODO: does it pay off to improve this hash function?
+ static FontNameHash aFontNameHash;
+ size_t nHash = aFontNameHash( rFSD.maSearchName );
+#ifdef ENABLE_GRAPHITE
+ // check for features and generate a unique hash if necessary
+ if (rFSD.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
+ != STRING_NOTFOUND)
+ {
+ nHash = aFontNameHash( rFSD.maTargetName );
+ }
+#endif
+ nHash += 11 * rFSD.mnHeight;
+ nHash += 19 * rFSD.meWeight;
+ nHash += 29 * rFSD.meItalic;
+ nHash += 37 * rFSD.mnOrientation;
+ nHash += 41 * rFSD.meLanguage;
+ if( rFSD.mbVertical )
+ nHash += 53;
+ return nHash;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplFontCache::IFSD_Equal::operator()(const ImplFontSelectData& rA, const ImplFontSelectData& rB) const
+{
+ // check normalized font family name
+ if( rA.maSearchName != rB.maSearchName )
+ return false;
+
+ // check font transformation
+ if( (rA.mnHeight != rB.mnHeight)
+ || (rA.mnWidth != rB.mnWidth)
+ || (rA.mnOrientation != rB.mnOrientation) )
+ return false;
+
+ // check mapping relevant attributes
+ if( (rA.mbVertical != rB.mbVertical)
+ || (rA.meLanguage != rB.meLanguage) )
+ return false;
+
+ // check font face attributes
+ if( (rA.meWeight != rB.meWeight)
+ || (rA.meItalic != rB.meItalic)
+// || (rA.meFamily != rB.meFamily) // TODO: remove this mostly obsolete member
+ || (rA.mePitch != rB.mePitch) )
+ return false;
+
+ // check style name
+ if( rA.maStyleName != rB.maStyleName)
+ return false;
+
+ // Symbol fonts may recode from one type to another So they are only
+ // safely equivalent for equal targets
+ if (
+ (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
+ (rB.mpFontData && rB.mpFontData->IsSymbolFont())
+ )
+ {
+ if (rA.maTargetName != rB.maTargetName)
+ return false;
+ }
+
+#ifdef ENABLE_GRAPHITE
+ // check for features
+ if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
+ != STRING_NOTFOUND ||
+ rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
+ != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
+ return false;
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontCache::ImplFontCache( bool bPrinter )
+: mpFirstEntry( NULL ),
+ mnRef0Count( 0 ),
+ mbPrinter( bPrinter )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplFontCache::~ImplFontCache()
+{
+ FontInstanceList::iterator it = maFontInstanceList.begin();
+ for(; it != maFontInstanceList.end(); ++it )
+ {
+ ImplFontEntry* pEntry = (*it).second;
+ delete pEntry;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
+ const Font& rFont, const Size& rSize, float fExactHeight, ImplDirectFontSubstitution* pDevSpecific )
+{
+ String aSearchName = rFont.GetName();
+
+ // TODO: also add device specific name caching
+ if( !pDevSpecific )
+ {
+ // check if the requested font name is already known
+ // if it is already known get its normalized search name
+ FontNameList::const_iterator it_name = maFontNameList.find( aSearchName );
+ if( it_name != maFontNameList.end() )
+ if( !(*it_name).second.EqualsAscii( "hg", 0, 2)
+#ifdef ENABLE_GRAPHITE
+ && (aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
+ == STRING_NOTFOUND)
+#endif
+ )
+ aSearchName = (*it_name).second;
+ }
+
+ // initialize internal font request object
+ ImplFontSelectData aFontSelData( rFont, aSearchName, rSize, fExactHeight );
+ return GetFontEntry( pFontList, aFontSelData, pDevSpecific );
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
+ ImplFontSelectData& aFontSelData, ImplDirectFontSubstitution* pDevSpecific )
+{
+ // check if a directly matching logical font instance is already cached,
+ // the most recently used font usually has a hit rate of >50%
+ ImplFontEntry *pEntry = NULL;
+ ImplDevFontListData* pFontFamily = NULL;
+ IFSD_Equal aIFSD_Equal;
+ if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
+ pEntry = mpFirstEntry;
+ else
+ {
+ FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
+ if( it != maFontInstanceList.end() )
+ pEntry = (*it).second;
+ }
+
+ if( !pEntry ) // no direct cache hit
+ {
+ // find the best matching logical font family and update font selector accordingly
+ pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific );
+ DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
+ if( pFontFamily )
+ aFontSelData.maSearchName = pFontFamily->GetSearchName();
+
+ // check if an indirectly matching logical font instance is already cached
+ FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
+ if( it != maFontInstanceList.end() )
+ {
+ // we have an indirect cache hit
+ pEntry = (*it).second;
+ // cache the requested and the selected font names
+ // => next time there is a good chance for a direct cache hit
+ // don't allow the cache to grow too big
+ // TODO: implement some fancy LRU caching?
+ if( maFontNameList.size() >= 4000 )
+ maFontNameList.clear();
+ // TODO: also add device specific name caching
+ if( !pDevSpecific )
+ if( aFontSelData.maName != aFontSelData.maSearchName )
+ maFontNameList[ aFontSelData.maName ] = aFontSelData.maSearchName;
+ }
+ }
+
+ if( pEntry ) // cache hit => use existing font instance
+ {
+ // increase the font instance's reference count
+ if( !pEntry->mnRefCount++ )
+ --mnRef0Count;
+ }
+ else // no cache hit => create a new font instance
+ {
+ // find the best matching physical font face
+ ImplFontData* pFontData = pFontFamily->FindBestFontFace( aFontSelData );
+ aFontSelData.mpFontData = pFontData;
+
+ // create a new logical font instance from this physical font face
+ pEntry = pFontData->CreateFontInstance( aFontSelData );
+
+ // if we found a different symbol font we need a symbol conversion table
+ if( pFontData->IsSymbolFont() )
+ if( aFontSelData.maTargetName != aFontSelData.maSearchName )
+ pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
+
+ // add the new entry to the cache
+ maFontInstanceList[ aFontSelData ] = pEntry;
+ }
+
+ mpFirstEntry = pEntry;
+ return pEntry;
+}
+
+// -----------------------------------------------------------------------
+
+ImplDevFontListData* ImplDevFontList::ImplFindByFont( ImplFontSelectData& rFSD,
+ bool bPrinter, ImplDirectFontSubstitution* pDevSpecific ) const
+{
+ // give up if no fonts are available
+ if( !Count() )
+ return NULL;
+
+ // test if a font in the token list is available
+ // substitute the font if this was requested
+ USHORT nSubstFlags = FONT_SUBSTITUTE_ALWAYS;
+ if ( bPrinter )
+ nSubstFlags |= FONT_SUBSTITUTE_SCREENONLY;
+
+ bool bMultiToken = false;
+ xub_StrLen nTokenPos = 0;
+ String& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
+ for(;;)
+ {
+ rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
+ aSearchName = rFSD.maTargetName;
+
+#ifdef ENABLE_GRAPHITE
+ // Until features are properly supported, they are appended to the
+ // font name, so we need to strip them off so the font is found.
+ xub_StrLen nFeat = aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX);
+ String aOrigName = rFSD.maTargetName;
+ String aBaseFontName(aSearchName, 0, (nFeat != STRING_NOTFOUND)?nFeat:aSearchName.Len());
+ if (nFeat != STRING_NOTFOUND && STRING_NOTFOUND !=
+ aSearchName.Search(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
+ {
+ aSearchName = aBaseFontName;
+ rFSD.maTargetName = aBaseFontName;
+ }
+
+#endif
+
+ GetEnglishSearchFontName( aSearchName );
+ ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
+ // #114999# special emboldening for Ricoh fonts
+ // TODO: smarter check for special cases by using PreMatch infrastructure?
+ if( (rFSD.meWeight > WEIGHT_MEDIUM)
+ && aSearchName.EqualsAscii( "hg", 0, 2) )
+ {
+ String aBoldName;
+ if( aSearchName.EqualsAscii( "hggothicb", 0, 9) )
+ aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hggothice"));
+ else if( aSearchName.EqualsAscii( "hgpgothicb", 0, 10) )
+ aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpgothice"));
+ else if( aSearchName.EqualsAscii( "hgminchol", 0, 9) )
+ aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchob"));
+ else if( aSearchName.EqualsAscii( "hgpminchol", 0, 10) )
+ aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchob"));
+ else if( aSearchName.EqualsAscii( "hgminchob" ) )
+ aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchoe"));
+ else if( aSearchName.EqualsAscii( "hgpminchob" ) )
+ aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchoe"));
+
+ if( aBoldName.Len() && ImplFindBySearchName( aBoldName ) )
+ {
+ // the other font is available => use it
+ aSearchName = aBoldName;
+ // prevent synthetic emboldening of bold version
+ rFSD.meWeight = WEIGHT_DONTKNOW;
+ }
+ }
+
+#ifdef ENABLE_GRAPHITE
+ // restore the features to make the font selection data unique
+ rFSD.maTargetName = aOrigName;
+#endif
+ // check if the current font name token or its substitute is valid
+ ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
+ if( pFoundData )
+ return pFoundData;
+
+ // some systems provide special customization
+ // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
+ // because the system wants to map it to another font first, e.g. "Helvetica"
+#ifdef ENABLE_GRAPHITE
+ // use the target name to search in the prematch hook
+ rFSD.maTargetName = aBaseFontName;
+#endif
+ if( mpPreMatchHook )
+ if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
+ GetEnglishSearchFontName( aSearchName );
+#ifdef ENABLE_GRAPHITE
+ // the prematch hook uses the target name to search, but we now need
+ // to restore the features to make the font selection data unique
+ rFSD.maTargetName = aOrigName;
+#endif
+ pFoundData = ImplFindBySearchName( aSearchName );
+ if( pFoundData )
+ return pFoundData;
+
+ // break after last font name token was checked unsuccessfully
+ if( nTokenPos == STRING_NOTFOUND)
+ break;
+ bMultiToken = true;
+ }
+
+ // if the first font was not available find the next available font in
+ // the semicolon separated list of font names. A font is also considered
+ // available when there is a matching entry in the Tools->Options->Fonts
+ // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
+ // font is available
+ for( nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
+ {
+ if( bMultiToken )
+ {
+ rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
+ aSearchName = rFSD.maTargetName;
+ GetEnglishSearchFontName( aSearchName );
+ }
+ else
+ nTokenPos = STRING_NOTFOUND;
+ if( mpPreMatchHook )
+ if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
+ GetEnglishSearchFontName( aSearchName );
+ ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
+ ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
+ if( pFoundData )
+ return pFoundData;
+ }
+
+ // if no font with a directly matching name is available use the
+ // first font name token and get its attributes to find a replacement
+ if ( bMultiToken )
+ {
+ nTokenPos = 0;
+ rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
+ aSearchName = rFSD.maTargetName;
+ GetEnglishSearchFontName( aSearchName );
+ }
+
+ String aSearchShortName;
+ String aSearchFamilyName;
+ FontWeight eSearchWeight = rFSD.meWeight;
+ FontWidth eSearchWidth = rFSD.meWidthType;
+ ULONG nSearchType = 0;
+ FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
+ eSearchWeight, eSearchWidth, nSearchType );
+
+ // note: the search name was already translated to english (if possible)
+
+ // use the font's shortened name if needed
+ if ( aSearchShortName != aSearchName )
+ {
+ ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchShortName );
+ if( pFoundData )
+ {
+#ifdef UNX
+ /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
+ a korean bitmap font that is not suitable here. Use the font replacement table,
+ that automatically leads to the desired "HG Mincho Light J". Same story for
+ MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
+ static String aMS_Mincho( RTL_CONSTASCII_USTRINGPARAM("msmincho") );
+ static String aMS_Gothic( RTL_CONSTASCII_USTRINGPARAM("msgothic") );
+ if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic))
+ // TODO: add heuristic to only throw out the fake ms* fonts
+#endif
+ {
+ return pFoundData;
+ }
+ }
+ }
+
+ // use font fallback
+ const FontNameAttr* pFontAttr = NULL;
+ if( aSearchName.Len() )
+ {
+ // get fallback info using FontSubstConfiguration and
+ // the target name, it's shortened name and family name in that order
+ const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
+ pFontAttr = rFontSubst.getSubstInfo( aSearchName );
+ if ( !pFontAttr && (aSearchShortName != aSearchName) )
+ pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
+ if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
+ pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
+
+ // try the font substitutions suggested by the fallback info
+ if( pFontAttr )
+ {
+ ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pFontAttr );
+ if( pFoundData )
+ return pFoundData;
+ }
+ }
+
+ // if a target symbol font is not available use a default symbol font
+ if( rFSD.IsSymbolFont() )
+ {
+ com::sun::star::lang::Locale aDefaultLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
+ aSearchName = DefaultFontConfiguration::get()->getDefaultFont( aDefaultLocale, DEFAULTFONT_SYMBOL );
+ ImplDevFontListData* pFoundData = ImplFindByTokenNames( aSearchName );
+ if( pFoundData )
+ return pFoundData;
+ }
+
+ // now try the other font name tokens
+ while( nTokenPos != STRING_NOTFOUND )
+ {
+ rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
+ if( !rFSD.maTargetName.Len() )
+ continue;
+
+ aSearchName = rFSD.maTargetName;
+ GetEnglishSearchFontName( aSearchName );
+
+ String aTempShortName;
+ String aTempFamilyName;
+ ULONG nTempType = 0;
+ FontWeight eTempWeight = rFSD.meWeight;
+ FontWidth eTempWidth = WIDTH_DONTKNOW;
+ FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
+ eTempWeight, eTempWidth, nTempType );
+
+ // use a shortend token name if available
+ if( aTempShortName != aSearchName )
+ {
+ ImplDevFontListData* pFoundData = ImplFindBySearchName( aTempShortName );
+ if( pFoundData )
+ return pFoundData;
+ }
+
+ // use a font name from font fallback list to determine font attributes
+
+ // get fallback info using FontSubstConfiguration and
+ // the target name, it's shortened name and family name in that order
+ const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
+ const FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
+ if ( !pTempFontAttr && (aTempShortName != aSearchName) )
+ pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
+ if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
+ pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
+
+ // try the font substitutions suggested by the fallback info
+ if( pTempFontAttr )
+ {
+ ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr );
+ if( pFoundData )
+ return pFoundData;
+ if( !pFontAttr )
+ pFontAttr = pTempFontAttr;
+ }
+ }
+
+ // if still needed use the alias names of the installed fonts
+ if( mbMapNames )
+ {
+ ImplDevFontListData* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName );
+ if( pFoundData )
+ return pFoundData;
+ }
+
+ // if still needed use the font request's attributes to find a good match
+ switch( rFSD.meLanguage )
+ {
+ case LANGUAGE_CHINESE:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC;
+ break;
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_MACAU:
+ nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC;
+ break;
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR;
+ break;
+ case LANGUAGE_JAPANESE:
+ nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP;
+ break;
+ default:
+ nSearchType |= ImplIsCJKFont( rFSD.maName );
+ if( rFSD.IsSymbolFont() )
+ nSearchType |= IMPL_FONT_ATTR_SYMBOL;
+ break;
+ }
+
+ ImplCalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.meFamily, pFontAttr );
+ ImplDevFontListData* pFoundData = ImplFindByAttributes( nSearchType,
+ eSearchWeight, eSearchWidth, rFSD.meFamily, rFSD.meItalic, aSearchFamilyName );
+
+ if( pFoundData )
+ {
+ // overwrite font selection attributes using info from the typeface flags
+ if( (eSearchWeight >= WEIGHT_BOLD)
+ && (eSearchWeight > rFSD.meWeight)
+ && (pFoundData->mnTypeFaces & IMPL_DEVFONT_BOLD) )
+ rFSD.meWeight = eSearchWeight;
+ else if( (eSearchWeight < WEIGHT_NORMAL)
+ && (eSearchWeight < rFSD.meWeight)
+ && (eSearchWeight != WEIGHT_DONTKNOW)
+ && (pFoundData->mnTypeFaces & IMPL_DEVFONT_LIGHT) )
+ rFSD.meWeight = eSearchWeight;
+
+ if( (nSearchType & IMPL_FONT_ATTR_ITALIC)
+ && ((rFSD.meItalic == ITALIC_DONTKNOW) || (rFSD.meItalic == ITALIC_NONE))
+ && (pFoundData->mnTypeFaces & IMPL_DEVFONT_ITALIC) )
+ rFSD.meItalic = ITALIC_NORMAL;
+ }
+ else
+ {
+ // if still needed fall back to default fonts
+ pFoundData = FindDefaultFont();
+ }
+
+ return pFoundData;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( ImplDevFontList* pFontList,
+ ImplFontSelectData& rFontSelData, int nFallbackLevel, rtl::OUString& rMissingCodes )
+{
+ // get a candidate font for glyph fallback
+ // unless the previously selected font got a device specific substitution
+ // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
+ if( nFallbackLevel >= 1)
+ {
+ ImplDevFontListData* pFallbackData = pFontList->GetGlyphFallbackFont(
+ rFontSelData, rMissingCodes, nFallbackLevel-1 );
+ // escape when there are no font candidates
+ if( !pFallbackData )
+ return NULL;
+ // override the font name
+ rFontSelData.maName = pFallbackData->GetFamilyName();
+ // clear the cached normalized name
+ rFontSelData.maSearchName = String();
+ }
+
+ // get device font without doing device specific substitutions
+ ImplFontEntry* pFallbackFont = GetFontEntry( pFontList, rFontSelData, NULL );
+ return pFallbackFont;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFontCache::Release( ImplFontEntry* pEntry )
+{
+ static const int FONTCACHE_MAX = 50;
+
+ DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
+ if( --pEntry->mnRefCount > 0 )
+ return;
+
+ if( ++mnRef0Count < FONTCACHE_MAX )
+ return;
+
+ // remove unused entries from font instance cache
+ FontInstanceList::iterator it_next = maFontInstanceList.begin();
+ while( it_next != maFontInstanceList.end() )
+ {
+ FontInstanceList::iterator it = it_next++;
+ ImplFontEntry* pFontEntry = (*it).second;
+ if( pFontEntry->mnRefCount > 0 )
+ continue;
+
+ maFontInstanceList.erase( it );
+ delete pFontEntry;
+ --mnRef0Count;
+ DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
+
+ if( mpFirstEntry == pFontEntry )
+ mpFirstEntry = NULL;
+ }
+
+ DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFontCache::Invalidate()
+{
+ // delete unreferenced entries
+ FontInstanceList::iterator it = maFontInstanceList.begin();
+ for(; it != maFontInstanceList.end(); ++it )
+ {
+ ImplFontEntry* pFontEntry = (*it).second;
+ if( pFontEntry->mnRefCount > 0 )
+ continue;
+
+ delete pFontEntry;
+ --mnRef0Count;
+ }
+
+ // #112304# make sure the font cache is really clean
+ mpFirstEntry = NULL;
+ maFontInstanceList.clear();
+
+ DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
+
+#ifdef USE_BUILTIN_RASTERIZER
+ // TODO: eventually move into SalGraphics layer
+ GlyphCache::GetInstance().InvalidateAllGlyphs();
+#endif
+}
+
+// =======================================================================
+
+ImplMultiTextLineInfo::ImplMultiTextLineInfo()
+{
+ mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
+ mnLines = 0;
+ mnSize = MULTITEXTLINEINFO_RESIZE;
+}
+
+
+ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
+{
+ for ( xub_StrLen i = 0; i < mnLines; i++ )
+ delete mpLines[i];
+ delete [] mpLines;
+}
+
+void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
+{
+ if ( mnSize == mnLines )
+ {
+ mnSize += MULTITEXTLINEINFO_RESIZE;
+ PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
+ memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
+ mpLines = pNewLines;
+ }
+
+ mpLines[mnLines] = pLine;
+ mnLines++;
+}
+
+void ImplMultiTextLineInfo::Clear()
+{
+ for ( xub_StrLen i = 0; i < mnLines; i++ )
+ delete mpLines[i];
+ mnLines = 0;
+}
+
+// =======================================================================
+
+FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont )
+{
+ FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
+
+ // If no Position is set, then calculate the default position, which
+ // depends on the language
+ if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
+ {
+ LanguageType eLang = rFont.GetLanguage();
+ // In Chinese Simplified the EmphasisMarks are below/left
+ if ( (eLang == LANGUAGE_CHINESE_SIMPLIFIED) ||
+ (eLang == LANGUAGE_CHINESE_SINGAPORE) )
+ nEmphasisMark |= EMPHASISMARK_POS_BELOW;
+ else
+ {
+ eLang = rFont.GetCJKContextLanguage();
+ // In Chinese Simplified the EmphasisMarks are below/left
+ if ( (eLang == LANGUAGE_CHINESE_SIMPLIFIED) ||
+ (eLang == LANGUAGE_CHINESE_SINGAPORE) )
+ nEmphasisMark |= EMPHASISMARK_POS_BELOW;
+ else
+ nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
+ }
+ }
+
+ return nEmphasisMark;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
+{
+ if ( !rFont.IsVertical() )
+ return FALSE;
+
+ if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
+ || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
+ // the underline is right for Japanese only
+ return TRUE;
+
+ return FALSE;
+}
+
+// =======================================================================
+
+void OutputDevice::ImplInitFontList() const
+{
+ if( ! mpFontList->Count() )
+ {
+ if( mpGraphics || ImplGetGraphics() )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "OutputDevice::ImplInitFontList()" );
+ mpGraphics->GetDevFontList( mpFontList );
+ }
+ }
+}
+
+// =======================================================================
+
+void OutputDevice::ImplInitFont() const
+{
+ DBG_TESTSOLARMUTEX();
+
+ if ( mbInitFont )
+ {
+ if ( meOutDevType != OUTDEV_PRINTER )
+ {
+ // decide if antialiasing is appropriate
+ bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
+ bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
+ mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
+ }
+
+ if( !mpPDFWriter || !mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
+ {
+ // select font in the device layers
+ mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
+ }
+ mbInitFont = false;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplInitTextColor()
+{
+ DBG_TESTSOLARMUTEX();
+
+ if ( mbInitTextColor )
+ {
+ mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
+ mbInitTextColor = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool OutputDevice::ImplNewFont() const
+{
+ DBG_TESTSOLARMUTEX();
+
+ // get correct font list on the PDF writer if necessary
+ if( mpPDFWriter )
+ {
+ const ImplSVData* pSVData = ImplGetSVData();
+ if( mpFontList == pSVData->maGDIData.mpScreenFontList
+ || mpFontCache == pSVData->maGDIData.mpScreenFontCache )
+ const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
+ }
+
+ if ( !mbNewFont )
+ return true;
+
+ // we need a graphics
+ if ( !mpGraphics && !ImplGetGraphics() )
+ return false;
+ SalGraphics* pGraphics = mpGraphics;
+ ImplInitFontList();
+
+ // convert to pixel height
+ // TODO: replace integer based aSize completely with subpixel accurate type
+ float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
+ Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
+ if ( !aSize.Height() )
+ {
+ // use default pixel height only when logical height is zero
+ if ( maFont.GetSize().Height() )
+ aSize.Height() = 1;
+ else
+ aSize.Height() = (12*mnDPIY)/72;
+ fExactHeight = static_cast<float>(aSize.Height());
+ }
+
+ // select the default width only when logical width is zero
+ if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
+ aSize.Width() = 1;
+
+ // get font entry
+ ImplDirectFontSubstitution* pDevSpecificSubst = NULL;
+ if( mpOutDevData )
+ pDevSpecificSubst = &mpOutDevData->maDevFontSubst;
+ ImplFontEntry* pOldEntry = mpFontEntry;
+ mpFontEntry = mpFontCache->GetFontEntry( mpFontList, maFont, aSize, fExactHeight, pDevSpecificSubst );
+ if( pOldEntry )
+ mpFontCache->Release( pOldEntry );
+
+ ImplFontEntry* pFontEntry = mpFontEntry;
+ // mark when lower layers need to get involved
+ mbNewFont = FALSE;
+ if( pFontEntry != pOldEntry )
+ mbInitFont = TRUE;
+
+ // select font when it has not been initialized yet
+ if ( !pFontEntry->mbInit )
+ {
+ ImplInitFont();
+
+ // get metric data from device layers
+ if ( pGraphics )
+ {
+ pFontEntry->mbInit = true;
+
+ pFontEntry->maMetric.mnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
+ if( mpPDFWriter && mpPDFWriter->isBuiltinFont( pFontEntry->maFontSelData.mpFontData ) )
+ mpPDFWriter->getFontMetric( &pFontEntry->maFontSelData, &(pFontEntry->maMetric) );
+ else
+ pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
+
+ pFontEntry->maMetric.ImplInitTextLineSize( this );
+ pFontEntry->maMetric.ImplInitAboveTextLineSize();
+
+ pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
+
+ if( pFontEntry->maFontSelData.mnOrientation
+ && !pFontEntry->maMetric.mnOrientation
+ && (meOutDevType != OUTDEV_PRINTER) )
+ {
+ pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
+ pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
+ }
+ else
+ pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
+ }
+ }
+
+ // enable kerning array if requested
+ if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
+ {
+ // TODO: test if physical font supports kerning and disable if not
+ if( pFontEntry->maMetric.mbKernableFont )
+ mbKerning = true;
+ }
+ else
+ mbKerning = false;
+ if ( maFont.GetKerning() & KERNING_ASIAN )
+ mbKerning = true;
+
+ // calculate EmphasisArea
+ mnEmphasisAscent = 0;
+ mnEmphasisDescent = 0;
+ if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
+ {
+ FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
+ long nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
+ if ( nEmphasisHeight < 1 )
+ nEmphasisHeight = 1;
+ if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
+ mnEmphasisDescent = nEmphasisHeight;
+ else
+ mnEmphasisAscent = nEmphasisHeight;
+ }
+
+ // calculate text offset depending on TextAlignment
+ TextAlign eAlign = maFont.GetAlign();
+ if ( eAlign == ALIGN_BASELINE )
+ {
+ mnTextOffX = 0;
+ mnTextOffY = 0;
+ }
+ else if ( eAlign == ALIGN_TOP )
+ {
+ mnTextOffX = 0;
+ mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
+ if ( pFontEntry->mnOrientation )
+ ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
+ }
+ else // eAlign == ALIGN_BOTTOM
+ {
+ mnTextOffX = 0;
+ mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
+ if ( pFontEntry->mnOrientation )
+ ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
+ }
+
+ mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
+ ((maFont.GetOverline() != UNDERLINE_NONE) && (maFont.GetOverline() != UNDERLINE_DONTKNOW)) ||
+ ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
+ mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() ||
+ (maFont.GetRelief() != RELIEF_NONE);
+
+ // #95414# fix for OLE objects which use scale factors very creatively
+ if( mbMap && !aSize.Width() )
+ {
+ int nOrigWidth = pFontEntry->maMetric.mnWidth;
+ float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
+ fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
+ int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
+ if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
+ {
+ Size aOrigSize = maFont.GetSize();
+ const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
+ mbMap = FALSE;
+ mbNewFont = TRUE;
+ ImplNewFont(); // recurse once using stretched width
+ mbMap = TRUE;
+ const_cast<Font&>(maFont).SetSize( aOrigSize );
+ }
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplGetTextWidth( const SalLayout& rSalLayout ) const
+{
+ long nWidth = rSalLayout.GetTextWidth();
+ nWidth /= rSalLayout.GetUnitsPerPixel();
+ return nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
+ long nX, long nY, long nWidth, long nHeight )
+{
+ short nOrientation = mpFontEntry->mnOrientation;
+ if ( nOrientation )
+ {
+ // Rotate rect without rounding problems for 90 degree rotations
+ if ( !(nOrientation % 900) )
+ {
+ nX -= nBaseX;
+ nY -= nBaseY;
+
+ if ( nOrientation == 900 )
+ {
+ long nTemp = nX;
+ nX = nY;
+ nY = -nTemp;
+ nTemp = nWidth;
+ nWidth = nHeight;
+ nHeight = nTemp;
+ nY -= nHeight;
+ }
+ else if ( nOrientation == 1800 )
+ {
+ nX = -nX;
+ nY = -nY;
+ nX -= nWidth;
+ nY -= nHeight;
+ }
+ else /* ( nOrientation == 2700 ) */
+ {
+ long nTemp = nX;
+ nX = -nY;
+ nY = nTemp;
+ nTemp = nWidth;
+ nWidth = nHeight;
+ nHeight = nTemp;
+ nX -= nWidth;
+ }
+
+ nX += nBaseX;
+ nY += nBaseY;
+ }
+ else
+ {
+ // inflate because polygons are drawn smaller
+ Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
+ Polygon aPoly( aRect );
+ aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
+ ImplDrawPolygon( aPoly );
+ return;
+ }
+ }
+
+ mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
+{
+ const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
+ const Point aBase = rSalLayout.DrawBase();
+ const long nX = aBase.X();
+ const long nY = aBase.Y();
+
+ if ( mbLineColor || mbInitLineColor )
+ {
+ mpGraphics->SetLineColor();
+ mbInitLineColor = TRUE;
+ }
+ mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
+ mbInitFillColor = TRUE;
+
+ ImplDrawTextRect( nX, nY, nX, nY-mpFontEntry->maMetric.mnAscent-mnEmphasisAscent,
+ nWidth,
+ mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
+{
+ Point aPoint = rSalLayout.GetDrawPosition();
+ long nX = aPoint.X();
+ long nY = aPoint.Y();
+
+ long nWidth = rSalLayout.GetTextWidth();
+ long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
+
+ nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
+
+ if ( mpFontEntry->mnOrientation )
+ {
+ long nBaseX = nX, nBaseY = nY;
+ if ( !(mpFontEntry->mnOrientation % 900) )
+ {
+ long nX2 = nX+nWidth;
+ long nY2 = nY+nHeight;
+ ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
+ ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
+ nWidth = nX2-nX;
+ nHeight = nY2-nY;
+ }
+ else
+ {
+ // inflate by +1+1 because polygons are drawn smaller
+ Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
+ Polygon aPoly( aRect );
+ aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
+ return aPoly.GetBoundRect();
+ }
+ }
+
+ return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplInitTextLineSize()
+{
+ mpFontEntry->maMetric.ImplInitTextLineSize( this );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplInitAboveTextLineSize()
+{
+ mpFontEntry->maMetric.ImplInitAboveTextLineSize();
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontMetricData::ImplFontMetricData( const ImplFontSelectData& rFontSelData )
+: ImplFontAttributes( rFontSelData )
+{
+ // initialize the members provided by the font request
+ mnWidth = rFontSelData.mnWidth;
+ mnOrientation = sal::static_int_cast<short>(rFontSelData.mnOrientation);
+
+ // intialize the used font name
+ if( rFontSelData.mpFontData )
+ {
+ maName = rFontSelData.mpFontData->maName;
+ maStyleName= rFontSelData.mpFontData->maStyleName;
+ mbDevice = rFontSelData.mpFontData->mbDevice;
+ mbKernableFont = true;
+ }
+ else
+ {
+ xub_StrLen nTokenPos = 0;
+ maName = GetNextFontToken( rFontSelData.maName, nTokenPos );
+ maStyleName= rFontSelData.maStyleName;
+ mbDevice = false;
+ mbKernableFont = false;
+ }
+
+ // reset metrics that are usually measured for the font instance
+ mnAscent = 0;
+ mnDescent = 0;
+ mnIntLeading = 0;
+ mnExtLeading = 0;
+ mnSlant = 0;
+ mnMinKashida = 0;
+
+ // reset metrics that are usually derived from the measurements
+ mnUnderlineSize = 0;
+ mnUnderlineOffset = 0;
+ mnBUnderlineSize = 0;
+ mnBUnderlineOffset = 0;
+ mnDUnderlineSize = 0;
+ mnDUnderlineOffset1 = 0;
+ mnDUnderlineOffset2 = 0;
+ mnWUnderlineSize = 0;
+ mnWUnderlineOffset = 0;
+ mnAboveUnderlineSize = 0;
+ mnAboveUnderlineOffset = 0;
+ mnAboveBUnderlineSize = 0;
+ mnAboveBUnderlineOffset = 0;
+ mnAboveDUnderlineSize = 0;
+ mnAboveDUnderlineOffset1 = 0;
+ mnAboveDUnderlineOffset2 = 0;
+ mnAboveWUnderlineSize = 0;
+ mnAboveWUnderlineOffset = 0;
+ mnStrikeoutSize = 0;
+ mnStrikeoutOffset = 0;
+ mnBStrikeoutSize = 0;
+ mnBStrikeoutOffset = 0;
+ mnDStrikeoutSize = 0;
+ mnDStrikeoutOffset1 = 0;
+ mnDStrikeoutOffset2 = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
+{
+ long nDescent = mnDescent;
+ if ( nDescent <= 0 )
+ {
+ nDescent = mnAscent / 10;
+ if ( !nDescent )
+ nDescent = 1;
+ }
+
+ // #i55341# for some fonts it is not a good idea to calculate
+ // their text line metrics from the real font descent
+ // => work around this problem just for these fonts
+ if( 3*nDescent > mnAscent )
+ nDescent = mnAscent / 3;
+
+ long nLineHeight = ((nDescent*25)+50) / 100;
+ if ( !nLineHeight )
+ nLineHeight = 1;
+ long nLineHeight2 = nLineHeight / 2;
+ if ( !nLineHeight2 )
+ nLineHeight2 = 1;
+
+ long nBLineHeight = ((nDescent*50)+50) / 100;
+ if ( nBLineHeight == nLineHeight )
+ nBLineHeight++;
+ long nBLineHeight2 = nBLineHeight/2;
+ if ( !nBLineHeight2 )
+ nBLineHeight2 = 1;
+
+ long n2LineHeight = ((nDescent*16)+50) / 100;
+ if ( !n2LineHeight )
+ n2LineHeight = 1;
+ long n2LineDY = n2LineHeight;
+ /* #117909#
+ * add some pixels to minimum double line distance on higher resolution devices
+ */
+ long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150;
+ if ( n2LineDY < nMin2LineDY )
+ n2LineDY = nMin2LineDY;
+ long n2LineDY2 = n2LineDY/2;
+ if ( !n2LineDY2 )
+ n2LineDY2 = 1;
+
+ long nUnderlineOffset = mnDescent/2 + 1;
+ long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
+
+ mnUnderlineSize = nLineHeight;
+ mnUnderlineOffset = nUnderlineOffset - nLineHeight2;
+
+ mnBUnderlineSize = nBLineHeight;
+ mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2;
+
+ mnDUnderlineSize = n2LineHeight;
+ mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight;
+ mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
+
+ long nWCalcSize = mnDescent;
+ if ( nWCalcSize < 6 )
+ {
+ if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
+ mnWUnderlineSize = nWCalcSize;
+ else
+ mnWUnderlineSize = 3;
+ }
+ else
+ mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
+
+ // #109280# the following line assures that wavelnes are never placed below the descent, however
+ // for most fonts the waveline then is drawn into the text, so we better keep the old solution
+ // pFontEntry->maMetric.mnWUnderlineOffset = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
+ mnWUnderlineOffset = nUnderlineOffset;
+
+ mnStrikeoutSize = nLineHeight;
+ mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2;
+
+ mnBStrikeoutSize = nBLineHeight;
+ mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2;
+
+ mnDStrikeoutSize = n2LineHeight;
+ mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
+ mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFontMetricData::ImplInitAboveTextLineSize()
+{
+ long nIntLeading = mnIntLeading;
+ // TODO: assess usage of nLeading below (changed in extleading CWS)
+ // if no leading is available, we assume 15% of the ascent
+ if ( nIntLeading <= 0 )
+ {
+ nIntLeading = mnAscent*15/100;
+ if ( !nIntLeading )
+ nIntLeading = 1;
+ }
+
+ long nLineHeight = ((nIntLeading*25)+50) / 100;
+ if ( !nLineHeight )
+ nLineHeight = 1;
+
+ long nBLineHeight = ((nIntLeading*50)+50) / 100;
+ if ( nBLineHeight == nLineHeight )
+ nBLineHeight++;
+
+ long n2LineHeight = ((nIntLeading*16)+50) / 100;
+ if ( !n2LineHeight )
+ n2LineHeight = 1;
+
+ long nCeiling = -mnAscent;
+
+ mnAboveUnderlineSize = nLineHeight;
+ mnAboveUnderlineOffset = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
+
+ mnAboveBUnderlineSize = nBLineHeight;
+ mnAboveBUnderlineOffset = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
+
+ mnAboveDUnderlineSize = n2LineHeight;
+ mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
+ mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + n2LineHeight + 1) / 2;
+
+ long nWCalcSize = nIntLeading;
+ if ( nWCalcSize < 6 )
+ {
+ if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
+ mnAboveWUnderlineSize = nWCalcSize;
+ else
+ mnAboveWUnderlineSize = 3;
+ }
+ else
+ mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
+
+ mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDrawWavePixel( long nOriginX, long nOriginY,
+ long nCurX, long nCurY,
+ short nOrientation,
+ SalGraphics* pGraphics,
+ OutputDevice* pOutDev,
+ BOOL bDrawPixAsRect,
+
+ long nPixWidth, long nPixHeight )
+{
+ if ( nOrientation )
+ ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
+
+ if ( bDrawPixAsRect )
+ {
+
+ pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
+ }
+ else
+ {
+ pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
+ long nStartX, long nStartY,
+ long nWidth, long nHeight,
+ long nLineWidth, short nOrientation,
+ const Color& rColor )
+{
+ if ( !nHeight )
+ return;
+
+ // Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben
+ if ( (nLineWidth == 1) && (nHeight == 1) )
+ {
+ mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
+ mbInitLineColor = TRUE;
+
+ long nEndX = nStartX+nWidth;
+ long nEndY = nStartY;
+ if ( nOrientation )
+ {
+ ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
+ ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
+ }
+ mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
+
+ }
+ else
+ {
+ long nCurX = nStartX;
+ long nCurY = nStartY;
+ long nDiffX = 2;
+ long nDiffY = nHeight-1;
+ long nCount = nWidth;
+ long nOffY = -1;
+ long nFreq;
+ long i;
+ long nPixWidth;
+ long nPixHeight;
+ BOOL bDrawPixAsRect;
+ // Auf Druckern die Pixel per DrawRect() ausgeben
+ if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
+ {
+ if ( mbLineColor || mbInitLineColor )
+ {
+ mpGraphics->SetLineColor();
+ mbInitLineColor = TRUE;
+ }
+ mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
+ mbInitFillColor = TRUE;
+ bDrawPixAsRect = TRUE;
+ nPixWidth = nLineWidth;
+ nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
+ }
+ else
+ {
+ mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
+ mbInitLineColor = TRUE;
+ nPixWidth = 1;
+ nPixHeight = 1;
+ bDrawPixAsRect = FALSE;
+ }
+
+ if ( !nDiffY )
+ {
+ while ( nWidth )
+ {
+ ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
+ mpGraphics, this,
+ bDrawPixAsRect, nPixWidth, nPixHeight );
+ nCurX++;
+ nWidth--;
+ }
+ }
+ else
+ {
+ nCurY += nDiffY;
+ nFreq = nCount / (nDiffX+nDiffY);
+ while ( nFreq-- )
+ {
+ for( i = nDiffY; i; --i )
+ {
+ ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
+ mpGraphics, this,
+ bDrawPixAsRect, nPixWidth, nPixHeight );
+ nCurX++;
+ nCurY += nOffY;
+ }
+ for( i = nDiffX; i; --i )
+ {
+ ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
+ mpGraphics, this,
+ bDrawPixAsRect, nPixWidth, nPixHeight );
+ nCurX++;
+ }
+ nOffY = -nOffY;
+ }
+ nFreq = nCount % (nDiffX+nDiffY);
+ if ( nFreq )
+ {
+ for( i = nDiffY; i && nFreq; --i, --nFreq )
+ {
+ ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
+ mpGraphics, this,
+ bDrawPixAsRect, nPixWidth, nPixHeight );
+ nCurX++;
+ nCurY += nOffY;
+
+ }
+ for( i = nDiffX; i && nFreq; --i, --nFreq )
+ {
+ ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
+ mpGraphics, this,
+ bDrawPixAsRect, nPixWidth, nPixHeight );
+ nCurX++;
+ }
+ }
+ }
+
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
+ long nX, long nY, long nWidth,
+ FontUnderline eTextLine,
+ Color aColor,
+ BOOL bIsAbove )
+{
+ ImplFontEntry* pFontEntry = mpFontEntry;
+ long nLineHeight;
+ long nLinePos;
+
+ if ( bIsAbove )
+ {
+ nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
+ nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
+ }
+ else
+ {
+ nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
+ nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
+ }
+ if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
+ nLineHeight = 3;
+ long nLineWidth = (mnDPIX/300);
+ if ( !nLineWidth )
+ nLineWidth = 1;
+ if ( eTextLine == UNDERLINE_BOLDWAVE )
+ nLineWidth *= 2;
+ nLinePos += nY - (nLineHeight / 2);
+ long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
+ if ( eTextLine == UNDERLINE_DOUBLEWAVE )
+ {
+ long nOrgLineHeight = nLineHeight;
+ nLineHeight /= 3;
+ if ( nLineHeight < 2 )
+ {
+ if ( nOrgLineHeight > 1 )
+ nLineHeight = 2;
+ else
+ nLineHeight = 1;
+ }
+ long nLineDY = nOrgLineHeight-(nLineHeight*2);
+ if ( nLineDY < nLineWidthHeight )
+ nLineDY = nLineWidthHeight;
+ long nLineDY2 = nLineDY/2;
+ if ( !nLineDY2 )
+ nLineDY2 = 1;
+
+ nLinePos -= nLineWidthHeight-nLineDY2;
+ ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight,
+ nLineWidth, mpFontEntry->mnOrientation, aColor );
+ nLinePos += nLineWidthHeight+nLineDY;
+ ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight,
+ nLineWidth, mpFontEntry->mnOrientation, aColor );
+ }
+ else
+ {
+ nLinePos -= nLineWidthHeight/2;
+ ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight,
+ nLineWidth, mpFontEntry->mnOrientation, aColor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
+ long nX, long nY, long nWidth,
+ FontUnderline eTextLine,
+ Color aColor,
+ BOOL bIsAbove )
+{
+ ImplFontEntry* pFontEntry = mpFontEntry;
+ long nLineHeight = 0;
+ long nLinePos = 0;
+ long nLinePos2 = 0;
+
+ if ( eTextLine > UNDERLINE_LAST )
+ eTextLine = UNDERLINE_SINGLE;
+
+ switch ( eTextLine )
+ {
+ case UNDERLINE_SINGLE:
+ case UNDERLINE_DOTTED:
+ case UNDERLINE_DASH:
+ case UNDERLINE_LONGDASH:
+ case UNDERLINE_DASHDOT:
+ case UNDERLINE_DASHDOTDOT:
+ if ( bIsAbove )
+ {
+ nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
+ nLinePos = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
+ }
+ else
+ {
+ nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
+ nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset;
+ }
+ break;
+ case UNDERLINE_BOLD:
+ case UNDERLINE_BOLDDOTTED:
+ case UNDERLINE_BOLDDASH:
+ case UNDERLINE_BOLDLONGDASH:
+ case UNDERLINE_BOLDDASHDOT:
+ case UNDERLINE_BOLDDASHDOTDOT:
+ if ( bIsAbove )
+ {
+ nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
+ nLinePos = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
+ }
+ else
+ {
+ nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
+ nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset;
+ }
+ break;
+ case UNDERLINE_DOUBLE:
+ if ( bIsAbove )
+ {
+ nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
+ nLinePos = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
+ nLinePos2 = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
+ }
+ else
+ {
+ nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
+ nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
+ nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ( nLineHeight )
+ {
+ if ( mbLineColor || mbInitLineColor )
+ {
+ mpGraphics->SetLineColor();
+ mbInitLineColor = TRUE;
+ }
+ mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
+ mbInitFillColor = TRUE;
+
+ long nLeft = nX;
+
+ switch ( eTextLine )
+ {
+ case UNDERLINE_SINGLE:
+ case UNDERLINE_BOLD:
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
+ break;
+ case UNDERLINE_DOUBLE:
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
+ break;
+ case UNDERLINE_DOTTED:
+ case UNDERLINE_BOLDDOTTED:
+ {
+ long nDotWidth = nLineHeight*mnDPIY;
+ nDotWidth += mnDPIY/2;
+ nDotWidth /= mnDPIY;
+ long nTempWidth = nDotWidth;
+ long nEnd = nLeft+nWidth;
+ while ( nLeft < nEnd )
+ {
+ if ( nLeft+nTempWidth > nEnd )
+ nTempWidth = nEnd-nLeft;
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
+ nLeft += nDotWidth*2;
+ }
+ }
+ break;
+ case UNDERLINE_DASH:
+ case UNDERLINE_LONGDASH:
+ case UNDERLINE_BOLDDASH:
+ case UNDERLINE_BOLDLONGDASH:
+ {
+ long nDotWidth = nLineHeight*mnDPIY;
+ nDotWidth += mnDPIY/2;
+ nDotWidth /= mnDPIY;
+ long nMinDashWidth;
+ long nMinSpaceWidth;
+ long nSpaceWidth;
+ long nDashWidth;
+ if ( (eTextLine == UNDERLINE_LONGDASH) ||
+ (eTextLine == UNDERLINE_BOLDLONGDASH) )
+ {
+ nMinDashWidth = nDotWidth*6;
+ nMinSpaceWidth = nDotWidth*2;
+ nDashWidth = 200;
+ nSpaceWidth = 100;
+ }
+ else
+ {
+ nMinDashWidth = nDotWidth*4;
+ nMinSpaceWidth = (nDotWidth*150)/100;
+ nDashWidth = 100;
+ nSpaceWidth = 50;
+ }
+ nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
+ nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
+ // DashWidth wird gegebenenfalls verbreitert, wenn
+ // die dicke der Linie im Verhaeltnis zur Laenge
+ // zu dick wird
+ if ( nDashWidth < nMinDashWidth )
+ nDashWidth = nMinDashWidth;
+ if ( nSpaceWidth < nMinSpaceWidth )
+ nSpaceWidth = nMinSpaceWidth;
+ long nTempWidth = nDashWidth;
+ long nEnd = nLeft+nWidth;
+ while ( nLeft < nEnd )
+ {
+ if ( nLeft+nTempWidth > nEnd )
+ nTempWidth = nEnd-nLeft;
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
+ nLeft += nDashWidth+nSpaceWidth;
+ }
+ }
+ break;
+ case UNDERLINE_DASHDOT:
+ case UNDERLINE_BOLDDASHDOT:
+ {
+ long nDotWidth = nLineHeight*mnDPIY;
+ nDotWidth += mnDPIY/2;
+ nDotWidth /= mnDPIY;
+ long nDashWidth = ((100*mnDPIX)+1270)/2540;
+ long nMinDashWidth = nDotWidth*4;
+ // DashWidth wird gegebenenfalls verbreitert, wenn
+ // die dicke der Linie im Verhaeltnis zur Laenge
+ // zu dick wird
+ if ( nDashWidth < nMinDashWidth )
+ nDashWidth = nMinDashWidth;
+ long nTempDotWidth = nDotWidth;
+ long nTempDashWidth = nDashWidth;
+ long nEnd = nLeft+nWidth;
+ while ( nLeft < nEnd )
+ {
+ if ( nLeft+nTempDotWidth > nEnd )
+ nTempDotWidth = nEnd-nLeft;
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
+ nLeft += nDotWidth*2;
+ if ( nLeft > nEnd )
+ break;
+ if ( nLeft+nTempDashWidth > nEnd )
+ nTempDashWidth = nEnd-nLeft;
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
+ nLeft += nDashWidth+nDotWidth;
+ }
+ }
+ break;
+ case UNDERLINE_DASHDOTDOT:
+ case UNDERLINE_BOLDDASHDOTDOT:
+ {
+ long nDotWidth = nLineHeight*mnDPIY;
+ nDotWidth += mnDPIY/2;
+ nDotWidth /= mnDPIY;
+ long nDashWidth = ((100*mnDPIX)+1270)/2540;
+ long nMinDashWidth = nDotWidth*4;
+ // DashWidth wird gegebenenfalls verbreitert, wenn
+ // die dicke der Linie im Verhaeltnis zur Laenge
+ // zu dick wird
+ if ( nDashWidth < nMinDashWidth )
+ nDashWidth = nMinDashWidth;
+ long nTempDotWidth = nDotWidth;
+ long nTempDashWidth = nDashWidth;
+ long nEnd = nLeft+nWidth;
+ while ( nLeft < nEnd )
+ {
+ if ( nLeft+nTempDotWidth > nEnd )
+ nTempDotWidth = nEnd-nLeft;
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
+ nLeft += nDotWidth*2;
+ if ( nLeft > nEnd )
+ break;
+ if ( nLeft+nTempDotWidth > nEnd )
+ nTempDotWidth = nEnd-nLeft;
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
+ nLeft += nDotWidth*2;
+ if ( nLeft > nEnd )
+ break;
+ if ( nLeft+nTempDashWidth > nEnd )
+ nTempDashWidth = nEnd-nLeft;
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
+ nLeft += nDashWidth+nDotWidth;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
+ long nX, long nY, long nWidth,
+ FontStrikeout eStrikeout,
+ Color aColor )
+{
+ ImplFontEntry* pFontEntry = mpFontEntry;
+ long nLineHeight = 0;
+ long nLinePos = 0;
+ long nLinePos2 = 0;
+
+ if ( eStrikeout > STRIKEOUT_LAST )
+ eStrikeout = STRIKEOUT_SINGLE;
+
+ switch ( eStrikeout )
+ {
+ case STRIKEOUT_SINGLE:
+ nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
+ nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset;
+ break;
+ case STRIKEOUT_BOLD:
+ nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
+ nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
+ break;
+ case STRIKEOUT_DOUBLE:
+ nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
+ nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
+ nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
+ break;
+ default:
+ break;
+ }
+
+ if ( nLineHeight )
+ {
+ if ( mbLineColor || mbInitLineColor )
+ {
+ mpGraphics->SetLineColor();
+ mbInitLineColor = TRUE;
+ }
+ mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
+ mbInitFillColor = TRUE;
+
+ long nLeft = nX;
+
+ switch ( eStrikeout )
+ {
+ case STRIKEOUT_SINGLE:
+ case STRIKEOUT_BOLD:
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
+ break;
+ case STRIKEOUT_DOUBLE:
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
+ ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
+ long nX, long nY, long nWidth,
+ FontStrikeout eStrikeout,
+ Color aColor )
+{
+ // PDF-export does its own strikeout drawing... why again?
+ if( mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) )
+ return;
+
+ // prepare string for strikeout measurement
+ static char cStrikeoutChar;
+ if ( eStrikeout == STRIKEOUT_SLASH )
+ cStrikeoutChar = '/';
+ else // ( eStrikeout == STRIKEOUT_X )
+ cStrikeoutChar = 'X';
+ static const int nTestStrLen = 4;
+ static const int nMaxStrikeStrLen = 2048;
+ xub_Unicode aChars[ nMaxStrikeStrLen +1]; // +1 for valgrind...
+ for( int i = 0; i < nTestStrLen; ++i)
+ aChars[i] = cStrikeoutChar;
+ const String aStrikeoutTest( aChars, nTestStrLen );
+
+ // calculate approximation of strikeout atom size
+ long nStrikeoutWidth = nWidth;
+ SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
+ if( pLayout )
+ {
+ nStrikeoutWidth = (pLayout->GetTextWidth() +nTestStrLen/2) / (nTestStrLen * pLayout->GetUnitsPerPixel());
+ pLayout->Release();
+ }
+ if( nStrikeoutWidth <= 0 ) // sanity check
+ return;
+
+ // calculate acceptable strikeout length
+ // allow the strikeout to be one pixel larger than the text it strikes out
+ long nMaxWidth = nStrikeoutWidth / 2;
+ if ( nMaxWidth < 2 )
+ nMaxWidth = 2;
+ nMaxWidth += nWidth + 1;
+
+ int nStrikeStrLen = (nMaxWidth + nStrikeoutWidth - 1) / nStrikeoutWidth;
+ // if the text width is smaller than the strikeout text, then do not
+ // strike out at all. This case requires user interaction, e.g. adding
+ // a space to the text
+ if( nStrikeStrLen <= 0 )
+ return;
+ if( nStrikeStrLen > nMaxStrikeStrLen )
+ nStrikeStrLen = nMaxStrikeStrLen;
+
+ // build the strikeout string
+ for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
+ aChars[i] = cStrikeoutChar;
+ const String aStrikeoutText( aChars, xub_StrLen(nStrikeStrLen) );
+
+ if( mpFontEntry->mnOrientation )
+ ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
+
+ // strikeout text has to be left aligned
+ ULONG nOrigTLM = mnTextLayoutMode;
+ mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
+ pLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN );
+ mnTextLayoutMode = nOrigTLM;
+
+ if( !pLayout )
+ return;
+
+ // draw the strikeout text
+ const Color aOldColor = GetTextColor();
+ SetTextColor( aColor );
+ ImplInitTextColor();
+
+ pLayout->DrawBase() = Point( nX+mnTextOffX, nY+mnTextOffY );
+ pLayout->DrawText( *mpGraphics );
+ pLayout->Release();
+
+ SetTextColor( aOldColor );
+ ImplInitTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawTextLine( long nBaseX,
+ long nX, long nY, long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ FontUnderline eOverline,
+ BOOL bUnderlineAbove )
+{
+ if ( !nWidth )
+ return;
+
+ Color aStrikeoutColor = GetTextColor();
+ Color aUnderlineColor = GetTextLineColor();
+ Color aOverlineColor = GetOverlineColor();
+ BOOL bStrikeoutDone = FALSE;
+ BOOL bUnderlineDone = FALSE;
+ BOOL bOverlineDone = FALSE;
+
+ // TODO: fix rotated text
+ if ( IsRTLEnabled() )
+ // --- RTL --- mirror at basex
+ nX = nBaseX - nWidth - (nX - nBaseX - 1);
+
+ if ( !IsTextLineColor() )
+ aUnderlineColor = GetTextColor();
+
+ if ( !IsOverlineColor() )
+ aOverlineColor = GetTextColor();
+
+ if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
+ (eUnderline == UNDERLINE_WAVE) ||
+ (eUnderline == UNDERLINE_DOUBLEWAVE) ||
+ (eUnderline == UNDERLINE_BOLDWAVE) )
+ {
+ ImplDrawWaveTextLine( nBaseX, nY, nX, nY, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
+ bUnderlineDone = TRUE;
+ }
+ if ( (eOverline == UNDERLINE_SMALLWAVE) ||
+ (eOverline == UNDERLINE_WAVE) ||
+ (eOverline == UNDERLINE_DOUBLEWAVE) ||
+ (eOverline == UNDERLINE_BOLDWAVE) )
+ {
+ ImplDrawWaveTextLine( nBaseX, nY, nX, nY, nWidth, eOverline, aOverlineColor, TRUE );
+ bOverlineDone = TRUE;
+ }
+
+ if ( (eStrikeout == STRIKEOUT_SLASH) ||
+ (eStrikeout == STRIKEOUT_X) )
+ {
+ ImplDrawStrikeoutChar( nBaseX, nY, nX, nY, nWidth, eStrikeout, aStrikeoutColor );
+ bStrikeoutDone = TRUE;
+ }
+
+ if ( !bUnderlineDone )
+ ImplDrawStraightTextLine( nBaseX, nY, nX, nY, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
+
+ if ( !bOverlineDone )
+ ImplDrawStraightTextLine( nBaseX, nY, nX, nY, nWidth, eOverline, aOverlineColor, TRUE );
+
+ if ( !bStrikeoutDone )
+ ImplDrawStrikeoutLine( nBaseX, nY, nX, nY, nWidth, eStrikeout, aStrikeoutColor );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
+ FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, BOOL bWordLine, BOOL bUnderlineAbove )
+{
+ if( bWordLine )
+ {
+ Point aPos, aStartPt;
+ sal_Int32 nWidth = 0, nAdvance=0;
+ for( int nStart = 0;;)
+ {
+ sal_GlyphId nGlyphIndex;
+ if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
+ break;
+
+ if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
+ {
+ if( !nWidth )
+ {
+ aStartPt = aPos;//rSalLayout.DrawBase() - (aPos - rSalLayout.DrawOffset());
+ }
+
+ nWidth += nAdvance;
+ }
+ else if( nWidth > 0 )
+ {
+ ImplDrawTextLine( rSalLayout.DrawBase().X(), aStartPt.X(), aStartPt.Y(), nWidth,
+ eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+ nWidth = 0;
+ }
+ }
+
+ if( nWidth > 0 )
+ {
+ ImplDrawTextLine( rSalLayout.DrawBase().X(), aStartPt.X(), aStartPt.Y(), nWidth,
+ eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+ }
+ }
+ else
+ {
+ Point aStartPt = rSalLayout.GetDrawPosition();
+ int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
+ ImplDrawTextLine( rSalLayout.DrawBase().X(), aStartPt.X(), aStartPt.Y(), nWidth,
+ eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
+{
+ long nBaseX = nX;
+ if( /*ImplHasMirroredGraphics() &&*/ IsRTLEnabled() )
+ {
+ // --- RTL ---
+ // add some strange offset
+ nX += 2;
+ // revert the hack that will be done later in ImplDrawTextLine
+ nX = nBaseX - nWidth - (nX - nBaseX - 1);
+ }
+
+ ImplDrawTextLine( nBaseX, nX, nY, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, BOOL& rPolyLine,
+ Rectangle& rRect1, Rectangle& rRect2,
+ long& rYOff, long& rWidth,
+ FontEmphasisMark eEmphasis,
+ long nHeight, short /*nOrient*/ )
+{
+ static const BYTE aAccentPolyFlags[24] =
+ {
+ 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
+ };
+
+ static const long aAccentPos[48] =
+ {
+ 78, 0,
+ 348, 79,
+ 599, 235,
+ 843, 469,
+ 938, 574,
+ 990, 669,
+ 990, 773,
+ 990, 843,
+ 964, 895,
+ 921, 947,
+ 886, 982,
+ 860, 999,
+ 825, 999,
+ 764, 999,
+ 721, 964,
+ 686, 895,
+ 625, 791,
+ 556, 660,
+ 469, 504,
+ 400, 400,
+ 261, 252,
+ 61, 61,
+ 0, 27,
+ 9, 0
+ };
+
+ rWidth = 0;
+ rYOff = 0;
+ rPolyLine = FALSE;
+
+ if ( !nHeight )
+ return;
+
+ FontEmphasisMark nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
+ long nDotSize = 0;
+ switch ( nEmphasisStyle )
+ {
+ case EMPHASISMARK_DOT:
+ // Dot has 55% of the height
+ nDotSize = (nHeight*550)/1000;
+ if ( !nDotSize )
+ nDotSize = 1;
+ if ( nDotSize <= 2 )
+ rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
+ else
+ {
+ long nRad = nDotSize/2;
+ Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
+ rPolyPoly.Insert( aPoly );
+ }
+ rYOff = ((nHeight*250)/1000)/2; // Center to the anthoer EmphasisMarks
+ rWidth = nDotSize;
+ break;
+
+ case EMPHASISMARK_CIRCLE:
+ // Dot has 80% of the height
+ nDotSize = (nHeight*800)/1000;
+ if ( !nDotSize )
+ nDotSize = 1;
+ if ( nDotSize <= 2 )
+ rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
+ else
+ {
+ long nRad = nDotSize/2;
+ Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
+ rPolyPoly.Insert( aPoly );
+ // BorderWidth is 15%
+ long nBorder = (nDotSize*150)/1000;
+ if ( nBorder <= 1 )
+ rPolyLine = TRUE;
+ else
+ {
+ Polygon aPoly2( Point( nRad, nRad ),
+ nRad-nBorder, nRad-nBorder );
+ rPolyPoly.Insert( aPoly2 );
+ }
+ }
+ rWidth = nDotSize;
+ break;
+
+ case EMPHASISMARK_DISC:
+ // Dot has 80% of the height
+ nDotSize = (nHeight*800)/1000;
+ if ( !nDotSize )
+ nDotSize = 1;
+ if ( nDotSize <= 2 )
+ rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
+ else
+ {
+ long nRad = nDotSize/2;
+ Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
+ rPolyPoly.Insert( aPoly );
+ }
+ rWidth = nDotSize;
+ break;
+
+ case EMPHASISMARK_ACCENT:
+ // Dot has 80% of the height
+ nDotSize = (nHeight*800)/1000;
+ if ( !nDotSize )
+ nDotSize = 1;
+ if ( nDotSize <= 2 )
+ {
+ if ( nDotSize == 1 )
+ {
+ rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
+ rWidth = nDotSize;
+ }
+ else
+ {
+ rRect1 = Rectangle( Point(), Size( 1, 1 ) );
+ rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
+ }
+ }
+ else
+ {
+ Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
+ (const Point*)aAccentPos,
+ aAccentPolyFlags );
+ double dScale = ((double)nDotSize)/1000.0;
+ aPoly.Scale( dScale, dScale );
+ Polygon aTemp;
+ aPoly.AdaptiveSubdivide( aTemp );
+ Rectangle aBoundRect = aTemp.GetBoundRect();
+ rWidth = aBoundRect.GetWidth();
+ nDotSize = aBoundRect.GetHeight();
+ rPolyPoly.Insert( aTemp );
+ }
+ break;
+ }
+
+ // calculate position
+ long nOffY = 1+(mnDPIY/300); // one visible pixel space
+ long nSpaceY = nHeight-nDotSize;
+ if ( nSpaceY >= nOffY*2 )
+ rYOff += nOffY;
+ if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
+ rYOff += nDotSize;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
+ const PolyPolygon& rPolyPoly, BOOL bPolyLine,
+ const Rectangle& rRect1, const Rectangle& rRect2 )
+{
+ // TODO: pass nWidth as width of this mark
+ long nWidth = 0;
+
+ if( IsRTLEnabled() )
+ // --- RTL --- mirror at basex
+ nX = nBaseX - nWidth - (nX - nBaseX - 1);
+
+ nX -= mnOutOffX;
+ nY -= mnOutOffY;
+
+ if ( rPolyPoly.Count() )
+ {
+ if ( bPolyLine )
+ {
+ Polygon aPoly = rPolyPoly.GetObject( 0 );
+ aPoly.Move( nX, nY );
+ DrawPolyLine( aPoly );
+ }
+ else
+ {
+ PolyPolygon aPolyPoly = rPolyPoly;
+ aPolyPoly.Move( nX, nY );
+ DrawPolyPolygon( aPolyPoly );
+ }
+ }
+
+ if ( !rRect1.IsEmpty() )
+ {
+ Rectangle aRect( Point( nX+rRect1.Left(),
+ nY+rRect1.Top() ), rRect1.GetSize() );
+ DrawRect( aRect );
+ }
+
+ if ( !rRect2.IsEmpty() )
+ {
+ Rectangle aRect( Point( nX+rRect2.Left(),
+ nY+rRect2.Top() ), rRect2.GetSize() );
+
+ DrawRect( aRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
+{
+ Color aOldColor = GetTextColor();
+ Color aOldLineColor = GetLineColor();
+ Color aOldFillColor = GetFillColor();
+ BOOL bOldMap = mbMap;
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ mpMetaFile = NULL;
+ EnableMapMode( FALSE );
+
+ FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
+ PolyPolygon aPolyPoly;
+ Rectangle aRect1;
+ Rectangle aRect2;
+ long nEmphasisYOff;
+ long nEmphasisWidth;
+ long nEmphasisHeight;
+ BOOL bPolyLine;
+
+ if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
+ nEmphasisHeight = mnEmphasisDescent;
+ else
+ nEmphasisHeight = mnEmphasisAscent;
+
+ ImplGetEmphasisMark( aPolyPoly, bPolyLine,
+ aRect1, aRect2,
+ nEmphasisYOff, nEmphasisWidth,
+ nEmphasisMark,
+ nEmphasisHeight, mpFontEntry->mnOrientation );
+
+ if ( bPolyLine )
+ {
+ SetLineColor( GetTextColor() );
+ SetFillColor();
+ }
+ else
+ {
+ SetLineColor();
+ SetFillColor( GetTextColor() );
+ }
+
+ Point aOffset = Point(0,0);
+
+ if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
+ aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
+ else
+ aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
+
+ long nEmphasisWidth2 = nEmphasisWidth / 2;
+ long nEmphasisHeight2 = nEmphasisHeight / 2;
+ aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
+
+ Point aOutPoint;
+ Rectangle aRectangle;
+ for( int nStart = 0;;)
+ {
+ sal_GlyphId nGlyphIndex;
+ if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aOutPoint, nStart ) )
+ break;
+
+ if( !mpGraphics->GetGlyphBoundRect( nGlyphIndex, aRectangle ) )
+ continue;
+
+ if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
+ {
+ Point aAdjPoint = aOffset;
+ aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
+ if ( mpFontEntry->mnOrientation )
+ ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
+ aOutPoint += aAdjPoint;
+ aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
+ ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
+ aOutPoint.X(), aOutPoint.Y(),
+ aPolyPoly, bPolyLine, aRect1, aRect2 );
+ }
+ }
+
+ SetLineColor( aOldLineColor );
+ SetFillColor( aOldFillColor );
+ EnableMapMode( bOldMap );
+ mpMetaFile = pOldMetaFile;
+}
+
+// -----------------------------------------------------------------------
+
+bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
+{
+ int nX = rSalLayout.DrawBase().X();
+ int nY = rSalLayout.DrawBase().Y();
+
+ Rectangle aBoundRect;
+ rSalLayout.DrawBase() = Point( 0, 0 );
+ rSalLayout.DrawOffset() = Point( 0, 0 );
+ if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
+ {
+ // guess vertical text extents if GetBoundRect failed
+ int nRight = rSalLayout.GetTextWidth();
+ int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
+ long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
+ aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
+ }
+
+ // cache virtual device for rotation
+ if ( !mpOutDevData )
+ ImplInitOutDevData();
+ if ( !mpOutDevData->mpRotateDev )
+ mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
+ VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
+
+ // size it accordingly
+ if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
+ return false;
+
+ Font aFont( GetFont() );
+ aFont.SetOrientation( 0 );
+ aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
+ pVDev->SetFont( aFont );
+ pVDev->SetTextColor( Color( COL_BLACK ) );
+ pVDev->SetTextFillColor();
+ pVDev->ImplNewFont();
+ pVDev->ImplInitFont();
+ pVDev->ImplInitTextColor();
+
+ // draw text into upper left corner
+ rSalLayout.DrawBase() -= aBoundRect.TopLeft();
+ rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
+
+ Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
+ if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
+ return false;
+
+ // calculate rotation offset
+ Polygon aPoly( aBoundRect );
+ aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
+ Point aPoint = aPoly.GetBoundRect().TopLeft();
+ aPoint += Point( nX, nY );
+
+ // mask output with text colored bitmap
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ long nOldOffX = mnOutOffX;
+ long nOldOffY = mnOutOffY;
+ BOOL bOldMap = mbMap;
+
+ mnOutOffX = 0L;
+ mnOutOffY = 0L;
+ mpMetaFile = NULL;
+ EnableMapMode( FALSE );
+
+ DrawMask( aPoint, aBmp, GetTextColor() );
+
+ EnableMapMode( bOldMap );
+ mnOutOffX = nOldOffX;
+ mnOutOffY = nOldOffY;
+ mpMetaFile = pOldMetaFile;
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, BOOL bTextLines )
+{
+ if( mpFontEntry->mnOwnOrientation )
+ if( ImplDrawRotateText( rSalLayout ) )
+ return;
+
+ long nOldX = rSalLayout.DrawBase().X();
+ if( ! (mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) ) )
+ {
+ if( ImplHasMirroredGraphics() )
+ {
+ long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
+ long x = rSalLayout.DrawBase().X();
+ rSalLayout.DrawBase().X() = w - 1 - x;
+ if( !IsRTLEnabled() )
+ {
+ OutputDevice *pOutDevRef = (OutputDevice *)this;
+ // mirror this window back
+ long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
+ rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
+ }
+ }
+ else if( IsRTLEnabled() )
+ {
+ //long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
+ //long x = rSalLayout.DrawBase().X();
+ OutputDevice *pOutDevRef = (OutputDevice *)this;
+ // mirror this window back
+ long devX = pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
+ rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
+ }
+
+ rSalLayout.DrawText( *mpGraphics );
+ }
+
+ rSalLayout.DrawBase().X() = nOldX;
+
+ if( bTextLines )
+ ImplDrawTextLines( rSalLayout,
+ maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
+ maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
+
+ // emphasis marks
+ if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
+ ImplDrawEmphasisMarks( rSalLayout );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
+{
+ Color aOldColor = GetTextColor();
+ Color aOldTextLineColor = GetTextLineColor();
+ Color aOldOverlineColor = GetOverlineColor();
+ FontRelief eRelief = maFont.GetRelief();
+
+ Point aOrigPos = rSalLayout.DrawBase();
+ if ( eRelief != RELIEF_NONE )
+ {
+ Color aReliefColor( COL_LIGHTGRAY );
+ Color aTextColor( aOldColor );
+
+ Color aTextLineColor( aOldTextLineColor );
+ Color aOverlineColor( aOldOverlineColor );
+
+ // we don't have a automatic color, so black is always drawn on white
+ if ( aTextColor.GetColor() == COL_BLACK )
+ aTextColor = Color( COL_WHITE );
+ if ( aTextLineColor.GetColor() == COL_BLACK )
+ aTextLineColor = Color( COL_WHITE );
+ if ( aOverlineColor.GetColor() == COL_BLACK )
+ aOverlineColor = Color( COL_WHITE );
+
+ // relief-color is black for white text, in all other cases
+ // we set this to LightGray
+ if ( aTextColor.GetColor() == COL_WHITE )
+ aReliefColor = Color( COL_BLACK );
+ SetTextLineColor( aReliefColor );
+ SetOverlineColor( aReliefColor );
+ SetTextColor( aReliefColor );
+ ImplInitTextColor();
+
+ // calculate offset - for high resolution printers the offset
+ // should be greater so that the effect is visible
+ long nOff = 1;
+ nOff += mnDPIX/300;
+
+ if ( eRelief == RELIEF_ENGRAVED )
+ nOff = -nOff;
+ rSalLayout.DrawOffset() += Point( nOff, nOff);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawOffset() -= Point( nOff, nOff);
+
+ SetTextLineColor( aTextLineColor );
+ SetOverlineColor( aOverlineColor );
+ SetTextColor( aTextColor );
+ ImplInitTextColor();
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+
+ SetTextLineColor( aOldTextLineColor );
+ SetOverlineColor( aOldOverlineColor );
+
+ if ( aTextColor != aOldColor )
+ {
+ SetTextColor( aOldColor );
+ ImplInitTextColor();
+ }
+ }
+ else
+ {
+ if ( maFont.IsShadow() )
+ {
+ long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
+ if ( maFont.IsOutline() )
+ nOff++;
+ SetTextLineColor();
+ SetOverlineColor();
+ if ( (GetTextColor().GetColor() == COL_BLACK)
+ || (GetTextColor().GetLuminance() < 8) )
+ SetTextColor( Color( COL_LIGHTGRAY ) );
+ else
+ SetTextColor( Color( COL_BLACK ) );
+ ImplInitTextColor();
+ rSalLayout.DrawBase() += Point( nOff, nOff );
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() -= Point( nOff, nOff );
+ SetTextColor( aOldColor );
+ SetTextLineColor( aOldTextLineColor );
+ SetOverlineColor( aOldOverlineColor );
+ ImplInitTextColor();
+
+ if ( !maFont.IsOutline() )
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ }
+
+ if ( maFont.IsOutline() )
+ {
+ rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ rSalLayout.DrawBase() = aOrigPos;
+
+ SetTextColor( Color( COL_WHITE ) );
+ SetTextLineColor( Color( COL_WHITE ) );
+ SetOverlineColor( Color( COL_WHITE ) );
+ ImplInitTextColor();
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+ SetTextColor( aOldColor );
+ SetTextLineColor( aOldTextLineColor );
+ SetOverlineColor( aOldOverlineColor );
+ ImplInitTextColor();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
+{
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
+ if( mbInitTextColor )
+ ImplInitTextColor();
+
+ rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
+
+ if( IsTextFillColor() )
+ ImplDrawTextBackground( rSalLayout );
+
+ if( mbTextSpecial )
+ ImplDrawSpecialText( rSalLayout );
+ else
+ ImplDrawTextDirect( rSalLayout, mbTextLines );
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
+ long nWidth, const XubString& rStr,
+ USHORT nStyle, const ::vcl::ITextLayout& _rLayout )
+{
+ DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
+
+ if ( nWidth <= 0 )
+ nWidth = 1;
+
+ long nMaxLineWidth = 0;
+ rLineInfo.Clear();
+ if ( rStr.Len() && (nWidth > 0) )
+ {
+ ::rtl::OUString aText( rStr );
+ uno::Reference < i18n::XBreakIterator > xBI;
+ // get service provider
+ uno::Reference< lang::XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
+
+ uno::Reference< linguistic2::XHyphenator > xHyph;
+ if( xSMgr.is() )
+ {
+ uno::Reference< linguistic2::XLinguServiceManager> xLinguMgr(xSMgr->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.linguistic2.LinguServiceManager"))),uno::UNO_QUERY);
+ if ( xLinguMgr.is() )
+ {
+ xHyph = xLinguMgr->getHyphenator();
+ }
+ }
+
+ i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, uno::Sequence <beans::PropertyValue>(), 1 );
+ i18n::LineBreakUserOptions aUserOptions;
+
+ xub_StrLen nPos = 0;
+ xub_StrLen nLen = rStr.Len();
+ while ( nPos < nLen )
+ {
+ xub_StrLen nBreakPos = nPos;
+
+ while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) )
+ nBreakPos++;
+
+ long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
+ if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
+ {
+ if ( !xBI.is() )
+ xBI = vcl::unohelper::CreateBreakIterator();
+
+ if ( xBI.is() )
+ {
+ const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILocale());
+ xub_StrLen nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
+ DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
+ //aHyphOptions.hyphenIndex = nSoftBreak;
+ i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
+ nBreakPos = (xub_StrLen)aLBR.breakIndex;
+ if ( nBreakPos <= nPos )
+ nBreakPos = nSoftBreak;
+ if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
+ {
+ // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
+ // die Silbentrennung jagen...
+ // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
+ // nBreakPos ist der Wort-Anfang
+ // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
+ // auf mehr als Zwei Zeilen gebrochen wird...
+ if ( xHyph.is() )
+ {
+ sal_Unicode cAlternateReplChar = 0;
+ sal_Unicode cAlternateExtraChar = 0;
+ i18n::Boundary aBoundary = xBI->getWordBoundary( aText, nBreakPos, rDefLocale, ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True );
+ // sal_uInt16 nWordStart = nBreakPos;
+ // sal_uInt16 nBreakPos_OLD = nBreakPos;
+ sal_uInt16 nWordStart = nPos;
+ sal_uInt16 nWordEnd = (USHORT) aBoundary.endPos;
+ DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
+
+ USHORT nWordLen = nWordEnd - nWordStart;
+ if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
+ {
+ // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
+ // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
+ String aWord( aText, nWordStart, nWordLen );
+ sal_uInt16 nMinTrail = static_cast<sal_uInt16>(nWordEnd-nSoftBreak+1); //+1: Vor dem angeknacksten Buchstaben
+ uno::Reference< linguistic2::XHyphenatedWord > xHyphWord;
+ if (xHyph.is())
+ xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.Len() - nMinTrail, uno::Sequence< beans::PropertyValue >() );
+ if (xHyphWord.is())
+ {
+ sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
+ sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
+
+ if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
+ {
+ if ( !bAlternate )
+ {
+ nBreakPos = nWordStart + _nWordLen;
+ }
+ else
+ {
+ String aAlt( xHyphWord->getHyphenatedWord() );
+
+ // Wir gehen von zwei Faellen aus, die nun
+ // vorliegen koennen:
+ // 1) packen wird zu pak-ken
+ // 2) Schiffahrt wird zu Schiff-fahrt
+ // In Fall 1 muss ein Zeichen ersetzt werden,
+ // in Fall 2 wird ein Zeichen hinzugefuegt.
+ // Die Identifikation wird erschwert durch Worte wie
+ // "Schiffahrtsbrennesseln", da der Hyphenator alle
+ // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
+ // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
+ // Index des AlternativWord auf aWord schliessen.
+
+ // Das ganze geraffel wird durch eine Funktion am
+ // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
+ sal_uInt16 nAltStart = _nWordLen - 1;
+ sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
+ sal_uInt16 nTxtEnd = nTxtStart;
+ sal_uInt16 nAltEnd = nAltStart;
+
+ // Die Bereiche zwischen den nStart und nEnd ist
+ // die Differenz zwischen Alternativ- und OriginalString.
+ while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
+ aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
+ {
+ ++nTxtEnd;
+ ++nAltEnd;
+ }
+
+ // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
+ if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
+ aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
+ {
+ ++nAltEnd;
+ ++nTxtStart;
+ ++nTxtEnd;
+ }
+
+ DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Falsche Annahme!" );
+
+ if ( nTxtEnd > nTxtStart )
+ cAlternateReplChar = aAlt.GetChar( nAltStart );
+ else
+ cAlternateExtraChar = aAlt.GetChar( nAltStart );
+
+ nBreakPos = nWordStart + nTxtStart;
+ if ( cAlternateReplChar )
+ nBreakPos++;
+ }
+ } // if (xHyphWord.is())
+ } // if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
+ } // if ( xHyph.is() )
+ } // if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
+ }
+ nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
+ }
+ else
+ {
+ // fallback to something really simple
+ USHORT nSpacePos = STRING_LEN;
+ long nW = 0;
+ do
+ {
+ nSpacePos = rStr.SearchBackward( sal_Unicode(' '), nSpacePos );
+ if( nSpacePos != STRING_NOTFOUND )
+ {
+ if( nSpacePos > nPos )
+ nSpacePos--;
+ nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
+ }
+ } while( nW > nWidth );
+
+ if( nSpacePos != STRING_NOTFOUND )
+ {
+ nBreakPos = nSpacePos;
+ nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
+ if( nBreakPos < rStr.Len()-1 )
+ nBreakPos++;
+ }
+ }
+ }
+
+ if ( nLineWidth > nMaxLineWidth )
+ nMaxLineWidth = nLineWidth;
+
+ rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
+
+ if ( nBreakPos == nPos )
+ nBreakPos++;
+ nPos = nBreakPos;
+
+ if ( ( rStr.GetChar( nPos ) == _CR ) || ( rStr.GetChar( nPos ) == _LF ) )
+ {
+ nPos++;
+ // CR/LF?
+ if ( ( nPos < nLen ) && ( rStr.GetChar( nPos ) == _LF ) && ( rStr.GetChar( nPos-1 ) == _CR ) )
+ nPos++;
+ }
+ }
+ }
+#ifdef DBG_UTIL
+ for ( USHORT nL = 0; nL < rLineInfo.Count(); nL++ )
+ {
+ ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
+ String aLine( rStr, pLine->GetIndex(), pLine->GetLen() );
+ DBG_ASSERT( aLine.Search( _CR ) == STRING_NOTFOUND, "ImplGetTextLines - Found CR!" );
+ DBG_ASSERT( aLine.Search( _LF ) == STRING_NOTFOUND, "ImplGetTextLines - Found LF!" );
+ }
+#endif
+
+ return nMaxLineWidth;
+}
+
+// =======================================================================
+
+void OutputDevice::SetAntialiasing( USHORT nMode )
+{
+ if ( mnAntialiasing != nMode )
+ {
+ mnAntialiasing = nMode;
+ mbInitFont = TRUE;
+
+ if(mpGraphics)
+ {
+ mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetAntialiasing( nMode );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetFont( const Font& rNewFont )
+{
+ DBG_TRACE( "OutputDevice::SetFont()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rNewFont, Font, NULL );
+
+ Font aFont( rNewFont );
+ aFont.SetLanguage(rNewFont.GetLanguage());
+ if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
+ DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
+ DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
+ {
+ Color aTextColor( aFont.GetColor() );
+
+ if ( mnDrawMode & DRAWMODE_BLACKTEXT )
+ aTextColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITETEXT )
+ aTextColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
+ {
+ const UINT8 cLum = aTextColor.GetLuminance();
+ aTextColor = Color( cLum, cLum, cLum );
+ }
+ else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
+ aTextColor = GetSettings().GetStyleSettings().GetFontColor();
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
+ {
+ aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
+ (aTextColor.GetGreen() >> 1 ) | 0x80,
+ (aTextColor.GetBlue() >> 1 ) | 0x80 );
+ }
+
+ aFont.SetColor( aTextColor );
+
+ BOOL bTransFill = aFont.IsTransparent();
+ if ( !bTransFill )
+ {
+ Color aTextFillColor( aFont.GetFillColor() );
+
+ if ( mnDrawMode & DRAWMODE_BLACKFILL )
+ aTextFillColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITEFILL )
+ aTextFillColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_GRAYFILL )
+ {
+ const UINT8 cLum = aTextFillColor.GetLuminance();
+ aTextFillColor = Color( cLum, cLum, cLum );
+ }
+ else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
+ aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
+ else if ( mnDrawMode & DRAWMODE_NOFILL )
+ {
+ aTextFillColor = Color( COL_TRANSPARENT );
+ bTransFill = TRUE;
+ }
+
+ if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
+ {
+ aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
+ (aTextFillColor.GetGreen() >> 1) | 0x80,
+ (aTextFillColor.GetBlue() >> 1) | 0x80 );
+ }
+
+ aFont.SetFillColor( aTextFillColor );
+ }
+ }
+
+ if ( mpMetaFile )
+ {
+ mpMetaFile->AddAction( new MetaFontAction( aFont ) );
+ // the color and alignment actions don't belong here
+ // TODO: get rid of them without breaking anything...
+ mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
+ mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
+ }
+
+#if (OSL_DEBUG_LEVEL > 2) || defined (HDU_DEBUG)
+ fprintf( stderr, " OutputDevice::SetFont( name=\"%s\", h=%ld)\n",
+ OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ aFont.GetSize().Height() );
+#endif
+
+ if ( !maFont.IsSameInstance( aFont ) )
+ {
+ // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
+ // because SetTextColor() is used for this.
+ // #i28759# maTextColor might have been changed behind our back, commit then, too.
+ if( aFont.GetColor() != COL_TRANSPARENT
+ && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
+ {
+ maTextColor = aFont.GetColor();
+ mbInitTextColor = TRUE;
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
+ }
+ maFont = aFont;
+ mbNewFont = TRUE;
+
+ if( mpAlphaVDev )
+ {
+ // #i30463#
+ // Since SetFont might change the text color, apply that only
+ // selectively to alpha vdev (which normally paints opaque text
+ // with COL_BLACK)
+ if( aFont.GetColor() != COL_TRANSPARENT )
+ {
+ mpAlphaVDev->SetTextColor( COL_BLACK );
+ aFont.SetColor( COL_TRANSPARENT );
+ }
+
+ mpAlphaVDev->SetFont( aFont );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetLayoutMode( ULONG nTextLayoutMode )
+{
+ DBG_TRACE( "OutputDevice::SetTextLayoutMode()" );
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
+
+ mnTextLayoutMode = nTextLayoutMode;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
+{
+ DBG_TRACE( "OutputDevice::SetTextLanguage()" );
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
+
+ meTextLanguage = eTextLanguage;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetDigitLanguage( eTextLanguage );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetTextColor( const Color& rColor )
+{
+ DBG_TRACE( "OutputDevice::SetTextColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor( rColor );
+
+ if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
+ DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
+ DRAWMODE_SETTINGSTEXT ) )
+ {
+ if ( mnDrawMode & DRAWMODE_BLACKTEXT )
+ aColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITETEXT )
+ aColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
+ aColor = GetSettings().GetStyleSettings().GetFontColor();
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
+ {
+ aColor = Color( (aColor.GetRed() >> 1) | 0x80,
+ (aColor.GetGreen() >> 1) | 0x80,
+ (aColor.GetBlue() >> 1) | 0x80 );
+ }
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
+
+ if ( maTextColor != aColor )
+ {
+ maTextColor = aColor;
+ mbInitTextColor = TRUE;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTextColor( COL_BLACK );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetTextFillColor()
+{
+ DBG_TRACE( "OutputDevice::SetTextFillColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), FALSE ) );
+
+ if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
+ maFont.SetFillColor( Color( COL_TRANSPARENT ) );
+ if ( !maFont.IsTransparent() )
+ maFont.SetTransparent( TRUE );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTextFillColor();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetTextFillColor( const Color& rColor )
+{
+ DBG_TRACE( "OutputDevice::SetTextFillColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor( rColor );
+ BOOL bTransFill = ImplIsColorTransparent( aColor ) ? TRUE : FALSE;
+
+ if ( !bTransFill )
+ {
+ if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
+ DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
+ DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
+ {
+ if ( mnDrawMode & DRAWMODE_BLACKFILL )
+ aColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITEFILL )
+ aColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_GRAYFILL )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
+ aColor = GetSettings().GetStyleSettings().GetWindowColor();
+ else if ( mnDrawMode & DRAWMODE_NOFILL )
+ {
+ aColor = Color( COL_TRANSPARENT );
+ bTransFill = TRUE;
+ }
+
+ if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
+ {
+ aColor = Color( (aColor.GetRed() >> 1) | 0x80,
+ (aColor.GetGreen() >> 1) | 0x80,
+ (aColor.GetBlue() >> 1) | 0x80 );
+ }
+ }
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, TRUE ) );
+
+ if ( maFont.GetFillColor() != aColor )
+ maFont.SetFillColor( aColor );
+ if ( maFont.IsTransparent() != bTransFill )
+ maFont.SetTransparent( bTransFill );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTextFillColor( COL_BLACK );
+}
+
+// -----------------------------------------------------------------------
+
+Color OutputDevice::GetTextFillColor() const
+{
+ if ( maFont.IsTransparent() )
+ return Color( COL_TRANSPARENT );
+ else
+ return maFont.GetFillColor();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetTextLineColor()
+{
+ DBG_TRACE( "OutputDevice::SetTextLineColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), FALSE ) );
+
+ maTextLineColor = Color( COL_TRANSPARENT );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTextLineColor();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetTextLineColor( const Color& rColor )
+{
+ DBG_TRACE( "OutputDevice::SetTextLineColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor( rColor );
+
+ if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
+ DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
+ DRAWMODE_SETTINGSTEXT ) )
+ {
+ if ( mnDrawMode & DRAWMODE_BLACKTEXT )
+ aColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITETEXT )
+ aColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
+ aColor = GetSettings().GetStyleSettings().GetFontColor();
+
+ if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
+ && (aColor.GetColor() != COL_TRANSPARENT) )
+ {
+ aColor = Color( (aColor.GetRed() >> 1) | 0x80,
+ (aColor.GetGreen() >> 1) | 0x80,
+ (aColor.GetBlue() >> 1) | 0x80 );
+ }
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, TRUE ) );
+
+ maTextLineColor = aColor;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTextLineColor( COL_BLACK );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetOverlineColor()
+{
+ DBG_TRACE( "OutputDevice::SetOverlineColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), FALSE ) );
+
+ maOverlineColor = Color( COL_TRANSPARENT );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetOverlineColor();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetOverlineColor( const Color& rColor )
+{
+ DBG_TRACE( "OutputDevice::SetOverlineColor()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Color aColor( rColor );
+
+ if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
+ DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
+ DRAWMODE_SETTINGSTEXT ) )
+ {
+ if ( mnDrawMode & DRAWMODE_BLACKTEXT )
+ aColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITETEXT )
+ aColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
+ aColor = GetSettings().GetStyleSettings().GetFontColor();
+
+ if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
+ && (aColor.GetColor() != COL_TRANSPARENT) )
+ {
+ aColor = Color( (aColor.GetRed() >> 1) | 0x80,
+ (aColor.GetGreen() >> 1) | 0x80,
+ (aColor.GetBlue() >> 1) | 0x80 );
+ }
+ }
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, TRUE ) );
+
+ maOverlineColor = aColor;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetOverlineColor( COL_BLACK );
+}
+
+// -----------------------------------------------------------------------
+
+
+void OutputDevice::SetTextAlign( TextAlign eAlign )
+{
+ DBG_TRACE( "OutputDevice::SetTextAlign()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
+
+ if ( maFont.GetAlign() != eAlign )
+ {
+ maFont.SetAlign( eAlign );
+ mbNewFont = TRUE;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTextAlign( eAlign );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ FontUnderline eOverline,
+ BOOL bUnderlineAbove )
+{
+ DBG_TRACE( "OutputDevice::DrawTextLine()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
+
+ if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
+ ((eOverline == UNDERLINE_NONE) || (eOverline == UNDERLINE_DONTKNOW)) &&
+ ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
+ return;
+
+ if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ // we need a graphics
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
+
+ // initialize font if needed to get text offsets
+ // TODO: only needed for mnTextOff!=(0,0)
+ if( mbNewFont )
+ if( !ImplNewFont() )
+ return;
+ if( mbInitFont )
+ ImplInitFont();
+
+ Point aPos = ImplLogicToDevicePixel( rPos );
+ nWidth = ImplLogicWidthToDevicePixel( nWidth );
+ aPos += Point( mnTextOffX, mnTextOffY );
+ ImplDrawTextLine( aPos.X(), aPos.X(), aPos.Y(), nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL OutputDevice::IsTextUnderlineAbove( const Font& rFont )
+{
+ return ImplIsUnderlineAbove( rFont );
+}
+
+// ------------------------------------------------------------------------
+
+void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos,
+ USHORT nStyle )
+{
+ DBG_TRACE( "OutputDevice::DrawWaveLine()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ // we need a graphics
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if( mbNewFont )
+ if( !ImplNewFont() )
+ return;
+
+ Point aStartPt = ImplLogicToDevicePixel( rStartPos );
+ Point aEndPt = ImplLogicToDevicePixel( rEndPos );
+ long nStartX = aStartPt.X();
+ long nStartY = aStartPt.Y();
+ long nEndX = aEndPt.X();
+ long nEndY = aEndPt.Y();
+ short nOrientation = 0;
+
+ // when rotated
+ if ( (nStartY != nEndY) || (nStartX > nEndX) )
+ {
+ long nDX = nEndX - nStartX;
+ double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
+ nO /= F_PI1800;
+ nOrientation = (short)nO;
+ ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
+ }
+
+ long nWaveHeight;
+ if ( nStyle == WAVE_NORMAL )
+ {
+ nWaveHeight = 3;
+ nStartY++;
+ nEndY++;
+ }
+ else if( nStyle == WAVE_SMALL )
+ {
+ nWaveHeight = 2;
+ nStartY++;
+ nEndY++;
+ }
+ else // WAVE_FLAT
+ nWaveHeight = 1;
+
+ // #109280# make sure the waveline does not exceed the descent to avoid paint problems
+ ImplFontEntry* pFontEntry = mpFontEntry;
+ if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
+ nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
+
+ ImplDrawWaveLine( nStartX, nStartY, nStartX, nStartY,
+ nEndX-nStartX, nWaveHeight, 1,
+ nOrientation, GetLineColor() );
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawText( const Point& rStartPt, const String& rStr,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ MetricVector* pVector, String* pDisplayText
+ )
+{
+ if( mpOutDevData && mpOutDevData->mpRecordLayout )
+ {
+ pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
+ pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
+ }
+
+ DBG_TRACE( "OutputDevice::DrawText()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, " OutputDevice::DrawText(\"%s\")\n",
+ OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
+#endif
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
+ if( pVector )
+ {
+ Region aClip( GetClipRegion() );
+ if( meOutDevType == OUTDEV_WINDOW )
+ aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
+ if( mpOutDevData && mpOutDevData->mpRecordLayout )
+ {
+ mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.Len() );
+ aClip.Intersect( mpOutDevData->maRecordRect );
+ }
+ if( ! aClip.IsNull() )
+ {
+ MetricVector aTmp;
+ GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
+
+ bool bInserted = false;
+ for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
+ {
+ bool bAppend = false;
+
+ if( aClip.IsOver( *it ) )
+ bAppend = true;
+ else if( rStr.GetChar( nIndex ) == ' ' && bInserted )
+ {
+ MetricVector::const_iterator next = it;
+ ++next;
+ if( next != aTmp.end() && aClip.IsOver( *next ) )
+ bAppend = true;
+ }
+
+ if( bAppend )
+ {
+ pVector->push_back( *it );
+ if( pDisplayText )
+ pDisplayText->Append( rStr.GetChar( nIndex ) );
+ bInserted = true;
+ }
+ }
+ }
+ else
+ {
+ GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
+ if( pDisplayText )
+ pDisplayText->Append( rStr.Copy( nIndex, nLen ) );
+ }
+ }
+
+ if ( !IsDeviceOutputNecessary() || pVector )
+ return;
+
+ SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, NULL, true );
+ if( pSalLayout )
+ {
+ ImplDrawText( *pSalLayout );
+ pSalLayout->Release();
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::GetTextWidth( const String& rStr,
+ xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_TRACE( "OutputDevice::GetTextWidth()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
+ return nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::GetTextHeight() const
+{
+ DBG_TRACE( "OutputDevice::GetTextHeight()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( mbNewFont )
+ if( !ImplNewFont() )
+ return 0;
+ if( mbInitFont )
+ if( !ImplNewFont() )
+ return 0;
+
+ long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
+
+ if ( mbMap )
+ nHeight = ImplDevicePixelToLogicHeight( nHeight );
+
+ return nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr,
+ const sal_Int32* pDXAry,
+ xub_StrLen nIndex, xub_StrLen nLen )
+{
+ DBG_TRACE( "OutputDevice::DrawTextArray()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
+
+ if ( !IsDeviceOutputNecessary() )
+ return;
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
+
+ SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
+ if( pSalLayout )
+ {
+ ImplDrawText( *pSalLayout );
+ pSalLayout->Release();
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::GetTextArray( const String& rStr, sal_Int32* pDXAry,
+ xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ DBG_TRACE( "OutputDevice::GetTextArray()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( nIndex >= rStr.Len() )
+ return 0;
+ if( (ULONG)nIndex+nLen >= rStr.Len() )
+ nLen = rStr.Len() - nIndex;
+
+ // do layout
+ SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
+ if( !pSalLayout )
+ return 0;
+
+ long nWidth = pSalLayout->FillDXArray( pDXAry );
+ int nWidthFactor = pSalLayout->GetUnitsPerPixel();
+ pSalLayout->Release();
+
+ // convert virtual char widths to virtual absolute positions
+ if( pDXAry )
+ for( int i = 1; i < nLen; ++i )
+ pDXAry[ i ] += pDXAry[ i-1 ];
+
+ // convert from font units to logical units
+ if( mbMap )
+ {
+ if( pDXAry )
+ for( int i = 0; i < nLen; ++i )
+ pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
+ nWidth = ImplDevicePixelToLogicWidth( nWidth );
+ }
+
+ if( nWidthFactor > 1 )
+ {
+ if( pDXAry )
+ for( int i = 0; i < nLen; ++i )
+ pDXAry[i] /= nWidthFactor;
+ nWidth /= nWidthFactor;
+ }
+
+ return nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+bool OutputDevice::GetCaretPositions( const XubString& rStr, sal_Int32* pCaretXArray,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ sal_Int32* pDXAry, long nLayoutWidth,
+ BOOL bCellBreaking ) const
+{
+ DBG_TRACE( "OutputDevice::GetCaretPositions()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( nIndex >= rStr.Len() )
+ return false;
+ if( (ULONG)nIndex+nLen >= rStr.Len() )
+ nLen = rStr.Len() - nIndex;
+
+ // layout complex text
+ SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
+ Point(0,0), nLayoutWidth, pDXAry );
+ if( !pSalLayout )
+ return false;
+
+ int nWidthFactor = pSalLayout->GetUnitsPerPixel();
+ pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
+ long nWidth = pSalLayout->GetTextWidth();
+ pSalLayout->Release();
+
+ // fixup unknown caret positions
+ int i;
+ for( i = 0; i < 2 * nLen; ++i )
+ if( pCaretXArray[ i ] >= 0 )
+ break;
+ long nXPos = pCaretXArray[ i ];
+ for( i = 0; i < 2 * nLen; ++i )
+ {
+ if( pCaretXArray[ i ] >= 0 )
+ nXPos = pCaretXArray[ i ];
+ else
+ pCaretXArray[ i ] = nXPos;
+ }
+
+ // handle window mirroring
+ if( IsRTLEnabled() )
+ {
+ for( i = 0; i < 2 * nLen; ++i )
+ pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
+ }
+
+ // convert from font units to logical units
+ if( mbMap )
+ {
+ for( i = 0; i < 2*nLen; ++i )
+ pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
+ }
+
+ if( nWidthFactor != 1 )
+ {
+ for( i = 0; i < 2*nLen; ++i )
+ pCaretXArray[i] /= nWidthFactor;
+ }
+
+ // if requested move caret position to cell limits
+ if( bCellBreaking )
+ {
+ ; // TODO
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawStretchText( const Point& rStartPt, ULONG nWidth,
+ const String& rStr,
+ xub_StrLen nIndex, xub_StrLen nLen )
+{
+ DBG_TRACE( "OutputDevice::DrawStretchText()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
+
+ if ( !IsDeviceOutputNecessary() )
+ return;
+
+ SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, nWidth, NULL, true );
+ if( pSalLayout )
+ {
+ ImplDrawText( *pSalLayout );
+ pSalLayout->Release();
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
+}
+
+// -----------------------------------------------------------------------
+
+ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( String& rStr,
+ xub_StrLen nMinIndex, xub_StrLen nLen,
+ long nPixelWidth, const sal_Int32* pDXArray ) const
+{
+ // get string length for calculating extents
+ xub_StrLen nEndIndex = rStr.Len();
+ if( (ULONG)nMinIndex + nLen < nEndIndex )
+ nEndIndex = nMinIndex + nLen;
+
+ // don't bother if there is nothing to do
+ if( nEndIndex < nMinIndex )
+ nEndIndex = nMinIndex;
+
+ int nLayoutFlags = 0;
+ if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
+ nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
+ if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
+ nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
+ else if( 0 == (mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
+ {
+ // disable Bidi if no RTL hint and no RTL codes used
+ const xub_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
+ const xub_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
+ for( ; pStr < pEnd; ++pStr )
+ if( ((*pStr >= 0x0580) && (*pStr < 0x0800)) // middle eastern scripts
+ || ((*pStr >= 0xFB18) && (*pStr < 0xFE00)) // hebrew + arabic A presentation forms
+ || ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
+ break;
+ if( pStr >= pEnd )
+ nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
+ }
+
+ if( mbKerning )
+ nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
+ if( maFont.GetKerning() & KERNING_ASIAN )
+ nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
+ if( maFont.IsVertical() )
+ nLayoutFlags |= SAL_LAYOUT_VERTICAL;
+
+ if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
+ nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
+ else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
+ nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
+ else
+ {
+ // disable CTL for non-CTL text
+ const sal_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
+ const sal_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
+ for( ; pStr < pEnd; ++pStr )
+ if( ((*pStr >= 0x0300) && (*pStr < 0x0370)) // diacritical marks
+ || ((*pStr >= 0x0590) && (*pStr < 0x10A0)) // many CTL scripts
+ || ((*pStr >= 0x1100) && (*pStr < 0x1200)) // hangul jamo
+ || ((*pStr >= 0x1700) && (*pStr < 0x1900)) // many CTL scripts
+ || ((*pStr >= 0xFB1D) && (*pStr < 0xFE00)) // middle east presentation
+ || ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation B
+ break;
+ if( pStr >= pEnd )
+ nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
+ }
+
+ if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
+ {
+ // disable character localization when no digits used
+ const sal_Unicode* pBase = rStr.GetBuffer();
+ const sal_Unicode* pStr = pBase + nMinIndex;
+ const sal_Unicode* pEnd = pBase + nEndIndex;
+ for( ; pStr < pEnd; ++pStr )
+ {
+ // TODO: are there non-digit localizations?
+ if( (*pStr >= '0') && (*pStr <= '9') )
+ {
+ // translate characters to local preference
+ sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
+ if( cChar != *pStr )
+ // TODO: are the localized digit surrogates?
+ rStr.SetChar( static_cast<USHORT>(pStr - pBase),
+ static_cast<sal_Unicode>(cChar) );
+ }
+ }
+ }
+
+ // right align for RTL text, DRAWPOS_REVERSED, RTL window style
+ bool bRightAlign = ((mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) != 0);
+ if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
+ bRightAlign = false;
+ else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
+ bRightAlign = true;
+ // SSA: hack for western office, ie text get right aligned
+ // for debugging purposes of mirrored UI
+ //static const char* pEnv = getenv( "SAL_RTL_MIRRORTEXT" );
+ bool bRTLWindow = IsRTLEnabled();
+ bRightAlign ^= bRTLWindow;
+ if( bRightAlign )
+ nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
+
+ // set layout options
+ ImplLayoutArgs aLayoutArgs( rStr.GetBuffer(), rStr.Len(), nMinIndex, nEndIndex, nLayoutFlags );
+
+ int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
+ aLayoutArgs.SetOrientation( nOrientation );
+
+ aLayoutArgs.SetLayoutWidth( nPixelWidth );
+ aLayoutArgs.SetDXArray( pDXArray );
+
+ return aLayoutArgs;
+}
+
+// -----------------------------------------------------------------------
+
+SalLayout* OutputDevice::ImplLayout( const String& rOrigStr,
+ xub_StrLen nMinIndex,
+ xub_StrLen nLen,
+ const Point& rLogicalPos,
+ long nLogicalWidth,
+ const sal_Int32* pDXArray,
+ bool bFilter ) const
+{
+ // we need a graphics
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return NULL;
+
+ // initialize font if needed
+ if( mbNewFont )
+ if( !ImplNewFont() )
+ return NULL;
+ if( mbInitFont )
+ ImplInitFont();
+
+ // check string index and length
+ if( (unsigned)nMinIndex + nLen > rOrigStr.Len() )
+ {
+ const int nNewLen = (int)rOrigStr.Len() - nMinIndex;
+ if( nNewLen <= 0 )
+ return NULL;
+ nLen = static_cast<xub_StrLen>(nNewLen);
+ }
+
+ String aStr = rOrigStr;
+
+ // filter out special markers
+ if( bFilter )
+ {
+ xub_StrLen nCutStart, nCutStop, nOrgLen = nLen;
+ bool bFiltered = mpGraphics->filterText( rOrigStr, aStr, nMinIndex, nLen, nCutStart, nCutStop );
+ if( !nLen )
+ return NULL;
+
+ if( bFiltered && nCutStop != nCutStart && pDXArray )
+ {
+ if( !nLen )
+ pDXArray = NULL;
+ else
+ {
+ sal_Int32* pAry = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
+ if( nCutStart > nMinIndex )
+ memcpy( pAry, pDXArray, sizeof(sal_Int32)*(nCutStart-nMinIndex) );
+ // note: nCutStart will never be smaller than nMinIndex
+ memcpy( pAry+nCutStart-nMinIndex,
+ pDXArray + nOrgLen - (nCutStop-nMinIndex),
+ sizeof(sal_Int32)*(nLen - (nCutStart-nMinIndex)) );
+ pDXArray = pAry;
+ }
+ }
+ }
+
+ // convert from logical units to physical units
+ // recode string if needed
+ if( mpFontEntry->mpConversion )
+ mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.Len() );
+
+ long nPixelWidth = nLogicalWidth;
+ if( nLogicalWidth && mbMap )
+ nPixelWidth = ImplLogicWidthToDevicePixel( nLogicalWidth );
+ if( pDXArray && mbMap )
+ {
+ // convert from logical units to font units using a temporary array
+ sal_Int32* pTempDXAry = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
+ // using base position for better rounding a.k.a. "dancing characters"
+ int nPixelXOfs = ImplLogicWidthToDevicePixel( rLogicalPos.X() );
+ for( int i = 0; i < nLen; ++i )
+ pTempDXAry[i] = ImplLogicWidthToDevicePixel( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
+
+ pDXArray = pTempDXAry;
+ }
+
+ ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
+
+ // get matching layout object for base font
+ SalLayout* pSalLayout = NULL;
+ if( mpPDFWriter )
+ pSalLayout = mpPDFWriter->GetTextLayout( aLayoutArgs, &mpFontEntry->maFontSelData );
+
+ if( !pSalLayout )
+ pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
+
+ // layout text
+ if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
+ {
+ pSalLayout->Release();
+ pSalLayout = NULL;
+ }
+
+ if( !pSalLayout )
+ return NULL;
+
+ // do glyph fallback if needed
+ // #105768# avoid fallback for very small font sizes
+ if( aLayoutArgs.NeedFallback() )
+ if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 3) )
+ pSalLayout = ImplGlyphFallbackLayout( pSalLayout, aLayoutArgs );
+
+ // position, justify, etc. the layout
+ pSalLayout->AdjustLayout( aLayoutArgs );
+ pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
+ // adjust to right alignment if necessary
+ if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
+ {
+ long nRTLOffset;
+ if( pDXArray )
+ nRTLOffset = pDXArray[ nLen - 1 ];
+ else if( nPixelWidth )
+ nRTLOffset = nPixelWidth;
+ else
+ nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
+ pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
+ }
+
+ return pSalLayout;
+}
+
+// -----------------------------------------------------------------------
+
+SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
+{
+ // prepare multi level glyph fallback
+ MultiSalLayout* pMultiSalLayout = NULL;
+ ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
+ rLayoutArgs.PrepareFallback();
+ rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
+
+#if defined(HDU_DEBUG)
+ {
+ int nCharPos = -1;
+ bool bRTL = false;
+ fprintf(stderr,"OD:ImplLayout Glyph Fallback for");
+ for( int i=0; i<8 && rLayoutArgs.GetNextPos( &nCharPos, &bRTL); ++i )
+ fprintf(stderr," U+%04X", rLayoutArgs.mpStr[ nCharPos ] );
+ fprintf(stderr,"\n");
+ rLayoutArgs.ResetPos();
+ }
+#endif
+ // get list of unicodes that need glyph fallback
+ int nCharPos = -1;
+ bool bRTL = false;
+ rtl::OUStringBuffer aMissingCodeBuf;
+ while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
+ aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
+ rLayoutArgs.ResetPos();
+ rtl::OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
+
+ ImplFontSelectData aFontSelData = mpFontEntry->maFontSelData;
+ // when device specific font substitution may have been performed for
+ // the originally selected font then make sure that a fallback to that
+ // font is performed first
+ int nDevSpecificFallback = 0;
+ if( mpOutDevData && !mpOutDevData->maDevFontSubst.Empty() )
+ nDevSpecificFallback = 1;
+
+ // try if fallback fonts support the missing unicodes
+ for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
+ {
+ // find a font family suited for glyph fallback
+#ifndef FONTFALLBACK_HOOKS_DISABLED
+ // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
+ // if the system-specific glyph fallback is active
+ aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
+#endif
+ ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontList,
+ aFontSelData, nFallbackLevel-nDevSpecificFallback, aMissingCodes );
+ if( !pFallbackFont )
+ break;
+
+ aFontSelData.mpFontEntry = pFallbackFont;
+ aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
+ if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1)
+ {
+ // ignore fallback font if it is the same as the original font
+ if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
+ {
+ mpFontCache->Release( pFallbackFont );
+ continue;
+ }
+ }
+
+#if defined(HDU_DEBUG)
+ {
+ ByteString aOrigFontName( maFont.GetName(), RTL_TEXTENCODING_UTF8);
+ ByteString aFallbackName( aFontSelData.mpFontData->GetFamilyName(),
+ RTL_TEXTENCODING_UTF8);
+ fprintf(stderr,"\tGlyphFallback[lvl=%d] \"%s\" -> \"%s\" (q=%d)\n",
+ nFallbackLevel, aOrigFontName.GetBuffer(), aFallbackName.GetBuffer(),
+ aFontSelData.mpFontData->GetQuality());
+ }
+#endif
+
+ pFallbackFont->mnSetFontFlags = mpGraphics->SetFont( &aFontSelData, nFallbackLevel );
+
+ // create and add glyph fallback layout to multilayout
+ rLayoutArgs.ResetPos();
+ SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
+ if( pFallback )
+ {
+ if( pFallback->LayoutText( rLayoutArgs ) )
+ {
+ if( !pMultiSalLayout )
+ pMultiSalLayout = new MultiSalLayout( *pSalLayout );
+ pMultiSalLayout->AddFallback( *pFallback,
+ rLayoutArgs.maRuns, aFontSelData.mpFontData );
+ if (nFallbackLevel == MAX_FALLBACK-1)
+ pMultiSalLayout->SetInComplete();
+ }
+ else
+ {
+ // there is no need for a font that couldn't resolve anything
+ pFallback->Release();
+ }
+ }
+
+ mpFontCache->Release( pFallbackFont );
+
+ // break when this fallback was sufficient
+ if( !rLayoutArgs.PrepareFallback() )
+ break;
+ }
+
+ if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
+ pSalLayout = pMultiSalLayout;
+
+ // restore orig font settings
+ pSalLayout->InitFont();
+ rLayoutArgs.maRuns = aLayoutRuns;
+
+ return pSalLayout;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetTextIsRTL(
+ const String& rString,
+ xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ String aStr( rString );
+ ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
+ bool bRTL = false;
+ int nCharPos = -1;
+ aArgs.GetNextPos( &nCharPos, &bRTL );
+ return (nCharPos != nIndex) ? TRUE : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ long nCharExtra, BOOL /*TODO: bCellBreaking*/ ) const
+{
+ DBG_TRACE( "OutputDevice::GetTextBreak()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
+ xub_StrLen nRetVal = STRING_LEN;
+ if( pSalLayout )
+ {
+ // convert logical widths into layout units
+ // NOTE: be very careful to avoid rounding errors for nCharExtra case
+ // problem with rounding errors especially for small nCharExtras
+ // TODO: remove when layout units have subpixel granularity
+ long nWidthFactor = pSalLayout->GetUnitsPerPixel();
+ long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
+ nTextWidth *= nWidthFactor * nSubPixelFactor;
+ long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
+ long nExtraPixelWidth = 0;
+ if( nCharExtra != 0 )
+ {
+ nCharExtra *= nWidthFactor * nSubPixelFactor;
+ nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
+ }
+ nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
+
+ pSalLayout->Release();
+ }
+
+ return nRetVal;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
+ sal_Unicode nHyphenatorChar, xub_StrLen& rHyphenatorPos,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ long nCharExtra ) const
+{
+ DBG_TRACE( "OutputDevice::GetTextBreak()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ rHyphenatorPos = STRING_LEN;
+
+ SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
+ if( !pSalLayout )
+ return STRING_LEN;
+
+ // convert logical widths into layout units
+ // NOTE: be very careful to avoid rounding errors for nCharExtra case
+ // problem with rounding errors especially for small nCharExtras
+ // TODO: remove when layout units have subpixel granularity
+ long nWidthFactor = pSalLayout->GetUnitsPerPixel();
+ long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
+
+ nTextWidth *= nWidthFactor * nSubPixelFactor;
+ long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
+ long nExtraPixelWidth = 0;
+ if( nCharExtra != 0 )
+ {
+ nCharExtra *= nWidthFactor * nSubPixelFactor;
+ nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
+ }
+
+ // calculate un-hyphenated break position
+ xub_StrLen nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
+
+ // calculate hyphenated break position
+ String aHyphenatorStr( &nHyphenatorChar, 1 );
+ xub_StrLen nTempLen = 1;
+ SalLayout* pHyphenatorLayout = ImplLayout( aHyphenatorStr, 0, nTempLen );
+ if( pHyphenatorLayout )
+ {
+ // calculate subpixel width of hyphenation character
+ long nHyphenatorPixelWidth = pHyphenatorLayout->GetTextWidth() * nSubPixelFactor;
+ pHyphenatorLayout->Release();
+
+ // calculate hyphenated break position
+ nTextPixelWidth -= nHyphenatorPixelWidth;
+ if( nExtraPixelWidth > 0 )
+ nTextPixelWidth -= nExtraPixelWidth;
+
+ rHyphenatorPos = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
+
+ if( rHyphenatorPos > nRetVal )
+ rHyphenatorPos = nRetVal;
+ }
+
+ pSalLayout->Release();
+ return nRetVal;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
+ const String& rOrigStr, USHORT nStyle,
+ MetricVector* pVector, String* pDisplayText,
+ ::vcl::ITextLayout& _rLayout )
+{
+ Color aOldTextColor;
+ Color aOldTextFillColor;
+ BOOL bRestoreFillColor = false;
+ if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
+ {
+ BOOL bHighContrastBlack = FALSE;
+ BOOL bHighContrastWhite = FALSE;
+ const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
+ if( rStyleSettings.GetHighContrastMode() )
+ {
+ Color aCol;
+ if( rTargetDevice.IsBackground() )
+ aCol = rTargetDevice.GetBackground().GetColor();
+ else
+ // best guess is the face color here
+ // but it may be totally wrong. the background color
+ // was typically already reset
+ aCol = rStyleSettings.GetFaceColor();
+
+ bHighContrastBlack = aCol.IsDark();
+ bHighContrastWhite = aCol.IsBright();
+ }
+
+ aOldTextColor = rTargetDevice.GetTextColor();
+ if ( rTargetDevice.IsTextFillColor() )
+ {
+ bRestoreFillColor = TRUE;
+ aOldTextFillColor = rTargetDevice.GetTextFillColor();
+ }
+ if( bHighContrastBlack )
+ rTargetDevice.SetTextColor( COL_GREEN );
+ else if( bHighContrastWhite )
+ rTargetDevice.SetTextColor( COL_LIGHTGREEN );
+ else
+ {
+ // draw disabled text always without shadow
+ // as it fits better with native look
+ /*
+ SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
+ Rectangle aRect = rRect;
+ aRect.Move( 1, 1 );
+ DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE );
+ */
+ rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
+ }
+ }
+
+ long nWidth = rRect.GetWidth();
+ long nHeight = rRect.GetHeight();
+
+ if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
+ return;
+
+ Point aPos = rRect.TopLeft();
+
+ long nTextHeight = rTargetDevice.GetTextHeight();
+ TextAlign eAlign = rTargetDevice.GetTextAlign();
+ xub_StrLen nMnemonicPos = STRING_NOTFOUND;
+
+ String aStr = rOrigStr;
+ if ( nStyle & TEXT_DRAW_MNEMONIC )
+ aStr = GetNonMnemonicString( aStr, nMnemonicPos );
+
+ const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
+
+ // Mehrzeiligen Text behandeln wir anders
+ if ( nStyle & TEXT_DRAW_MULTILINE )
+ {
+
+ XubString aLastLine;
+ ImplMultiTextLineInfo aMultiLineInfo;
+ ImplTextLineInfo* pLineInfo;
+ long nMaxTextWidth;
+ xub_StrLen i;
+ xub_StrLen nLines;
+ xub_StrLen nFormatLines;
+
+ if ( nTextHeight )
+ {
+ nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
+ nLines = (xub_StrLen)(nHeight/nTextHeight);
+ nFormatLines = aMultiLineInfo.Count();
+ if ( !nLines )
+ nLines = 1;
+ if ( nFormatLines > nLines )
+ {
+ if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
+ {
+ // Letzte Zeile zusammenbauen und kuerzen
+ nFormatLines = nLines-1;
+
+ pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
+ aLastLine = aStr.Copy( pLineInfo->GetIndex() );
+ aLastLine.ConvertLineEnd( LINEEND_LF );
+ // Alle LineFeed's durch Spaces ersetzen
+ xub_StrLen nLastLineLen = aLastLine.Len();
+ for ( i = 0; i < nLastLineLen; i++ )
+ {
+ if ( aLastLine.GetChar( i ) == _LF )
+ aLastLine.SetChar( i, ' ' );
+ }
+ aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
+ nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
+ nStyle |= TEXT_DRAW_TOP;
+ }
+ }
+ else
+ {
+ if ( nMaxTextWidth <= nWidth )
+ nStyle &= ~TEXT_DRAW_CLIP;
+ }
+
+ // Muss in der Hoehe geclippt werden?
+ if ( nFormatLines*nTextHeight > nHeight )
+ nStyle |= TEXT_DRAW_CLIP;
+
+ // Clipping setzen
+ if ( nStyle & TEXT_DRAW_CLIP )
+ {
+ rTargetDevice.Push( PUSH_CLIPREGION );
+ rTargetDevice.IntersectClipRegion( rRect );
+ }
+
+ // Vertikales Alignment
+ if ( nStyle & TEXT_DRAW_BOTTOM )
+ aPos.Y() += nHeight-(nFormatLines*nTextHeight);
+ else if ( nStyle & TEXT_DRAW_VCENTER )
+ aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
+
+ // Font Alignment
+ if ( eAlign == ALIGN_BOTTOM )
+ aPos.Y() += nTextHeight;
+ else if ( eAlign == ALIGN_BASELINE )
+ aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
+
+ // Alle Zeilen ausgeben, bis auf die letzte
+ for ( i = 0; i < nFormatLines; i++ )
+ {
+ pLineInfo = aMultiLineInfo.GetLine( i );
+ if ( nStyle & TEXT_DRAW_RIGHT )
+ aPos.X() += nWidth-pLineInfo->GetWidth();
+ else if ( nStyle & TEXT_DRAW_CENTER )
+ aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
+ xub_StrLen nIndex = pLineInfo->GetIndex();
+ xub_StrLen nLineLen = pLineInfo->GetLen();
+ _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
+ if ( bDrawMnemonics )
+ {
+ if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
+ {
+ long nMnemonicX;
+ long nMnemonicY;
+ long nMnemonicWidth;
+
+ sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
+ /*BOOL bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
+ nIndex, nLineLen );
+ long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
+ long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
+ nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
+
+ Point aTempPos = rTargetDevice.LogicToPixel( aPos );
+ nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min( lc_x1, lc_x2 ) );
+ nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
+ rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ }
+ }
+ aPos.Y() += nTextHeight;
+ aPos.X() = rRect.Left();
+ }
+
+
+ // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
+ // da die Zeile gekuerzt wurde
+ if ( aLastLine.Len() )
+ _rLayout.DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
+
+ // Clipping zuruecksetzen
+ if ( nStyle & TEXT_DRAW_CLIP )
+ rTargetDevice.Pop();
+ }
+ }
+ else
+ {
+ long nTextWidth = _rLayout.GetTextWidth( aStr, 0, STRING_LEN );
+
+ // Evt. Text kuerzen
+ if ( nTextWidth > nWidth )
+ {
+ if ( nStyle & TEXT_DRAW_ELLIPSIS )
+ {
+ aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
+ nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
+ nStyle |= TEXT_DRAW_LEFT;
+ nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.Len() );
+ }
+ }
+ else
+ {
+ if ( nTextHeight <= nHeight )
+ nStyle &= ~TEXT_DRAW_CLIP;
+ }
+
+ // horizontal text alignment
+ if ( nStyle & TEXT_DRAW_RIGHT )
+ aPos.X() += nWidth-nTextWidth;
+ else if ( nStyle & TEXT_DRAW_CENTER )
+ aPos.X() += (nWidth-nTextWidth)/2;
+
+ // vertical font alignment
+ if ( eAlign == ALIGN_BOTTOM )
+ aPos.Y() += nTextHeight;
+ else if ( eAlign == ALIGN_BASELINE )
+ aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
+
+ if ( nStyle & TEXT_DRAW_BOTTOM )
+ aPos.Y() += nHeight-nTextHeight;
+ else if ( nStyle & TEXT_DRAW_VCENTER )
+ aPos.Y() += (nHeight-nTextHeight)/2;
+
+ long nMnemonicX = 0;
+ long nMnemonicY = 0;
+ long nMnemonicWidth = 0;
+ if ( nMnemonicPos != STRING_NOTFOUND )
+ {
+ sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.Len() );
+ /*BOOL bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
+ long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
+ long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
+ nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
+
+ Point aTempPos = rTargetDevice.LogicToPixel( aPos );
+ nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min(lc_x1, lc_x2) );
+ nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
+ }
+
+ if ( nStyle & TEXT_DRAW_CLIP )
+ {
+ rTargetDevice.Push( PUSH_CLIPREGION );
+ rTargetDevice.IntersectClipRegion( rRect );
+ _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
+ if ( bDrawMnemonics )
+ {
+ if ( nMnemonicPos != STRING_NOTFOUND )
+ rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ }
+ rTargetDevice.Pop();
+ }
+ else
+ {
+ _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
+ if ( bDrawMnemonics )
+ {
+ if ( nMnemonicPos != STRING_NOTFOUND )
+ rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ }
+ }
+ }
+
+ if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
+ {
+ rTargetDevice.SetTextColor( aOldTextColor );
+ if ( bRestoreFillColor )
+ rTargetDevice.SetTextFillColor( aOldTextFillColor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::AddTextRectActions( const Rectangle& rRect,
+ const String& rOrigStr,
+ USHORT nStyle,
+ GDIMetaFile& rMtf )
+{
+ DBG_TRACE( "OutputDevice::AddTextRectActions( const Rectangle& )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !rOrigStr.Len() || rRect.IsEmpty() )
+ return;
+
+ // we need a graphics
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ // temporarily swap in passed mtf for action generation, and
+ // disable output generation.
+ const BOOL bOutputEnabled( IsOutputEnabled() );
+ GDIMetaFile* pMtf = mpMetaFile;
+
+ mpMetaFile = &rMtf;
+ EnableOutput( FALSE );
+
+ // #i47157# Factored out to ImplDrawTextRect(), to be shared
+ // between us and DrawText()
+ DefaultTextLayout aLayout( *this );
+ ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
+
+ // and restore again
+ EnableOutput( bOutputEnabled );
+ mpMetaFile = pMtf;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle,
+ MetricVector* pVector, String* pDisplayText,
+ ::vcl::ITextLayout* _pTextLayout )
+{
+ if( mpOutDevData && mpOutDevData->mpRecordLayout )
+ {
+ pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
+ pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
+ }
+
+ DBG_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
+ if ( mpMetaFile && !bDecomposeTextRectAction )
+ mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
+
+ if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || !rOrigStr.Len() || rRect.IsEmpty() )
+ return;
+
+ // we need a graphics
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped && !bDecomposeTextRectAction )
+ return;
+
+ // temporarily disable mtf action generation (ImplDrawText _does_
+ // create META_TEXT_ACTIONs otherwise)
+ GDIMetaFile* pMtf = mpMetaFile;
+ if ( !bDecomposeTextRectAction )
+ mpMetaFile = NULL;
+
+ // #i47157# Factored out to ImplDrawText(), to be used also
+ // from AddTextRectActions()
+ DefaultTextLayout aDefaultLayout( *this );
+ ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
+
+ // and enable again
+ mpMetaFile = pMtf;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
+ const XubString& rStr, USHORT nStyle,
+ TextRectInfo* pInfo,
+ const ::vcl::ITextLayout* _pTextLayout ) const
+{
+ DBG_TRACE( "OutputDevice::GetTextRect()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Rectangle aRect = rRect;
+ xub_StrLen nLines;
+ long nWidth = rRect.GetWidth();
+ long nMaxWidth;
+ long nTextHeight = GetTextHeight();
+
+ String aStr = rStr;
+ if ( nStyle & TEXT_DRAW_MNEMONIC )
+ aStr = GetNonMnemonicString( aStr );
+
+ if ( nStyle & TEXT_DRAW_MULTILINE )
+ {
+ ImplMultiTextLineInfo aMultiLineInfo;
+ ImplTextLineInfo* pLineInfo;
+ xub_StrLen nFormatLines;
+ xub_StrLen i;
+
+ nMaxWidth = 0;
+ DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
+ ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
+ nFormatLines = aMultiLineInfo.Count();
+ if ( !nTextHeight )
+ nTextHeight = 1;
+ nLines = (USHORT)(aRect.GetHeight()/nTextHeight);
+ if ( pInfo )
+ pInfo->mnLineCount = nFormatLines;
+ if ( !nLines )
+ nLines = 1;
+ if ( nFormatLines <= nLines )
+ nLines = nFormatLines;
+ else
+ {
+ if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
+ nLines = nFormatLines;
+ else
+ {
+ if ( pInfo )
+ pInfo->mbEllipsis = TRUE;
+ nMaxWidth = nWidth;
+ }
+ }
+ if ( pInfo )
+ {
+ BOOL bMaxWidth = nMaxWidth == 0;
+ pInfo->mnMaxWidth = 0;
+ for ( i = 0; i < nLines; i++ )
+ {
+ pLineInfo = aMultiLineInfo.GetLine( i );
+ if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
+ nMaxWidth = pLineInfo->GetWidth();
+ if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
+ pInfo->mnMaxWidth = pLineInfo->GetWidth();
+ }
+ }
+ else if ( !nMaxWidth )
+ {
+ for ( i = 0; i < nLines; i++ )
+ {
+ pLineInfo = aMultiLineInfo.GetLine( i );
+ if ( pLineInfo->GetWidth() > nMaxWidth )
+ nMaxWidth = pLineInfo->GetWidth();
+ }
+ }
+ }
+ else
+ {
+ nLines = 1;
+ nMaxWidth = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.Len() ) : GetTextWidth( aStr );
+
+ if ( pInfo )
+ {
+ pInfo->mnLineCount = 1;
+ pInfo->mnMaxWidth = nMaxWidth;
+ }
+
+ if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
+ {
+ if ( pInfo )
+ pInfo->mbEllipsis = TRUE;
+ nMaxWidth = nWidth;
+ }
+ }
+
+ if ( nStyle & TEXT_DRAW_RIGHT )
+ aRect.Left() = aRect.Right()-nMaxWidth+1;
+ else if ( nStyle & TEXT_DRAW_CENTER )
+ {
+ aRect.Left() += (nWidth-nMaxWidth)/2;
+ aRect.Right() = aRect.Left()+nMaxWidth-1;
+ }
+ else
+ aRect.Right() = aRect.Left()+nMaxWidth-1;
+
+ if ( nStyle & TEXT_DRAW_BOTTOM )
+ aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
+ else if ( nStyle & TEXT_DRAW_VCENTER )
+ {
+ aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2;
+ aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
+ }
+ else
+ aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
+
+ aRect.Right()++; // #99188# get rid of rounding problems when using this rect later
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplIsCharIn( xub_Unicode c, const sal_Char* pStr )
+{
+ while ( *pStr )
+ {
+ if ( *pStr == c )
+ return TRUE;
+ pStr++;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
+ USHORT nStyle ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
+ return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
+}
+
+// -----------------------------------------------------------------------
+
+String OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const XubString& rOrigStr, long nMaxWidth,
+ USHORT nStyle, const ::vcl::ITextLayout& _rLayout )
+{
+ DBG_TRACE( "OutputDevice::ImplGetEllipsisString()" );
+
+ String aStr = rOrigStr;
+ xub_StrLen nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.Len() );
+
+
+ if ( nIndex != STRING_LEN )
+ {
+ if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
+ {
+ aStr.Erase( nIndex );
+ if ( nIndex > 1 )
+ {
+ aStr.AppendAscii( "..." );
+ while ( aStr.Len() && (_rLayout.GetTextWidth( aStr, 0, aStr.Len() ) > nMaxWidth) )
+ {
+ if ( (nIndex > 1) || (nIndex == aStr.Len()) )
+ nIndex--;
+ aStr.Erase( nIndex, 1 );
+ }
+ }
+
+ if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) )
+ aStr += rOrigStr.GetChar( 0 );
+ }
+ else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
+ {
+ rtl::OUString aPath( rOrigStr );
+ rtl::OUString aAbbreviatedPath;
+ osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
+ aStr = aAbbreviatedPath;
+ }
+ else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
+ {
+ static sal_Char const pSepChars[] = ".";
+ // Letztes Teilstueck ermitteln
+ xub_StrLen nLastContent = aStr.Len();
+ while ( nLastContent )
+ {
+ nLastContent--;
+ if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
+ break;
+ }
+ while ( nLastContent &&
+ ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
+ nLastContent--;
+
+ XubString aLastStr( aStr, nLastContent, aStr.Len() );
+ XubString aTempLastStr1( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
+ aTempLastStr1 += aLastStr;
+ if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.Len() ) > nMaxWidth )
+ aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
+ else
+ {
+ USHORT nFirstContent = 0;
+ while ( nFirstContent < nLastContent )
+ {
+ nFirstContent++;
+ if ( ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
+ break;
+ }
+ while ( (nFirstContent < nLastContent) &&
+ ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
+ nFirstContent++;
+
+ if ( nFirstContent >= nLastContent )
+ aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
+ else
+ {
+ if ( nFirstContent > 4 )
+ nFirstContent = 4;
+ XubString aFirstStr( aStr, 0, nFirstContent );
+ aFirstStr.AppendAscii( "..." );
+ XubString aTempStr = aFirstStr;
+ aTempStr += aLastStr;
+ if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
+ aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
+ else
+ {
+ do
+ {
+ aStr = aTempStr;
+ if( nLastContent > aStr.Len() )
+ nLastContent = aStr.Len();
+ while ( nFirstContent < nLastContent )
+ {
+ nLastContent--;
+ if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
+ break;
+
+ }
+ while ( (nFirstContent < nLastContent) &&
+ ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
+ nLastContent--;
+
+ if ( nFirstContent < nLastContent )
+ {
+ XubString aTempLastStr( aStr, nLastContent, aStr.Len() );
+ aTempStr = aFirstStr;
+ aTempStr += aTempLastStr;
+ if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
+ break;
+ }
+ }
+ while ( nFirstContent < nLastContent );
+ }
+ }
+ }
+ }
+ }
+
+ return aStr;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ USHORT nStyle, MetricVector* pVector, String* pDisplayText )
+{
+ DBG_TRACE( "OutputDevice::DrawCtrlText()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) )
+ return;
+
+ // better get graphics here because ImplDrawMnemonicLine() will not
+ // we need a graphics
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if( nIndex >= rStr.Len() )
+ return;
+ if( (ULONG)nIndex+nLen >= rStr.Len() )
+ nLen = rStr.Len() - nIndex;
+
+ XubString aStr = rStr;
+ xub_StrLen nMnemonicPos = STRING_NOTFOUND;
+
+ long nMnemonicX = 0;
+ long nMnemonicY = 0;
+ long nMnemonicWidth = 0;
+ if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
+ {
+ aStr = GetNonMnemonicString( aStr, nMnemonicPos );
+ if ( nMnemonicPos != STRING_NOTFOUND )
+ {
+ if( nMnemonicPos < nIndex )
+ --nIndex;
+ else if( nLen < STRING_LEN )
+ {
+ if( nMnemonicPos < (nIndex+nLen) )
+ --nLen;
+ DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
+ }
+ BOOL bInvalidPos = FALSE;
+
+ if( nMnemonicPos >= nLen )
+ {
+ // #106952#
+ // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
+ // due to some strange BiDi text editors
+ // ->place the underline behind the string to indicate a failure
+ bInvalidPos = TRUE;
+ nMnemonicPos = nLen-1;
+ }
+
+ sal_Int32* pCaretXArray = (sal_Int32*)alloca( 2 * sizeof(sal_Int32) * nLen );
+ /*BOOL bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
+ long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
+ long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
+ nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
+
+ Point aTempPos( Min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
+ if( bInvalidPos ) // #106952#, place behind the (last) character
+ aTempPos = Point( Max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
+
+ aTempPos += rPos;
+ aTempPos = LogicToPixel( aTempPos );
+ nMnemonicX = mnOutOffX + aTempPos.X();
+ nMnemonicY = mnOutOffY + aTempPos.Y();
+ }
+ }
+
+ if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
+ {
+ Color aOldTextColor;
+ Color aOldTextFillColor;
+ BOOL bRestoreFillColor;
+ BOOL bHighContrastBlack = FALSE;
+ BOOL bHighContrastWhite = FALSE;
+ const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
+ if( rStyleSettings.GetHighContrastMode() )
+ {
+ if( IsBackground() )
+ {
+ Wallpaper aWall = GetBackground();
+ Color aCol = aWall.GetColor();
+ bHighContrastBlack = aCol.IsDark();
+ bHighContrastWhite = aCol.IsBright();
+ }
+ }
+
+ aOldTextColor = GetTextColor();
+ if ( IsTextFillColor() )
+ {
+ bRestoreFillColor = TRUE;
+ aOldTextFillColor = GetTextFillColor();
+ }
+ else
+ bRestoreFillColor = FALSE;
+
+ if( bHighContrastBlack )
+ SetTextColor( COL_GREEN );
+ else if( bHighContrastWhite )
+ SetTextColor( COL_LIGHTGREEN );
+ else
+ SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
+
+ DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
+ if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
+ {
+ if ( nMnemonicPos != STRING_NOTFOUND )
+ ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ }
+ SetTextColor( aOldTextColor );
+ if ( bRestoreFillColor )
+ SetTextFillColor( aOldTextFillColor );
+ }
+ else
+ {
+ DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
+ if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
+ {
+ if ( nMnemonicPos != STRING_NOTFOUND )
+ ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::GetCtrlTextWidth( const String& rStr,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ USHORT nStyle ) const
+{
+ DBG_TRACE( "OutputDevice::GetCtrlTextSize()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( nStyle & TEXT_DRAW_MNEMONIC )
+ {
+ xub_StrLen nMnemonicPos;
+ XubString aStr = GetNonMnemonicString( rStr, nMnemonicPos );
+ if ( nMnemonicPos != STRING_NOTFOUND )
+ {
+ if ( nMnemonicPos < nIndex )
+ nIndex--;
+ else if ( (nLen < STRING_LEN) &&
+ (nMnemonicPos >= nIndex) && (nMnemonicPos < (ULONG)(nIndex+nLen)) )
+ nLen--;
+ }
+ return GetTextWidth( aStr, nIndex, nLen );
+ }
+ else
+ return GetTextWidth( rStr, nIndex, nLen );
+}
+
+// -----------------------------------------------------------------------
+
+String OutputDevice::GetNonMnemonicString( const String& rStr, xub_StrLen& rMnemonicPos )
+{
+ String aStr = rStr;
+ xub_StrLen nLen = aStr.Len();
+ xub_StrLen i = 0;
+
+ rMnemonicPos = STRING_NOTFOUND;
+ while ( i < nLen )
+ {
+ if ( aStr.GetChar( i ) == '~' )
+ {
+ if ( aStr.GetChar( i+1 ) != '~' )
+ {
+ if ( rMnemonicPos == STRING_NOTFOUND )
+ rMnemonicPos = i;
+ aStr.Erase( i, 1 );
+ nLen--;
+ }
+ else
+ {
+ aStr.Erase( i, 1 );
+ nLen--;
+ i++;
+ }
+ }
+ else
+ i++;
+ }
+
+ return aStr;
+}
+
+// -----------------------------------------------------------------------
+
+int OutputDevice::GetDevFontCount() const
+{
+ DBG_TRACE( "OutputDevice::GetDevFontCount()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( !mpGetDevFontList )
+ mpGetDevFontList = mpFontList->GetDevFontList();
+ return mpGetDevFontList->Count();
+}
+
+// -----------------------------------------------------------------------
+
+FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
+{
+ DBG_TRACE( "OutputDevice::GetDevFont()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ FontInfo aFontInfo;
+
+ ImplInitFontList();
+
+ int nCount = GetDevFontCount();
+ if( nDevFontIndex < nCount )
+ {
+ const ImplFontData& rData = *mpGetDevFontList->Get( nDevFontIndex );
+ aFontInfo.SetName( rData.maName );
+ aFontInfo.SetStyleName( rData.maStyleName );
+ aFontInfo.SetCharSet( rData.mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
+ aFontInfo.SetFamily( rData.meFamily );
+ aFontInfo.SetPitch( rData.mePitch );
+ aFontInfo.SetWeight( rData.meWeight );
+ aFontInfo.SetItalic( rData.meItalic );
+ aFontInfo.SetWidthType( rData.meWidthType );
+ if( rData.IsScalable() )
+ aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
+ if( rData.mbDevice )
+ aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
+ }
+
+ return aFontInfo;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::AddTempDevFont( const String& rFileURL, const String& rFontName )
+{
+ DBG_TRACE( "OutputDevice::AddTempDevFont()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ ImplInitFontList();
+
+ if( !mpGraphics && !ImplGetGraphics() )
+ return FALSE;
+
+ bool bRC = mpGraphics->AddTempDevFont( mpFontList, rFileURL, rFontName );
+ if( !bRC )
+ return FALSE;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
+
+ mpFontCache->Invalidate();
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
+{
+ DBG_TRACE( "OutputDevice::GetDevFontSizeCount()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ delete mpGetDevSizeList;
+
+ ImplInitFontList();
+ mpGetDevSizeList = mpFontList->GetDevSizeList( rFont.GetName() );
+ return mpGetDevSizeList->Count();
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const
+{
+ DBG_TRACE( "OutputDevice::GetDevFontSize()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // check range
+ int nCount = GetDevFontSizeCount( rFont );
+ if ( nSizeIndex >= nCount )
+ return Size();
+
+ // when mapping is enabled round to .5 points
+ Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
+ if ( mbMap )
+ {
+ aSize.Height() *= 10;
+ MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
+ aSize = PixelToLogic( aSize, aMap );
+ aSize.Height() += 5;
+ aSize.Height() /= 10;
+ long nRound = aSize.Height() % 5;
+ if ( nRound >= 3 )
+ aSize.Height() += (5-nRound);
+ else
+ aSize.Height() -= nRound;
+ aSize.Height() *= 10;
+ aSize = LogicToPixel( aSize, aMap );
+ aSize = PixelToLogic( aSize );
+ aSize.Height() += 5;
+ aSize.Height() /= 10;
+ }
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::IsFontAvailable( const String& rFontName ) const
+{
+ DBG_TRACE( "OutputDevice::IsFontAvailable()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ ImplDevFontListData* pFound = mpFontList->FindFontFamily( rFontName );
+ return (pFound != NULL);
+}
+
+// -----------------------------------------------------------------------
+
+FontMetric OutputDevice::GetFontMetric() const
+{
+ DBG_TRACE( "OutputDevice::GetFontMetric()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ FontMetric aMetric;
+ if( mbNewFont && !ImplNewFont() )
+ return aMetric;
+
+ ImplFontEntry* pEntry = mpFontEntry;
+ ImplFontMetricData* pMetric = &(pEntry->maMetric);
+
+ // prepare metric
+ aMetric.Font::operator=( maFont );
+
+ // set aMetric with info from font
+ aMetric.SetName( maFont.GetName() );
+ aMetric.SetStyleName( pMetric->maStyleName );
+ aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
+ aMetric.SetCharSet( pMetric->mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
+ aMetric.SetFamily( pMetric->meFamily );
+ aMetric.SetPitch( pMetric->mePitch );
+ aMetric.SetWeight( pMetric->meWeight );
+ aMetric.SetItalic( pMetric->meItalic );
+ aMetric.SetWidthType( pMetric->meWidthType );
+ if ( pEntry->mnOwnOrientation )
+ aMetric.SetOrientation( pEntry->mnOwnOrientation );
+ else
+ aMetric.SetOrientation( pMetric->mnOrientation );
+ if( !pEntry->maMetric.mbKernableFont )
+ aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
+
+ // set remaining metric fields
+ aMetric.mpImplMetric->mnMiscFlags = 0;
+ if( pMetric->mbDevice )
+ aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
+ if( pMetric->mbScalableFont )
+ aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
+ aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
+ aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
+ aMetric.mpImplMetric->mnIntLeading = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
+ aMetric.mpImplMetric->mnExtLeading = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
+ aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
+ aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
+
+#ifdef UNX
+ // backwards compatible line metrics after fixing #i60945#
+ if( (meOutDevType == OUTDEV_VIRDEV)
+ && static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() )
+ aMetric.mpImplMetric->mnExtLeading = 0;
+#endif
+
+ return aMetric;
+}
+
+// -----------------------------------------------------------------------
+
+FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
+{
+ // select font, query metrics, select original font again
+ Font aOldFont = GetFont();
+ const_cast<OutputDevice*>(this)->SetFont( rFont );
+ FontMetric aMetric( GetFontMetric() );
+ const_cast<OutputDevice*>(this)->SetFont( aOldFont );
+ return aMetric;
+}
+
+// -----------------------------------------------------------------------
+
+/** OutputDevice::GetSysFontData
+ *
+ * @param nFallbacklevel Fallback font level (0 = best matching font)
+ *
+ * Retrieve detailed font information in platform independent structure
+ *
+ * @return SystemFontData
+ **/
+SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
+{
+ SystemFontData aSysFontData;
+ aSysFontData.nSize = sizeof(aSysFontData);
+
+ if (!mpGraphics) ImplGetGraphics();
+ if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
+
+ return aSysFontData;
+}
+
+
+// -----------------------------------------------------------------------
+
+/** OutputDevice::GetSysTextLayoutData
+ *
+ * @param rStartPt Start point of the text
+ * @param rStr Text string that will be transformed into layout of glyphs
+ * @param nIndex Position in the string from where layout will be done
+ * @param nLen Length of the string
+ * @param pDXAry Custom layout adjustment data
+ *
+ * Export finalized glyph layout data as platform independent SystemTextLayoutData
+ * (see vcl/inc/vcl/sysdata.hxx)
+ *
+ * Only parameters rStartPt and rStr are mandatory, the rest is optional
+ * (default values will be used)
+ *
+ * @return SystemTextLayoutData
+ **/
+SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen,
+ const sal_Int32* pDXAry) const
+{
+ DBG_TRACE( "OutputDevice::GetSysTextLayoutData()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ SystemTextLayoutData aSysLayoutData;
+ aSysLayoutData.nSize = sizeof(aSysLayoutData);
+ aSysLayoutData.rGlyphData.reserve( 256 );
+
+ if ( mpMetaFile ) {
+ if (pDXAry)
+ mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
+ else
+ mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
+ }
+
+ if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
+
+ SalLayout* rLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
+
+ // setup glyphs
+ Point aPos;
+ sal_GlyphId aGlyphId;
+ int nFallbacklevel = 0;
+ for( int nStart = 0; rLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
+ {
+ // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
+ // ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
+
+ SystemGlyphData aGlyph;
+ aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
+ aGlyph.x = aPos.X();
+ aGlyph.y = aPos.Y();
+ aSysLayoutData.rGlyphData.push_back(aGlyph);
+
+ int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
+ if (nLevel > nFallbacklevel && nLevel < MAX_FALLBACK)
+ nFallbacklevel = nLevel;
+ }
+
+ // Get font data
+ aSysLayoutData.aSysFontData = GetSysFontData(nFallbacklevel);
+ aSysLayoutData.orientation = rLayout->GetOrientation();
+
+ rLayout->Release();
+
+ return aSysLayoutData;
+}
+
+// -----------------------------------------------------------------------
+
+
+long OutputDevice::GetMinKashida() const
+{
+ DBG_TRACE( "OutputDevice::GetMinKashida()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ if( mbNewFont && !ImplNewFont() )
+ return 0;
+
+ ImplFontEntry* pEntry = mpFontEntry;
+ ImplFontMetricData* pMetric = &(pEntry->maMetric);
+ return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
+}
+// -----------------------------------------------------------------------
+
+long OutputDevice::GetMinKashida( const Font& rFont ) const
+{
+ // select font, query Kashida, select original font again
+ Font aOldFont = GetFont();
+ const_cast<OutputDevice*>(this)->SetFont( rFont );
+ long aKashida = GetMinKashida();
+ const_cast<OutputDevice*>(this)->SetFont( aOldFont );
+ return aKashida;
+}
+
+// -----------------------------------------------------------------------
+xub_StrLen OutputDevice::ValidateKashidas ( const String& rTxt,
+ xub_StrLen nIdx, xub_StrLen nLen,
+ xub_StrLen nKashCount,
+ const xub_StrLen* pKashidaPos,
+ xub_StrLen* pKashidaPosDropped ) const
+{
+ // do layout
+ SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
+ if( !pSalLayout )
+ return 0;
+ xub_StrLen nDropped = 0;
+ for( int i = 0; i < nKashCount; ++i )
+ {
+ if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
+ {
+ pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
+ ++nDropped;
+ }
+ }
+ pSalLayout->Release();
+ return nDropped;
+}
+
+
+
+// -----------------------------------------------------------------------
+
+
+// TODO: best is to get rid of this method completely
+ULONG OutputDevice::GetKerningPairCount() const
+{
+ DBG_TRACE( "OutputDevice::GetKerningPairCount()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( mbNewFont && !ImplNewFont() )
+ return 0;
+ if( mbInitFont )
+ ImplInitFont();
+
+ if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
+ return 0;
+
+ // get the kerning pair count from the device layer
+ int nKernPairs = mpGraphics->GetKernPairs( 0, NULL );
+ return nKernPairs;
+}
+
+// -----------------------------------------------------------------------
+
+inline bool CmpKernData( const KerningPair& a, const KerningPair& b )
+{
+ return (a.nChar1 < b.nChar1) || ((a.nChar1 == a.nChar2) && (a.nChar2 < a.nChar2));
+}
+
+// TODO: best is to get rid of this method completely
+void OutputDevice::GetKerningPairs( ULONG nRequestedPairs, KerningPair* pKernPairs ) const
+{
+ DBG_TRACE( "OutputDevice::GetKerningPairs()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if( mbNewFont && !ImplNewFont() )
+ return;
+ if( mbInitFont )
+ ImplInitFont();
+
+ if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
+ return;
+
+ // get the kerning pairs directly from the device layer
+ int nKernPairs = mpGraphics->GetKernPairs( nRequestedPairs, (ImplKernPairData*)pKernPairs );
+
+ // sort kerning pairs
+ std::sort( pKernPairs, pKernPairs+nKernPairs, CmpKernData );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const String& rStr,
+ int nIndex, int nLen, int nBase, MetricVector& rVector )
+{
+ DBG_TRACE( "OutputDevice::GetGlyphBoundRect_CTL()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ rVector.clear();
+
+ if( nLen == STRING_LEN )
+ nLen = rStr.Len() - nIndex;
+
+ Rectangle aRect;
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( !GetTextBoundRect( aRect, rStr, sal::static_int_cast<xub_StrLen>(nBase), sal::static_int_cast<xub_StrLen>(nIndex+i), 1 ) )
+ break;
+ aRect.Move( rOrigin.X(), rOrigin.Y() );
+ rVector.push_back( aRect );
+ }
+
+ return (nLen == (int)rVector.size());
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetTextBoundRect( Rectangle& rRect,
+ const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
+ ULONG nLayoutWidth, const sal_Int32* pDXAry ) const
+{
+ DBG_TRACE( "OutputDevice::GetTextBoundRect()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ BOOL bRet = FALSE;
+ rRect.SetEmpty();
+
+ SalLayout* pSalLayout = NULL;
+ const Point aPoint;
+ // calculate offset when nBase!=nIndex
+ long nXOffset = 0;
+ if( nBase != nIndex )
+ {
+ xub_StrLen nStart = Min( nBase, nIndex );
+ xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
+ pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
+ if( pSalLayout )
+ {
+ nXOffset = pSalLayout->GetTextWidth();
+ nXOffset /= pSalLayout->GetUnitsPerPixel();
+ pSalLayout->Release();
+ // TODO: fix offset calculation for Bidi case
+ if( nBase < nIndex)
+ nXOffset = -nXOffset;
+ }
+ }
+
+ pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
+ Rectangle aPixelRect;
+ if( pSalLayout )
+ {
+ bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
+
+ if( bRet )
+ {
+ int nWidthFactor = pSalLayout->GetUnitsPerPixel();
+
+ if( nWidthFactor > 1 )
+ {
+ double fFactor = 1.0 / nWidthFactor;
+ aPixelRect.Left()
+ = static_cast< long >(aPixelRect.Left() * fFactor);
+ aPixelRect.Right()
+ = static_cast< long >(aPixelRect.Right() * fFactor);
+ aPixelRect.Top()
+ = static_cast< long >(aPixelRect.Top() * fFactor);
+ aPixelRect.Bottom()
+ = static_cast< long >(aPixelRect.Bottom() * fFactor);
+ }
+
+ Point aRotatedOfs( mnTextOffX, mnTextOffY );
+ aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
+ aPixelRect += aRotatedOfs;
+ rRect = PixelToLogic( aPixelRect );
+ if( mbMap )
+ rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
+ }
+
+ pSalLayout->Release();
+ }
+
+ if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
+ return bRet;
+
+ // fall back to bitmap method to get the bounding rectangle,
+ // so we need a monochrome virtual device with matching font
+ VirtualDevice aVDev( 1 );
+ Font aFont( GetFont() );
+ aFont.SetShadow( FALSE );
+ aFont.SetOutline( FALSE );
+ aFont.SetRelief( RELIEF_NONE );
+ aFont.SetOrientation( 0 );
+ aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
+ aVDev.SetFont( aFont );
+ aVDev.SetTextAlign( ALIGN_TOP );
+
+ // layout the text on the virtual device
+ pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
+ if( !pSalLayout )
+ return false;
+
+ // make the bitmap big enough
+ // TODO: use factors when it would get too big
+ long nWidth = pSalLayout->GetTextWidth();
+ long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
+ Point aOffset( nWidth/2, 8 );
+ Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
+ if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
+ return false;
+
+ // draw text in black
+ pSalLayout->DrawBase() = aOffset;
+ aVDev.SetTextColor( Color( COL_BLACK ) );
+ aVDev.SetTextFillColor();
+ aVDev.ImplInitTextColor();
+ aVDev.ImplDrawText( *pSalLayout );
+ pSalLayout->Release();
+
+ // find extents using the bitmap
+ Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
+ BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
+ if( !pAcc )
+ return FALSE;
+ const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const long nW = pAcc->Width();
+ const long nH = pAcc->Height();
+ long nLeft = 0;
+ long nRight = 0;
+
+ // find top left point
+ long nTop = 0;
+ for(; nTop < nH; ++nTop )
+ {
+ for( nLeft = 0; nLeft < nW; ++nLeft )
+ if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
+ break;
+ if( nLeft < nW )
+ break;
+ }
+
+ // find bottom right point
+ long nBottom = nH;
+ while( --nBottom >= nTop )
+ {
+ for( nRight = nW; --nRight >= 0; )
+ if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
+ break;
+ if( nRight >= 0 )
+ break;
+ }
+ if( nRight < nLeft )
+ {
+ long nX = nRight;
+ nRight = nLeft;
+ nLeft = nX;
+ }
+
+ for( long nY = nTop; nY <= nBottom; ++nY )
+ {
+ // find leftmost point
+ long nX;
+ for( nX = 0; nX < nLeft; ++nX )
+ if( pAcc->GetPixel( nY, nX ) == aBlack )
+ break;
+ nLeft = nX;
+
+ // find rightmost point
+ for( nX = nW; --nX > nRight; )
+ if( pAcc->GetPixel( nY, nX ) == aBlack )
+ break;
+ nRight = nX;
+ }
+
+ aBmp.ReleaseAccess( pAcc );
+
+ if( nTop <= nBottom )
+ {
+ Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
+ Point aTopLeft( nLeft, nTop );
+ aTopLeft -= aOffset;
+ // adjust to text alignment
+ aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
+ // convert to logical coordinates
+ aSize = PixelToLogic( aSize );
+ aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
+ aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
+ rRect = Rectangle( aTopLeft, aSize );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
+ const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
+ BOOL bOptimize, ULONG nTWidth, const sal_Int32* pDXArray ) const
+{
+ // the fonts need to be initialized
+ if( mbNewFont )
+ ImplNewFont();
+ if( mbInitFont )
+ ImplInitFont();
+ if( !mpFontEntry )
+ return FALSE;
+
+ BOOL bRet = FALSE;
+ rVector.clear();
+ if( nLen == STRING_LEN )
+ nLen = rStr.Len() - nIndex;
+ rVector.reserve( nLen );
+
+ // we want to get the Rectangle in logical units, so to
+ // avoid rounding errors we just size the font in logical units
+ BOOL bOldMap = mbMap;
+ if( bOldMap )
+ {
+ const_cast<OutputDevice&>(*this).mbMap = FALSE;
+ const_cast<OutputDevice&>(*this).mbNewFont = TRUE;
+ }
+
+ SalLayout* pSalLayout = NULL;
+
+ // calculate offset when nBase!=nIndex
+ long nXOffset = 0;
+ if( nBase != nIndex )
+ {
+ xub_StrLen nStart = Min( nBase, nIndex );
+ xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
+ pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nTWidth, pDXArray );
+ if( pSalLayout )
+ {
+ nXOffset = pSalLayout->GetTextWidth();
+ pSalLayout->Release();
+ // TODO: fix offset calculation for Bidi case
+ if( nBase > nIndex)
+ nXOffset = -nXOffset;
+ }
+ }
+
+ pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
+ if( pSalLayout )
+ {
+ bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
+ if( bRet )
+ {
+ // transform polygon to pixel units
+ ::basegfx::B2DHomMatrix aMatrix;
+
+ int nWidthFactor = pSalLayout->GetUnitsPerPixel();
+ if( nXOffset | mnTextOffX | mnTextOffY )
+ {
+ Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
+ aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
+ aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
+ }
+
+ if( nWidthFactor > 1 )
+ {
+ double fFactor = 1.0 / nWidthFactor;
+ aMatrix.scale( fFactor, fFactor );
+ }
+
+ if( !aMatrix.isIdentity() )
+ {
+ ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
+ for(; aIt != rVector.end(); ++aIt )
+ (*aIt).transform( aMatrix );
+ }
+ }
+
+ pSalLayout->Release();
+ }
+
+ if( bOldMap )
+ {
+ // restore original font size and map mode
+ const_cast<OutputDevice&>(*this).mbMap = bOldMap;
+ const_cast<OutputDevice&>(*this).mbNewFont = TRUE;
+ }
+
+ if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
+ return bRet;
+
+ // fall back to bitmap conversion ------------------------------------------
+
+ // Here, we can savely assume that the mapping between characters and glyphs
+ // is one-to-one. This is most probably valid for the old bitmap fonts.
+
+ // fall back to bitmap method to get the bounding rectangle,
+ // so we need a monochrome virtual device with matching font
+ pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
+ if (pSalLayout == 0)
+ return false;
+ long nOrgWidth = pSalLayout->GetTextWidth();
+ long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
+ + mnEmphasisDescent;
+ pSalLayout->Release();
+
+ VirtualDevice aVDev(1);
+
+ Font aFont(GetFont());
+ aFont.SetShadow(false);
+ aFont.SetOutline(false);
+ aFont.SetRelief(RELIEF_NONE);
+ aFont.SetOrientation(0);
+ if( bOptimize )
+ {
+ aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
+ aVDev.SetMapMode( MAP_PIXEL );
+ }
+ aVDev.SetFont( aFont );
+ aVDev.SetTextAlign( ALIGN_TOP );
+ aVDev.SetTextColor( Color(COL_BLACK) );
+ aVDev.SetTextFillColor();
+
+ pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
+ if (pSalLayout == 0)
+ return false;
+ long nWidth = pSalLayout->GetTextWidth();
+ long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
+ + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
+ pSalLayout->Release();
+
+ if( !nWidth || !nHeight )
+ return TRUE;
+ double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
+ double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
+
+ // calculate offset when nBase!=nIndex
+ // TODO: fix offset calculation for Bidi case
+ nXOffset = 0;
+ if( nBase != nIndex )
+ {
+ xub_StrLen nStart = ((nBase < nIndex) ? nBase : nIndex);
+ xub_StrLen nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
+ pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nTWidth, pDXArray );
+ if( pSalLayout )
+ {
+ nXOffset = pSalLayout->GetTextWidth();
+ pSalLayout->Release();
+ if( nBase > nIndex)
+ nXOffset = -nXOffset;
+ }
+ }
+
+ bRet = true;
+ bool bRTL = false;
+ String aStr( rStr ); // prepare for e.g. localized digits
+ ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
+ for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
+ {
+ bool bSuccess = false;
+
+ // draw character into virtual device
+ pSalLayout = aVDev.ImplLayout( rStr, static_cast< xub_StrLen >(nCharPos), 1, Point(0,0), nTWidth, pDXArray );
+ if (pSalLayout == 0)
+ return false;
+ long nCharWidth = pSalLayout->GetTextWidth();
+
+ Point aOffset(nCharWidth / 2, 8);
+ Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
+ bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
+ if( bSuccess )
+ {
+ // draw glyph into virtual device
+ aVDev.Erase();
+ pSalLayout->DrawBase() += aOffset;
+ pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
+ pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
+ pSalLayout->Release();
+
+ // convert character image into outline
+ Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
+
+ PolyPolygon aPolyPoly;
+ bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
+ if( !bVectorized )
+ bSuccess = false;
+ else
+ {
+ // convert units to logical width
+ for (USHORT j = 0; j < aPolyPoly.Count(); ++j)
+ {
+ Polygon& rPoly = aPolyPoly[j];
+ for (USHORT k = 0; k < rPoly.GetSize(); ++k)
+ {
+ Point& rPt = rPoly[k];
+ rPt -= aOffset;
+ int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
+ int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
+ rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
+ rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
+ }
+ }
+
+
+ // ignore "empty" glyphs:
+ if( aPolyPoly.Count() > 0 )
+ {
+ // convert to B2DPolyPolygon
+ // TODO: get rid of intermediate tool's PolyPolygon
+ ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
+ ::basegfx::B2DHomMatrix aMatrix;
+ aMatrix.scale( fScaleX, fScaleY );
+ int nAngle = GetFont().GetOrientation();
+ if( nAngle )
+ aMatrix.rotate( nAngle * F_PI1800 );
+ aB2DPolyPoly.transform( aMatrix );
+ rVector.push_back( aB2DPolyPoly );
+ }
+ }
+ }
+
+ nXOffset += nCharWidth;
+ bRet = bRet && bSuccess;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
+ const String& rStr, xub_StrLen nBase, xub_StrLen nIndex,
+ xub_StrLen nLen, BOOL bOptimize, ULONG nTWidth, const sal_Int32* pDXArray ) const
+{
+ rResultVector.clear();
+
+ // get the basegfx polypolygon vector
+ ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
+ if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
+ bOptimize, nTWidth, pDXArray ) )
+ return FALSE;
+
+ // convert to a tool polypolygon vector
+ rResultVector.reserve( aB2DPolyPolyVector.size() );
+ ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
+ for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
+ rResultVector.push_back(PolyPolygon(*aIt)); // #i76339#
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly,
+ const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
+ BOOL bOptimize, ULONG nTWidth, const sal_Int32* pDXArray ) const
+{
+ rPolyPoly.Clear();
+
+ // get the basegfx polypolygon vector
+ ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
+ if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
+ bOptimize, nTWidth, pDXArray ) )
+ return FALSE;
+
+ // convert and merge into a tool polypolygon
+ ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
+ for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
+ for( unsigned int i = 0; i < aIt->count(); ++i )
+ rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const
+{
+ rFontCharMap.Reset();
+
+ // we need a graphics
+ if( !mpGraphics && !ImplGetGraphics() )
+ return FALSE;
+
+ if( mbNewFont )
+ ImplNewFont();
+ if( mbInitFont )
+ ImplInitFont();
+ if( !mpFontEntry )
+ return FALSE;
+
+ // a little font charmap cache helps considerably
+ static const int NMAXITEMS = 16;
+ static int nUsedItems = 0, nCurItem = 0;
+
+ struct CharMapCacheItem { const ImplFontData* mpFontData; FontCharMap maCharMap; };
+ static CharMapCacheItem aCache[ NMAXITEMS ];
+
+ const ImplFontData* pFontData = mpFontEntry->maFontSelData.mpFontData;
+
+ int i;
+ for( i = nUsedItems; --i >= 0; )
+ if( pFontData == aCache[i].mpFontData )
+ break;
+ if( i >= 0 ) // found in cache
+ {
+ rFontCharMap.Reset( aCache[i].maCharMap.mpImpl );
+ }
+ else // need to cache
+ {
+ ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap();
+ rFontCharMap.Reset( pNewMap );
+
+ // manage cache round-robin and insert data
+ CharMapCacheItem& rItem = aCache[ nCurItem ];
+ rItem.mpFontData = pFontData;
+ rItem.maCharMap.Reset( pNewMap );
+
+ if( ++nCurItem >= NMAXITEMS )
+ nCurItem = 0;
+
+ if( ++nUsedItems >= NMAXITEMS )
+ nUsedItems = NMAXITEMS;
+ }
+
+ if( rFontCharMap.IsDefaultMap() )
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+xub_StrLen OutputDevice::HasGlyphs( const Font& rTempFont, const String& rStr,
+ xub_StrLen nIndex, xub_StrLen nLen ) const
+{
+ if( nIndex >= rStr.Len() )
+ return nIndex;
+ xub_StrLen nEnd = nIndex + nLen;
+ if( (ULONG)nIndex+nLen > rStr.Len() )
+ nEnd = rStr.Len();
+
+ DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
+ DBG_ASSERT( nEnd <= rStr.Len(), "String too short" );
+
+ // to get the map temporarily set font
+ const Font aOrigFont = GetFont();
+ const_cast<OutputDevice&>(*this).SetFont( rTempFont );
+ FontCharMap aFontCharMap;
+ BOOL bRet = GetFontCharMap( aFontCharMap );
+ const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
+
+ // if fontmap is unknown assume it doesn't have the glyphs
+ if( bRet == FALSE )
+ return nIndex;
+
+ const sal_Unicode* pStr = rStr.GetBuffer();
+ for( pStr += nIndex; nIndex < nEnd; ++pStr, ++nIndex )
+ if( ! aFontCharMap.HasChar( *pStr ) )
+ return nIndex;
+
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/source/gdi/outdev4.cxx b/vcl/source/gdi/outdev4.cxx
new file mode 100644
index 000000000000..8ad02ed2d818
--- /dev/null
+++ b/vcl/source/gdi/outdev4.cxx
@@ -0,0 +1,1421 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <svsys.h>
+#include <vcl/salgdi.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/outdata.hxx>
+#include <tools/poly.hxx>
+#include <vcl/salbtype.hxx>
+#include <tools/line.hxx>
+#include <vcl/hatch.hxx>
+#include <vcl/window.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/outdev.hxx>
+
+#include "pdfwriter_impl.hxx"
+#include "vcl/window.h"
+#include "vcl/salframe.hxx"
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define HATCH_MAXPOINTS 1024
+#define GRADIENT_DEFAULT_STEPCOUNT 0
+
+// ----------------
+// - Cmp-Function -
+// ----------------
+
+extern "C" int __LOADONCALLAPI ImplHatchCmpFnc( const void* p1, const void* p2 )
+{
+ const long nX1 = ( (Point*) p1 )->X();
+ const long nX2 = ( (Point*) p2 )->X();
+ const long nY1 = ( (Point*) p1 )->Y();
+ const long nY2 = ( (Point*) p2 )->Y();
+
+ return ( nX1 > nX2 ? 1 : nX1 == nX2 ? nY1 > nY2 ? 1: nY1 == nY2 ? 0 : -1 : -1 );
+}
+
+// =======================================================================
+
+DBG_NAMEEX( OutputDevice )
+DBG_NAMEEX( Gradient )
+
+// =======================================================================
+
+void OutputDevice::ImplDrawPolygon( const Polygon& rPoly, const PolyPolygon* pClipPolyPoly )
+{
+ if( pClipPolyPoly )
+ ImplDrawPolyPolygon( rPoly, pClipPolyPoly );
+ else
+ {
+ USHORT nPoints = rPoly.GetSize();
+
+ if ( nPoints < 2 )
+ return;
+
+ const SalPoint* pPtAry = (const SalPoint*)rPoly.GetConstPointAry();
+ mpGraphics->DrawPolygon( nPoints, pPtAry, this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawPolyPolygon( const PolyPolygon& rPolyPoly, const PolyPolygon* pClipPolyPoly )
+{
+ PolyPolygon* pPolyPoly;
+
+ if( pClipPolyPoly )
+ {
+ pPolyPoly = new PolyPolygon;
+ rPolyPoly.GetIntersection( *pClipPolyPoly, *pPolyPoly );
+ }
+ else
+ pPolyPoly = (PolyPolygon*) &rPolyPoly;
+
+ if( pPolyPoly->Count() == 1 )
+ {
+ const Polygon rPoly = pPolyPoly->GetObject( 0 );
+ USHORT nSize = rPoly.GetSize();
+
+ if( nSize >= 2 )
+ {
+ const SalPoint* pPtAry = (const SalPoint*)rPoly.GetConstPointAry();
+ mpGraphics->DrawPolygon( nSize, pPtAry, this );
+ }
+ }
+ else if( pPolyPoly->Count() )
+ {
+ USHORT nCount = pPolyPoly->Count();
+ sal_uInt32* pPointAry = new sal_uInt32[nCount];
+ PCONSTSALPOINT* pPointAryAry = new PCONSTSALPOINT[nCount];
+ USHORT i = 0;
+ do
+ {
+ const Polygon& rPoly = pPolyPoly->GetObject( i );
+ USHORT nSize = rPoly.GetSize();
+ if ( nSize )
+ {
+ pPointAry[i] = nSize;
+ pPointAryAry[i] = (PCONSTSALPOINT)rPoly.GetConstPointAry();
+ i++;
+ }
+ else
+ nCount--;
+ }
+ while( i < nCount );
+
+ if( nCount == 1 )
+ mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this );
+ else
+ mpGraphics->DrawPolyPolygon( nCount, pPointAry, pPointAryAry, this );
+
+ delete[] pPointAry;
+ delete[] pPointAryAry;
+ }
+
+ if( pClipPolyPoly )
+ delete pPolyPoly;
+}
+
+// -----------------------------------------------------------------------
+
+inline UINT8 ImplGetGradientColorValue( long nValue )
+{
+ if ( nValue < 0 )
+ return 0;
+ else if ( nValue > 0xFF )
+ return 0xFF;
+ else
+ return (UINT8)nValue;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect,
+ const Gradient& rGradient,
+ BOOL bMtf, const PolyPolygon* pClipPolyPoly )
+{
+ // rotiertes BoundRect ausrechnen
+ Rectangle aRect = rRect;
+ aRect.Left()--;
+ aRect.Top()--;
+ aRect.Right()++;
+ aRect.Bottom()++;
+ USHORT nAngle = rGradient.GetAngle() % 3600;
+ double fAngle = nAngle * F_PI1800;
+ double fWidth = aRect.GetWidth();
+ double fHeight = aRect.GetHeight();
+ double fDX = fWidth * fabs( cos( fAngle ) ) +
+ fHeight * fabs( sin( fAngle ) );
+ double fDY = fHeight * fabs( cos( fAngle ) ) +
+ fWidth * fabs( sin( fAngle ) );
+ fDX = (fDX - fWidth) * 0.5 + 0.5;
+ fDY = (fDY - fHeight) * 0.5 + 0.5;
+ aRect.Left() -= (long)fDX;
+ aRect.Right() += (long)fDX;
+ aRect.Top() -= (long)fDY;
+ aRect.Bottom() += (long)fDY;
+
+ // Rand berechnen und Rechteck neu setzen
+ Point aCenter = rRect.Center();
+ Rectangle aFullRect = aRect;
+ long nBorder = (long)rGradient.GetBorder() * aRect.GetHeight() / 100;
+ BOOL bLinear;
+
+ // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
+ if ( rGradient.GetStyle() == GRADIENT_LINEAR )
+ {
+ bLinear = TRUE;
+ aRect.Top() += nBorder;
+ }
+ // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
+ else
+ {
+ bLinear = FALSE;
+ nBorder >>= 1;
+
+ aRect.Top() += nBorder;
+ aRect.Bottom() -= nBorder;
+ }
+
+ // Top darf nicht groesser als Bottom sein
+ aRect.Top() = Min( aRect.Top(), (long)(aRect.Bottom() - 1) );
+
+ long nMinRect = aRect.GetHeight();
+
+ // Intensitaeten von Start- und Endfarbe ggf. aendern und
+ // Farbschrittweiten berechnen
+ long nFactor;
+ Color aStartCol = rGradient.GetStartColor();
+ Color aEndCol = rGradient.GetEndColor();
+ long nStartRed = aStartCol.GetRed();
+ long nStartGreen = aStartCol.GetGreen();
+ long nStartBlue = aStartCol.GetBlue();
+ long nEndRed = aEndCol.GetRed();
+ long nEndGreen = aEndCol.GetGreen();
+ long nEndBlue = aEndCol.GetBlue();
+ nFactor = rGradient.GetStartIntensity();
+ nStartRed = (nStartRed * nFactor) / 100;
+ nStartGreen = (nStartGreen * nFactor) / 100;
+ nStartBlue = (nStartBlue * nFactor) / 100;
+ nFactor = rGradient.GetEndIntensity();
+ nEndRed = (nEndRed * nFactor) / 100;
+ nEndGreen = (nEndGreen * nFactor) / 100;
+ nEndBlue = (nEndBlue * nFactor) / 100;
+ long nRedSteps = nEndRed - nStartRed;
+ long nGreenSteps = nEndGreen - nStartGreen;
+ long nBlueSteps = nEndBlue - nStartBlue;
+ long nStepCount = rGradient.GetSteps();
+
+ // Bei nicht linearen Farbverlaeufen haben wir nur die halben Steps
+ // pro Farbe
+ if ( !bLinear )
+ {
+ nRedSteps <<= 1;
+ nGreenSteps <<= 1;
+ nBlueSteps <<= 1;
+ }
+
+ // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
+ if ( !nStepCount )
+ {
+ long nInc;
+
+ if ( meOutDevType != OUTDEV_PRINTER && !bMtf )
+ {
+ nInc = (nMinRect < 50) ? 2 : 4;
+ }
+ else
+ {
+ // #105998# Use display-equivalent step size calculation
+ nInc = (nMinRect < 800) ? 10 : 20;
+ }
+
+ if ( !nInc )
+ nInc = 1;
+
+ nStepCount = nMinRect / nInc;
+ }
+ // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
+ long nSteps = Max( nStepCount, 2L );
+ long nCalcSteps = Abs( nRedSteps );
+ long nTempSteps = Abs( nGreenSteps );
+ if ( nTempSteps > nCalcSteps )
+ nCalcSteps = nTempSteps;
+ nTempSteps = Abs( nBlueSteps );
+ if ( nTempSteps > nCalcSteps )
+ nCalcSteps = nTempSteps;
+ if ( nCalcSteps < nSteps )
+ nSteps = nCalcSteps;
+ if ( !nSteps )
+ nSteps = 1;
+
+ // Falls axialer Farbverlauf, muss die Schrittanzahl ungerade sein
+ if ( !bLinear && !(nSteps & 1) )
+ nSteps++;
+
+ // Berechnung ueber Double-Addition wegen Genauigkeit
+ double fScanLine = aRect.Top();
+ double fScanInc = (double)aRect.GetHeight() / (double)nSteps;
+
+ // Startfarbe berechnen und setzen
+ UINT8 nRed;
+ UINT8 nGreen;
+ UINT8 nBlue;
+ long nSteps2;
+ long nStepsHalf = 0;
+ if ( bLinear )
+ {
+ // Um 1 erhoeht, um die Border innerhalb der Schleife
+ // zeichnen zu koennen
+ nSteps2 = nSteps + 1;
+ nRed = (UINT8)nStartRed;
+ nGreen = (UINT8)nStartGreen;
+ nBlue = (UINT8)nStartBlue;
+ }
+ else
+ {
+ // Um 2 erhoeht, um die Border innerhalb der Schleife
+ // zeichnen zu koennen
+ nSteps2 = nSteps + 2;
+ nRed = (UINT8)nEndRed;
+ nGreen = (UINT8)nEndGreen;
+ nBlue = (UINT8)nEndBlue;
+ nStepsHalf = nSteps >> 1;
+ }
+
+ if ( bMtf )
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) );
+ else
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+ // Startpolygon erzeugen (== Borderpolygon)
+ Polygon aPoly( 4 );
+ Polygon aTempPoly( 2 );
+ aPoly[0] = aFullRect.TopLeft();
+ aPoly[1] = aFullRect.TopRight();
+ aPoly[2] = aRect.TopRight();
+ aPoly[3] = aRect.TopLeft();
+ aPoly.Rotate( aCenter, nAngle );
+
+ // Schleife, um rotierten Verlauf zu fuellen
+ for ( long i = 0; i < nSteps2; i++ )
+ {
+ // berechnetesPolygon ausgeben
+ if ( bMtf )
+ mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+ else
+ ImplDrawPolygon( aPoly, pClipPolyPoly );
+
+ // neues Polygon berechnen
+ aRect.Top() = (long)(fScanLine += fScanInc);
+
+ // unteren Rand komplett fuellen
+ if ( i == nSteps )
+ {
+ aTempPoly[0] = aFullRect.BottomLeft();
+ aTempPoly[1] = aFullRect.BottomRight();
+ }
+ else
+ {
+ aTempPoly[0] = aRect.TopLeft();
+ aTempPoly[1] = aRect.TopRight();
+ }
+ aTempPoly.Rotate( aCenter, nAngle );
+
+ aPoly[0] = aPoly[3];
+ aPoly[1] = aPoly[2];
+ aPoly[2] = aTempPoly[1];
+ aPoly[3] = aTempPoly[0];
+
+ // Farbintensitaeten aendern...
+ // fuer lineare FV
+ if ( bLinear )
+ {
+ nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i)/nSteps2) );
+ nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i)/nSteps2) );
+ nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i)/nSteps2) );
+ }
+ // fuer radiale FV
+ else
+ {
+ // fuer axiale FV muss die letzte Farbe der ersten
+ // Farbe entsprechen
+ // #107350# Setting end color one step earlier, as the
+ // last time we get here, we drop out of the loop later
+ // on.
+ if ( i >= nSteps )
+ {
+ nRed = (UINT8)nEndRed;
+ nGreen = (UINT8)nEndGreen;
+ nBlue = (UINT8)nEndBlue;
+ }
+ else
+ {
+ if ( i <= nStepsHalf )
+ {
+ nRed = ImplGetGradientColorValue( nEndRed-((nRedSteps*i)/nSteps2) );
+ nGreen = ImplGetGradientColorValue( nEndGreen-((nGreenSteps*i)/nSteps2) );
+ nBlue = ImplGetGradientColorValue( nEndBlue-((nBlueSteps*i)/nSteps2) );
+ }
+ // genau die Mitte und hoeher
+ else
+ {
+ long i2 = i - nStepsHalf;
+ nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i2)/nSteps2) );
+ nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i2)/nSteps2) );
+ nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i2)/nSteps2) );
+ }
+ }
+ }
+
+ if ( bMtf )
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) );
+ else
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect,
+ const Gradient& rGradient,
+ BOOL bMtf, const PolyPolygon* pClipPolyPoly )
+{
+ // Feststellen ob Ausgabe ueber Polygon oder PolyPolygon
+ // Bei Rasteroperationen ungleich Overpaint immer PolyPolygone,
+ // da es zu falschen Ergebnissen kommt, wenn man mehrfach uebereinander
+ // ausgibt
+ // Bei Druckern auch immer PolyPolygone, da nicht alle Drucker
+ // das Uebereinanderdrucken von Polygonen koennen
+ // Virtuelle Device werden auch ausgeklammert, da einige Treiber
+ // ansonsten zu langsam sind
+ PolyPolygon* pPolyPoly;
+ Rectangle aRect( rRect );
+ Color aStartCol( rGradient.GetStartColor() );
+ Color aEndCol( rGradient.GetEndColor() );
+ long nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100;
+ long nStartGreen = ( (long) aStartCol.GetGreen() * rGradient.GetStartIntensity() ) / 100;
+ long nStartBlue = ( (long) aStartCol.GetBlue() * rGradient.GetStartIntensity() ) / 100;
+ long nEndRed = ( (long) aEndCol.GetRed() * rGradient.GetEndIntensity() ) / 100;
+ long nEndGreen = ( (long) aEndCol.GetGreen() * rGradient.GetEndIntensity() ) / 100;
+ long nEndBlue = ( (long) aEndCol.GetBlue() * rGradient.GetEndIntensity() ) / 100;
+ long nRedSteps = nEndRed - nStartRed;
+ long nGreenSteps = nEndGreen - nStartGreen;
+ long nBlueSteps = nEndBlue - nStartBlue;
+ long nStepCount = rGradient.GetSteps();
+ USHORT nAngle = rGradient.GetAngle() % 3600;
+
+ if( (meRasterOp != ROP_OVERPAINT) || (meOutDevType != OUTDEV_WINDOW) || bMtf )
+ pPolyPoly = new PolyPolygon( 2 );
+ else
+ pPolyPoly = NULL;
+
+ if( rGradient.GetStyle() == GRADIENT_SQUARE || rGradient.GetStyle() == GRADIENT_RECT )
+ {
+ const double fAngle = nAngle * F_PI1800;
+ const double fWidth = aRect.GetWidth();
+ const double fHeight = aRect.GetHeight();
+ double fDX = fWidth * fabs( cos( fAngle ) ) + fHeight * fabs( sin( fAngle ) );
+ double fDY = fHeight * fabs( cos( fAngle ) ) + fWidth * fabs( sin( fAngle ) );
+
+ fDX = ( fDX - fWidth ) * 0.5 + 0.5;
+ fDY = ( fDY - fHeight ) * 0.5 + 0.5;
+
+ aRect.Left() -= (long) fDX;
+ aRect.Right() += (long) fDX;
+ aRect.Top() -= (long) fDY;
+ aRect.Bottom() += (long) fDY;
+ }
+
+ Size aSize( aRect.GetSize() );
+
+ if( rGradient.GetStyle() == GRADIENT_RADIAL )
+ {
+ // Radien-Berechnung fuer Kreis
+ aSize.Width() = (long)(0.5 + sqrt((double)aSize.Width()*(double)aSize.Width() + (double)aSize.Height()*(double)aSize.Height()));
+ aSize.Height() = aSize.Width();
+ }
+ else if( rGradient.GetStyle() == GRADIENT_ELLIPTICAL )
+ {
+ // Radien-Berechnung fuer Ellipse
+ aSize.Width() = (long)( 0.5 + (double) aSize.Width() * 1.4142 );
+ aSize.Height() = (long)( 0.5 + (double) aSize.Height() * 1.4142 );
+ }
+ else if( rGradient.GetStyle() == GRADIENT_SQUARE )
+ {
+ if ( aSize.Width() > aSize.Height() )
+ aSize.Height() = aSize.Width();
+ else
+ aSize.Width() = aSize.Height();
+ }
+
+ // neue Mittelpunkte berechnen
+ long nZWidth = aRect.GetWidth() * (long) rGradient.GetOfsX() / 100;
+ long nZHeight = aRect.GetHeight() * (long) rGradient.GetOfsY() / 100;
+ long nBorderX = (long) rGradient.GetBorder() * aSize.Width() / 100;
+ long nBorderY = (long) rGradient.GetBorder() * aSize.Height() / 100;
+ Point aCenter( aRect.Left() + nZWidth, aRect.Top() + nZHeight );
+
+ // Rand beruecksichtigen
+ aSize.Width() -= nBorderX;
+ aSize.Height() -= nBorderY;
+
+ // Ausgaberechteck neu setzen
+ aRect.Left() = aCenter.X() - ( aSize.Width() >> 1 );
+ aRect.Top() = aCenter.Y() - ( aSize.Height() >> 1 );
+
+ aRect.SetSize( aSize );
+ long nMinRect = Min( aRect.GetWidth(), aRect.GetHeight() );
+
+ // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
+ if( !nStepCount )
+ {
+ long nInc;
+
+ if ( meOutDevType != OUTDEV_PRINTER && !bMtf )
+ {
+ nInc = ( nMinRect < 50 ) ? 2 : 4;
+ }
+ else
+ {
+ // #105998# Use display-equivalent step size calculation
+ nInc = (nMinRect < 800) ? 10 : 20;
+ }
+
+ if( !nInc )
+ nInc = 1;
+
+ nStepCount = nMinRect / nInc;
+ }
+
+ // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
+ long nSteps = Max( nStepCount, 2L );
+ long nCalcSteps = Abs( nRedSteps );
+ long nTempSteps = Abs( nGreenSteps );
+ if ( nTempSteps > nCalcSteps )
+ nCalcSteps = nTempSteps;
+ nTempSteps = Abs( nBlueSteps );
+ if ( nTempSteps > nCalcSteps )
+ nCalcSteps = nTempSteps;
+ if ( nCalcSteps < nSteps )
+ nSteps = nCalcSteps;
+ if ( !nSteps )
+ nSteps = 1;
+
+ // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen
+ Polygon aPoly;
+ double fScanLeft = aRect.Left();
+ double fScanTop = aRect.Top();
+ double fScanRight = aRect.Right();
+ double fScanBottom = aRect.Bottom();
+ double fScanInc = (double) nMinRect / (double) nSteps * 0.5;
+ UINT8 nRed = (UINT8) nStartRed, nGreen = (UINT8) nStartGreen, nBlue = (UINT8) nStartBlue;
+ bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
+
+ if( bMtf )
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) );
+ else
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+ if( pPolyPoly )
+ {
+ pPolyPoly->Insert( aPoly = rRect );
+ pPolyPoly->Insert( aPoly );
+ }
+ else
+ {
+ // extend rect, to avoid missing bounding line
+ Rectangle aExtRect( rRect );
+
+ aExtRect.Left() -= 1;
+ aExtRect.Top() -= 1;
+ aExtRect.Right() += 1;
+ aExtRect.Bottom() += 1;
+
+ ImplDrawPolygon( aPoly = aExtRect, pClipPolyPoly );
+ }
+
+ // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben
+ for( long i = 1; i < nSteps; i++ )
+ {
+ // neues Polygon berechnen
+ aRect.Left() = (long)( fScanLeft += fScanInc );
+ aRect.Top() = (long)( fScanTop += fScanInc );
+ aRect.Right() = (long)( fScanRight -= fScanInc );
+ aRect.Bottom() = (long)( fScanBottom -= fScanInc );
+
+ if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
+ break;
+
+ if( rGradient.GetStyle() == GRADIENT_RADIAL || rGradient.GetStyle() == GRADIENT_ELLIPTICAL )
+ aPoly = Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
+ else
+ aPoly = Polygon( aRect );
+
+ aPoly.Rotate( aCenter, nAngle );
+
+ // Farbe entsprechend anpassen
+ const long nStepIndex = ( ( pPolyPoly != NULL ) ? i : ( i + 1 ) );
+ nRed = ImplGetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
+ nGreen = ImplGetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
+ nBlue = ImplGetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
+
+ // entweder langsame PolyPolygon-Ausgaben oder schnelles Polygon-Painting
+ if( pPolyPoly )
+ {
+ bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
+
+ pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 );
+ pPolyPoly->Replace( aPoly, 1 );
+
+ if( bMtf )
+ mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) );
+ else
+ ImplDrawPolyPolygon( *pPolyPoly, pClipPolyPoly );
+
+ // #107349# Set fill color _after_ geometry painting:
+ // pPolyPoly's geometry is the band from last iteration's
+ // aPoly to current iteration's aPoly. The window outdev
+ // path (see else below), on the other hand, paints the
+ // full aPoly. Thus, here, we're painting the band before
+ // the one painted in the window outdev path below. To get
+ // matching colors, have to delay color setting here.
+ if( bMtf )
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) );
+ else
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+ }
+ else
+ {
+ // #107349# Set fill color _before_ geometry painting
+ if( bMtf )
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) );
+ else
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+ ImplDrawPolygon( aPoly, pClipPolyPoly );
+ }
+ }
+
+ // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes inneres Polygon zeichnen
+ if( pPolyPoly )
+ {
+ const Polygon& rPoly = pPolyPoly->GetObject( 1 );
+
+ if( !rPoly.GetBoundRect().IsEmpty() )
+ {
+ // #107349# Paint last polygon with end color only if loop
+ // has generated output. Otherwise, the current
+ // (i.e. start) color is taken, to generate _any_ output.
+ if( bPaintLastPolygon )
+ {
+ nRed = ImplGetGradientColorValue( nEndRed );
+ nGreen = ImplGetGradientColorValue( nEndGreen );
+ nBlue = ImplGetGradientColorValue( nEndBlue );
+ }
+
+ if( bMtf )
+ {
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) );
+ mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
+ }
+ else
+ {
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+ ImplDrawPolygon( rPoly, pClipPolyPoly );
+ }
+ }
+
+ delete pPolyPoly;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawGradient( const Rectangle& rRect,
+ const Gradient& rGradient )
+{
+ DBG_TRACE( "OutputDevice::DrawGradient()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rGradient, Gradient, NULL );
+
+ if ( mnDrawMode & DRAWMODE_NOGRADIENT )
+ return;
+ else if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) )
+ {
+ Color aColor;
+
+ if ( mnDrawMode & DRAWMODE_BLACKGRADIENT )
+ aColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITEGRADIENT )
+ aColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_SETTINGSGRADIENT )
+ aColor = GetSettings().GetStyleSettings().GetWindowColor();
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
+ {
+ aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
+ ( aColor.GetGreen() >> 1 ) | 0x80,
+ ( aColor.GetBlue() >> 1 ) | 0x80 );
+ }
+
+ Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ SetLineColor( aColor );
+ SetFillColor( aColor );
+ DrawRect( rRect );
+ Pop();
+ return;
+ }
+
+ Gradient aGradient( rGradient );
+
+ if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) )
+ {
+ Color aStartCol( aGradient.GetStartColor() );
+ Color aEndCol( aGradient.GetEndColor() );
+
+ if ( mnDrawMode & DRAWMODE_GRAYGRADIENT )
+ {
+ BYTE cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance();
+ aStartCol = Color( cStartLum, cStartLum, cStartLum );
+ aEndCol = Color( cEndLum, cEndLum, cEndLum );
+ }
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
+ {
+ aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80,
+ ( aStartCol.GetGreen() >> 1 ) | 0x80,
+ ( aStartCol.GetBlue() >> 1 ) | 0x80 );
+
+ aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80,
+ ( aEndCol.GetGreen() >> 1 ) | 0x80,
+ ( aEndCol.GetBlue() >> 1 ) | 0x80 );
+ }
+
+ aGradient.SetStartColor( aStartCol );
+ aGradient.SetEndColor( aEndCol );
+ }
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaGradientAction( rRect, aGradient ) );
+
+ if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ // Rechteck in Pixel umrechnen
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+ aRect.Justify();
+
+ // Wenn Rechteck leer ist, brauchen wir nichts machen
+ if ( !aRect.IsEmpty() )
+ {
+ // Clip Region sichern
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( rRect );
+
+ // because we draw with no border line, we have to expand gradient
+ // rect to avoid missing lines on the right and bottom edge
+ aRect.Left()--;
+ aRect.Top()--;
+ aRect.Right()++;
+ aRect.Bottom()++;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( !mbOutputClipped )
+ {
+ // Gradienten werden ohne Umrandung gezeichnet
+ if ( mbLineColor || mbInitLineColor )
+ {
+ mpGraphics->SetLineColor();
+ mbInitLineColor = TRUE;
+ }
+
+ mbInitFillColor = TRUE;
+
+ // calculate step count if neccessary
+ if ( !aGradient.GetSteps() )
+ aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
+
+ if( aGradient.GetStyle() == GRADIENT_LINEAR || aGradient.GetStyle() == GRADIENT_AXIAL )
+ ImplDrawLinearGradient( aRect, aGradient, FALSE, NULL );
+ else
+ ImplDrawComplexGradient( aRect, aGradient, FALSE, NULL );
+ }
+
+ Pop();
+ }
+
+ if( mpAlphaVDev )
+ {
+ // #i32109#: Make gradient area opaque
+ mpAlphaVDev->ImplFillOpaqueRectangle( rRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawGradient( const PolyPolygon& rPolyPoly,
+ const Gradient& rGradient )
+{
+ DBG_TRACE( "OutputDevice::DrawGradient()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rGradient, Gradient, NULL );
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if( mbOutputClipped )
+ return;
+
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return;
+
+ if( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() && !( mnDrawMode & DRAWMODE_NOGRADIENT ) )
+ {
+ if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) )
+ {
+ Color aColor;
+
+ if ( mnDrawMode & DRAWMODE_BLACKGRADIENT )
+ aColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITEGRADIENT )
+ aColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_SETTINGSGRADIENT )
+ aColor = GetSettings().GetStyleSettings().GetWindowColor();
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
+ {
+ aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
+ ( aColor.GetGreen() >> 1 ) | 0x80,
+ ( aColor.GetBlue() >> 1 ) | 0x80 );
+ }
+
+ Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ SetLineColor( aColor );
+ SetFillColor( aColor );
+ DrawPolyPolygon( rPolyPoly );
+ Pop();
+ return;
+ }
+
+ if( mpMetaFile )
+ {
+ const Rectangle aRect( rPolyPoly.GetBoundRect() );
+
+ mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
+ mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
+
+ if( OUTDEV_PRINTER == meOutDevType )
+ {
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( rPolyPoly );
+ DrawGradient( aRect, rGradient );
+ Pop();
+ }
+ else
+ {
+ const BOOL bOldOutput = IsOutputEnabled();
+
+ EnableOutput( FALSE );
+ Push( PUSH_RASTEROP );
+ SetRasterOp( ROP_XOR );
+ DrawGradient( aRect, rGradient );
+ SetFillColor( COL_BLACK );
+ SetRasterOp( ROP_0 );
+ DrawPolyPolygon( rPolyPoly );
+ SetRasterOp( ROP_XOR );
+ DrawGradient( aRect, rGradient );
+ Pop();
+ EnableOutput( bOldOutput );
+ }
+
+ mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
+ }
+
+ if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ Gradient aGradient( rGradient );
+
+ if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) )
+ {
+ Color aStartCol( aGradient.GetStartColor() );
+ Color aEndCol( aGradient.GetEndColor() );
+
+ if ( mnDrawMode & DRAWMODE_GRAYGRADIENT )
+ {
+ BYTE cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance();
+ aStartCol = Color( cStartLum, cStartLum, cStartLum );
+ aEndCol = Color( cEndLum, cEndLum, cEndLum );
+ }
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
+ {
+ aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80,
+ ( aStartCol.GetGreen() >> 1 ) | 0x80,
+ ( aStartCol.GetBlue() >> 1 ) | 0x80 );
+
+ aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80,
+ ( aEndCol.GetGreen() >> 1 ) | 0x80,
+ ( aEndCol.GetBlue() >> 1 ) | 0x80 );
+ }
+
+ aGradient.SetStartColor( aStartCol );
+ aGradient.SetEndColor( aEndCol );
+ }
+
+ if( OUTDEV_PRINTER == meOutDevType || ImplGetSVData()->maGDIData.mbNoXORClipping )
+ {
+ const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
+
+ if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
+ {
+ // Rechteck in Pixel umrechnen
+ Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
+ aRect.Justify();
+
+ // Wenn Rechteck leer ist, brauchen wir nichts machen
+ if ( !aRect.IsEmpty() )
+ {
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if( !mbOutputClipped )
+ {
+ PolyPolygon aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) );
+
+ // Gradienten werden ohne Umrandung gezeichnet
+ if( mbLineColor || mbInitLineColor )
+ {
+ mpGraphics->SetLineColor();
+ mbInitLineColor = TRUE;
+ }
+
+ mbInitFillColor = TRUE;
+
+ // calculate step count if neccessary
+ if ( !aGradient.GetSteps() )
+ aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
+
+ if( aGradient.GetStyle() == GRADIENT_LINEAR || aGradient.GetStyle() == GRADIENT_AXIAL )
+ ImplDrawLinearGradient( aRect, aGradient, FALSE, &aClipPolyPoly );
+ else
+ ImplDrawComplexGradient( aRect, aGradient, FALSE, &aClipPolyPoly );
+ }
+ }
+ }
+ }
+ else
+ {
+ const PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
+ const Rectangle aBoundRect( aPolyPoly.GetBoundRect() );
+ Point aPoint;
+ Rectangle aDstRect( aPoint, GetOutputSizePixel() );
+
+ aDstRect.Intersection( aBoundRect );
+
+ if( OUTDEV_WINDOW == meOutDevType )
+ {
+ const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
+
+ if( !aPaintRgn.IsNull() )
+ aDstRect.Intersection( LogicToPixel( aPaintRgn ).GetBoundRect() );
+ }
+
+ if( !aDstRect.IsEmpty() )
+ {
+ VirtualDevice* pVDev;
+ const Size aDstSize( aDstRect.GetSize() );
+
+ if( HasAlpha() )
+ {
+ // #110958# Pay attention to alpha VDevs here, otherwise,
+ // background will be wrong: Temp VDev has to have alpha, too.
+ pVDev = new VirtualDevice( *this, 0, GetAlphaBitCount() > 1 ? 0 : 1 );
+ }
+ else
+ {
+ // nothing special here. Plain VDev
+ pVDev = new VirtualDevice();
+ }
+
+ if( pVDev->SetOutputSizePixel( aDstSize) )
+ {
+ MapMode aVDevMap;
+ const BOOL bOldMap = mbMap;
+
+ EnableMapMode( FALSE );
+
+ pVDev->DrawOutDev( Point(), aDstSize, aDstRect.TopLeft(), aDstSize, *this );
+ pVDev->SetRasterOp( ROP_XOR );
+ aVDevMap.SetOrigin( Point( -aDstRect.Left(), -aDstRect.Top() ) );
+ pVDev->SetMapMode( aVDevMap );
+ pVDev->DrawGradient( aBoundRect, aGradient );
+ pVDev->SetFillColor( COL_BLACK );
+ pVDev->SetRasterOp( ROP_0 );
+ pVDev->DrawPolyPolygon( aPolyPoly );
+ pVDev->SetRasterOp( ROP_XOR );
+ pVDev->DrawGradient( aBoundRect, aGradient );
+ aVDevMap.SetOrigin( Point() );
+ pVDev->SetMapMode( aVDevMap );
+ DrawOutDev( aDstRect.TopLeft(), aDstSize, Point(), aDstSize, *pVDev );
+
+ EnableMapMode( bOldMap );
+ }
+
+ delete pVDev;
+ }
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::AddGradientActions( const Rectangle& rRect, const Gradient& rGradient,
+ GDIMetaFile& rMtf )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rGradient, Gradient, NULL );
+
+ Rectangle aRect( rRect );
+
+ aRect.Justify();
+
+ // Wenn Rechteck leer ist, brauchen wir nichts machen
+ if ( !aRect.IsEmpty() )
+ {
+ Gradient aGradient( rGradient );
+ GDIMetaFile* pOldMtf = mpMetaFile;
+
+ mpMetaFile = &rMtf;
+ mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) );
+ mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) );
+ mpMetaFile->AddAction( new MetaLineColorAction( Color(), FALSE ) );
+
+ // because we draw with no border line, we have to expand gradient
+ // rect to avoid missing lines on the right and bottom edge
+ aRect.Left()--;
+ aRect.Top()--;
+ aRect.Right()++;
+ aRect.Bottom()++;
+
+ // calculate step count if neccessary
+ if ( !aGradient.GetSteps() )
+ aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
+
+ if( aGradient.GetStyle() == GRADIENT_LINEAR || aGradient.GetStyle() == GRADIENT_AXIAL )
+ ImplDrawLinearGradient( aRect, aGradient, TRUE, NULL );
+ else
+ ImplDrawComplexGradient( aRect, aGradient, TRUE, NULL );
+
+ mpMetaFile->AddAction( new MetaPopAction() );
+ mpMetaFile = pOldMtf;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
+{
+ DBG_TRACE( "OutputDevice::DrawHatch()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Hatch aHatch( rHatch );
+
+ if ( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
+ DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
+ DRAWMODE_SETTINGSLINE ) )
+ {
+ Color aColor( rHatch.GetColor() );
+
+ if ( mnDrawMode & DRAWMODE_BLACKLINE )
+ aColor = Color( COL_BLACK );
+ else if ( mnDrawMode & DRAWMODE_WHITELINE )
+ aColor = Color( COL_WHITE );
+ else if ( mnDrawMode & DRAWMODE_GRAYLINE )
+ {
+ const UINT8 cLum = aColor.GetLuminance();
+ aColor = Color( cLum, cLum, cLum );
+ }
+ else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
+ {
+ aColor = GetSettings().GetStyleSettings().GetFontColor();
+ }
+
+ if ( mnDrawMode & DRAWMODE_GHOSTEDLINE )
+ {
+ aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
+ ( aColor.GetGreen() >> 1 ) | 0x80,
+ ( aColor.GetBlue() >> 1 ) | 0x80);
+ }
+
+ aHatch.SetColor( aColor );
+ }
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaHatchAction( rPolyPoly, aHatch ) );
+
+ if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if( mbOutputClipped )
+ return;
+
+ if( rPolyPoly.Count() )
+ {
+ PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ BOOL bOldMap = mbMap;
+
+ aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME );
+ aHatch.SetDistance( ImplLogicWidthToDevicePixel( aHatch.GetDistance() ) );
+
+ mpMetaFile = NULL;
+ EnableMapMode( FALSE );
+ Push( PUSH_LINECOLOR );
+ SetLineColor( aHatch.GetColor() );
+ ImplInitLineColor();
+ ImplDrawHatch( aPolyPoly, aHatch, FALSE );
+ Pop();
+ EnableMapMode( bOldMap );
+ mpMetaFile = pOldMetaFile;
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawHatch( rPolyPoly, rHatch );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::AddHatchActions( const PolyPolygon& rPolyPoly, const Hatch& rHatch,
+ GDIMetaFile& rMtf )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ PolyPolygon aPolyPoly( rPolyPoly );
+ aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME | POLY_OPTIMIZE_CLOSE );
+
+ if( aPolyPoly.Count() )
+ {
+ GDIMetaFile* pOldMtf = mpMetaFile;
+
+ mpMetaFile = &rMtf;
+ mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) );
+ mpMetaFile->AddAction( new MetaLineColorAction( rHatch.GetColor(), TRUE ) );
+ ImplDrawHatch( aPolyPoly, rHatch, TRUE );
+ mpMetaFile->AddAction( new MetaPopAction() );
+ mpMetaFile = pOldMtf;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch, BOOL bMtf )
+{
+ Rectangle aRect( rPolyPoly.GetBoundRect() );
+ const long nLogPixelWidth = ImplDevicePixelToLogicWidth( 1 );
+ const long nWidth = ImplDevicePixelToLogicWidth( Max( ImplLogicWidthToDevicePixel( rHatch.GetDistance() ), 3L ) );
+ Point* pPtBuffer = new Point[ HATCH_MAXPOINTS ];
+ Point aPt1, aPt2, aEndPt1;
+ Size aInc;
+
+ // Single hatch
+ aRect.Left() -= nLogPixelWidth; aRect.Top() -= nLogPixelWidth; aRect.Right() += nLogPixelWidth; aRect.Bottom() += nLogPixelWidth;
+ ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle(), aPt1, aPt2, aInc, aEndPt1 );
+ do
+ {
+ ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf );
+ aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
+ aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
+ }
+ while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
+
+ if( ( rHatch.GetStyle() == HATCH_DOUBLE ) || ( rHatch.GetStyle() == HATCH_TRIPLE ) )
+ {
+ // Double hatch
+ ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 900, aPt1, aPt2, aInc, aEndPt1 );
+ do
+ {
+ ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf );
+ aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
+ aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
+ }
+ while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
+
+ if( rHatch.GetStyle() == HATCH_TRIPLE )
+ {
+ // Triple hatch
+ ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 450, aPt1, aPt2, aInc, aEndPt1 );
+ do
+ {
+ ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf );
+ aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
+ aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
+ }
+ while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
+ }
+ }
+
+ delete[] pPtBuffer;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplCalcHatchValues( const Rectangle& rRect, long nDist, USHORT nAngle10,
+ Point& rPt1, Point& rPt2, Size& rInc, Point& rEndPt1 )
+{
+ Point aRef;
+ long nAngle = nAngle10 % 1800;
+ long nOffset = 0;
+
+ if( nAngle > 900 )
+ nAngle -= 1800;
+
+ aRef = ( !IsRefPoint() ? rRect.TopLeft() : GetRefPoint() );
+
+ if( 0 == nAngle )
+ {
+ rInc = Size( 0, nDist );
+ rPt1 = rRect.TopLeft();
+ rPt2 = rRect.TopRight();
+ rEndPt1 = rRect.BottomLeft();
+
+ if( aRef.Y() <= rRect.Top() )
+ nOffset = ( ( rRect.Top() - aRef.Y() ) % nDist );
+ else
+ nOffset = ( nDist - ( ( aRef.Y() - rRect.Top() ) % nDist ) );
+
+ rPt1.Y() -= nOffset;
+ rPt2.Y() -= nOffset;
+ }
+ else if( 900 == nAngle )
+ {
+ rInc = Size( nDist, 0 );
+ rPt1 = rRect.TopLeft();
+ rPt2 = rRect.BottomLeft();
+ rEndPt1 = rRect.TopRight();
+
+ if( aRef.X() <= rRect.Left() )
+ nOffset = ( rRect.Left() - aRef.X() ) % nDist;
+ else
+ nOffset = nDist - ( ( aRef.X() - rRect.Left() ) % nDist );
+
+ rPt1.X() -= nOffset;
+ rPt2.X() -= nOffset;
+ }
+ else if( nAngle >= -450 && nAngle <= 450 )
+ {
+ const double fAngle = F_PI1800 * labs( nAngle );
+ const double fTan = tan( fAngle );
+ const long nYOff = FRound( ( rRect.Right() - rRect.Left() ) * fTan );
+ long nPY;
+
+ rInc = Size( 0, nDist = FRound( nDist / cos( fAngle ) ) );
+
+ if( nAngle > 0 )
+ {
+ rPt1 = rRect.TopLeft();
+ rPt2 = Point( rRect.Right(), rRect.Top() - nYOff );
+ rEndPt1 = Point( rRect.Left(), rRect.Bottom() + nYOff );
+ nPY = FRound( aRef.Y() - ( ( rPt1.X() - aRef.X() ) * fTan ) );
+ }
+ else
+ {
+ rPt1 = rRect.TopRight();
+ rPt2 = Point( rRect.Left(), rRect.Top() - nYOff );
+ rEndPt1 = Point( rRect.Right(), rRect.Bottom() + nYOff );
+ nPY = FRound( aRef.Y() + ( ( rPt1.X() - aRef.X() ) * fTan ) );
+ }
+
+ if( nPY <= rPt1.Y() )
+ nOffset = ( rPt1.Y() - nPY ) % nDist;
+ else
+ nOffset = nDist - ( ( nPY - rPt1.Y() ) % nDist );
+
+ rPt1.Y() -= nOffset;
+ rPt2.Y() -= nOffset;
+ }
+ else
+ {
+ const double fAngle = F_PI1800 * labs( nAngle );
+ const double fTan = tan( fAngle );
+ const long nXOff = FRound( ( rRect.Bottom() - rRect.Top() ) / fTan );
+ long nPX;
+
+ rInc = Size( nDist = FRound( nDist / sin( fAngle ) ), 0 );
+
+ if( nAngle > 0 )
+ {
+ rPt1 = rRect.TopLeft();
+ rPt2 = Point( rRect.Left() - nXOff, rRect.Bottom() );
+ rEndPt1 = Point( rRect.Right() + nXOff, rRect.Top() );
+ nPX = FRound( aRef.X() - ( ( rPt1.Y() - aRef.Y() ) / fTan ) );
+ }
+ else
+ {
+ rPt1 = rRect.BottomLeft();
+ rPt2 = Point( rRect.Left() - nXOff, rRect.Top() );
+ rEndPt1 = Point( rRect.Right() + nXOff, rRect.Bottom() );
+ nPX = FRound( aRef.X() + ( ( rPt1.Y() - aRef.Y() ) / fTan ) );
+ }
+
+ if( nPX <= rPt1.X() )
+ nOffset = ( rPt1.X() - nPX ) % nDist;
+ else
+ nOffset = nDist - ( ( nPX - rPt1.X() ) % nDist );
+
+ rPt1.X() -= nOffset;
+ rPt2.X() -= nOffset;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void OutputDevice::ImplDrawHatchLine( const Line& rLine, const PolyPolygon& rPolyPoly,
+ Point* pPtBuffer, BOOL bMtf )
+{
+ double fX, fY;
+ long nAdd, nPCounter = 0;
+
+ for( long nPoly = 0, nPolyCount = rPolyPoly.Count(); nPoly < nPolyCount; nPoly++ )
+ {
+ const Polygon& rPoly = rPolyPoly[ (USHORT) nPoly ];
+
+ if( rPoly.GetSize() > 1 )
+ {
+ Line aCurSegment( rPoly[ 0 ], Point() );
+
+ for( long i = 1, nCount = rPoly.GetSize(); i <= nCount; i++ )
+ {
+ aCurSegment.SetEnd( rPoly[ (USHORT)( i % nCount ) ] );
+ nAdd = 0;
+
+ if( rLine.Intersection( aCurSegment, fX, fY ) )
+ {
+ if( ( fabs( fX - aCurSegment.GetStart().X() ) <= 0.0000001 ) &&
+ ( fabs( fY - aCurSegment.GetStart().Y() ) <= 0.0000001 ) )
+ {
+ const Line aPrevSegment( rPoly[ (USHORT)( ( i > 1 ) ? ( i - 2 ) : ( nCount - 1 ) ) ], aCurSegment.GetStart() );
+ const double fPrevDistance = rLine.GetDistance( aPrevSegment.GetStart() );
+ const double fCurDistance = rLine.GetDistance( aCurSegment.GetEnd() );
+
+ if( ( fPrevDistance <= 0.0 && fCurDistance > 0.0 ) ||
+ ( fPrevDistance > 0.0 && fCurDistance < 0.0 ) )
+ {
+ nAdd = 1;
+ }
+ }
+ else if( ( fabs( fX - aCurSegment.GetEnd().X() ) <= 0.0000001 ) &&
+ ( fabs( fY - aCurSegment.GetEnd().Y() ) <= 0.0000001 ) )
+ {
+ const Line aNextSegment( aCurSegment.GetEnd(), rPoly[ (USHORT)( ( i + 1 ) % nCount ) ] );
+
+ if( ( fabs( rLine.GetDistance( aNextSegment.GetEnd() ) ) <= 0.0000001 ) &&
+ ( rLine.GetDistance( aCurSegment.GetStart() ) > 0.0 ) )
+ {
+ nAdd = 1;
+ }
+ }
+ else
+ nAdd = 1;
+
+ if( nAdd )
+ pPtBuffer[ nPCounter++ ] = Point( FRound( fX ), FRound( fY ) );
+ }
+
+ aCurSegment.SetStart( aCurSegment.GetEnd() );
+ }
+ }
+ }
+
+ if( nPCounter > 1 )
+ {
+ qsort( pPtBuffer, nPCounter, sizeof( Point ), ImplHatchCmpFnc );
+
+ if( nPCounter & 1 )
+ nPCounter--;
+
+ if( bMtf )
+ {
+ for( long i = 0; i < nPCounter; i += 2 )
+ mpMetaFile->AddAction( new MetaLineAction( pPtBuffer[ i ], pPtBuffer[ i + 1 ] ) );
+ }
+ else
+ {
+ for( long i = 0; i < nPCounter; i += 2 )
+ {
+ if( mpPDFWriter )
+ {
+ mpPDFWriter->drawLine( pPtBuffer[ i ], pPtBuffer[ i+1 ] );
+ }
+ else
+ {
+ const Point aPt1( ImplLogicToDevicePixel( pPtBuffer[ i ] ) );
+ const Point aPt2( ImplLogicToDevicePixel( pPtBuffer[ i + 1 ] ) );
+ mpGraphics->DrawLine( aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y(), this );
+ }
+ }
+ }
+ }
+}
diff --git a/vcl/source/gdi/outdev5.cxx b/vcl/source/gdi/outdev5.cxx
new file mode 100644
index 000000000000..d42723215c55
--- /dev/null
+++ b/vcl/source/gdi/outdev5.cxx
@@ -0,0 +1,313 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/ref.hxx>
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salgdi.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <tools/poly.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/outdata.hxx>
+#include <vcl/outdev.h>
+#include <vcl/outdev.hxx>
+#include <vcl/virdev.hxx>
+
+// =======================================================================
+
+DBG_NAMEEX( OutputDevice )
+
+// =======================================================================
+
+void OutputDevice::DrawRect( const Rectangle& rRect,
+ ULONG nHorzRound, ULONG nVertRound )
+{
+ DBG_TRACE( "OutputDevice::DrawRoundRect()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaRoundRectAction( rRect, nHorzRound, nVertRound ) );
+
+ if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
+ return;
+
+ const Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+
+ if ( aRect.IsEmpty() )
+ return;
+
+ nHorzRound = ImplLogicWidthToDevicePixel( nHorzRound );
+ nVertRound = ImplLogicHeightToDevicePixel( nVertRound );
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+
+ if ( !nHorzRound && !nVertRound )
+ mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), this );
+ else
+ {
+ const Polygon aRoundRectPoly( aRect, nHorzRound, nVertRound );
+
+ if ( aRoundRectPoly.GetSize() >= 2 )
+ {
+ const SalPoint* pPtAry = (const SalPoint*) aRoundRectPoly.GetConstPointAry();
+
+ if ( !mbFillColor )
+ mpGraphics->DrawPolyLine( aRoundRectPoly.GetSize(), pPtAry, this );
+ else
+ mpGraphics->DrawPolygon( aRoundRectPoly.GetSize(), pPtAry, this );
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawRect( rRect, nHorzRound, nVertRound );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawEllipse( const Rectangle& rRect )
+{
+ DBG_TRACE( "OutputDevice::DrawEllipse()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaEllipseAction( rRect ) );
+
+ if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
+ return;
+
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+ if ( aRect.IsEmpty() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ Polygon aRectPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
+ if ( aRectPoly.GetSize() >= 2 )
+ {
+ const SalPoint* pPtAry = (const SalPoint*)aRectPoly.GetConstPointAry();
+ if ( !mbFillColor )
+ mpGraphics->DrawPolyLine( aRectPoly.GetSize(), pPtAry, this );
+ else
+ {
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+ mpGraphics->DrawPolygon( aRectPoly.GetSize(), pPtAry, this );
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawEllipse( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawArc( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt )
+{
+ DBG_TRACE( "OutputDevice::DrawArc()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaArcAction( rRect, rStartPt, rEndPt ) );
+
+ if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
+ return;
+
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+ if ( aRect.IsEmpty() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ const Point aStart( ImplLogicToDevicePixel( rStartPt ) );
+ const Point aEnd( ImplLogicToDevicePixel( rEndPt ) );
+ Polygon aArcPoly( aRect, aStart, aEnd, POLY_ARC );
+
+ if ( aArcPoly.GetSize() >= 2 )
+ {
+ const SalPoint* pPtAry = (const SalPoint*)aArcPoly.GetConstPointAry();
+ mpGraphics->DrawPolyLine( aArcPoly.GetSize(), pPtAry, this );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawArc( rRect, rStartPt, rEndPt );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawPie( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt )
+{
+ DBG_TRACE( "OutputDevice::DrawPie()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaPieAction( rRect, rStartPt, rEndPt ) );
+
+ if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
+ return;
+
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+ if ( aRect.IsEmpty() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ const Point aStart( ImplLogicToDevicePixel( rStartPt ) );
+ const Point aEnd( ImplLogicToDevicePixel( rEndPt ) );
+ Polygon aPiePoly( aRect, aStart, aEnd, POLY_PIE );
+
+ if ( aPiePoly.GetSize() >= 2 )
+ {
+ const SalPoint* pPtAry = (const SalPoint*)aPiePoly.GetConstPointAry();
+ if ( !mbFillColor )
+ mpGraphics->DrawPolyLine( aPiePoly.GetSize(), pPtAry, this );
+ else
+ {
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+ mpGraphics->DrawPolygon( aPiePoly.GetSize(), pPtAry, this );
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawPie( rRect, rStartPt, rEndPt );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawChord( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt )
+{
+ DBG_TRACE( "OutputDevice::DrawChord()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaChordAction( rRect, rStartPt, rEndPt ) );
+
+ if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
+ return;
+
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+ if ( aRect.IsEmpty() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+
+ const Point aStart( ImplLogicToDevicePixel( rStartPt ) );
+ const Point aEnd( ImplLogicToDevicePixel( rEndPt ) );
+ Polygon aChordPoly( aRect, aStart, aEnd, POLY_CHORD );
+
+ if ( aChordPoly.GetSize() >= 2 )
+ {
+ const SalPoint* pPtAry = (const SalPoint*)aChordPoly.GetConstPointAry();
+ if ( !mbFillColor )
+ mpGraphics->DrawPolyLine( aChordPoly.GetSize(), pPtAry, this );
+ else
+ {
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+ mpGraphics->DrawPolygon( aChordPoly.GetSize(), pPtAry, this );
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawChord( rRect, rStartPt, rEndPt );
+}
diff --git a/vcl/source/gdi/outdev6.cxx b/vcl/source/gdi/outdev6.cxx
new file mode 100644
index 000000000000..5b8d228bb141
--- /dev/null
+++ b/vcl/source/gdi/outdev6.cxx
@@ -0,0 +1,1247 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salgdi.hxx>
+#include <tools/debug.hxx>
+#include <vcl/outdev.h>
+#include <vcl/outdev.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/wall2.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <math.h>
+#include <vcl/window.h>
+#include <vcl/svdata.hxx>
+
+// ========================================================================
+
+DBG_NAMEEX( OutputDevice )
+
+// ------------------------------------------------------------------------
+
+void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, ULONG nFlags )
+{
+ DBG_TRACE( "OutputDevice::DrawGrid()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() );
+ aDstRect.Intersection( rRect );
+
+ if( aDstRect.IsEmpty() || ImplIsRecordLayout() )
+ return;
+
+ if( !mpGraphics && !ImplGetGraphics() )
+ return;
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if( mbOutputClipped )
+ return;
+
+ const long nDistX = Max( rDist.Width(), 1L );
+ const long nDistY = Max( rDist.Height(), 1L );
+ long nX = ( rRect.Left() >= aDstRect.Left() ) ? rRect.Left() : ( rRect.Left() + ( ( aDstRect.Left() - rRect.Left() ) / nDistX ) * nDistX );
+ long nY = ( rRect.Top() >= aDstRect.Top() ) ? rRect.Top() : ( rRect.Top() + ( ( aDstRect.Top() - rRect.Top() ) / nDistY ) * nDistY );
+ const long nRight = aDstRect.Right();
+ const long nBottom = aDstRect.Bottom();
+ const long nStartX = ImplLogicXToDevicePixel( nX );
+ const long nEndX = ImplLogicXToDevicePixel( nRight );
+ const long nStartY = ImplLogicYToDevicePixel( nY );
+ const long nEndY = ImplLogicYToDevicePixel( nBottom );
+ long nHorzCount = 0L;
+ long nVertCount = 0L;
+
+ ::com::sun::star::uno::Sequence< sal_Int32 > aVertBuf;
+ ::com::sun::star::uno::Sequence< sal_Int32 > aHorzBuf;
+
+ if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_HORZLINES ) )
+ {
+ aVertBuf.realloc( aDstRect.GetHeight() / nDistY + 2L );
+ aVertBuf[ nVertCount++ ] = nStartY;
+ while( ( nY += nDistY ) <= nBottom )
+ aVertBuf[ nVertCount++ ] = ImplLogicYToDevicePixel( nY );
+ }
+
+ if( ( nFlags & GRID_DOTS ) || ( nFlags & GRID_VERTLINES ) )
+ {
+ aHorzBuf.realloc( aDstRect.GetWidth() / nDistX + 2L );
+ aHorzBuf[ nHorzCount++ ] = nStartX;
+ while( ( nX += nDistX ) <= nRight )
+ aHorzBuf[ nHorzCount++ ] = ImplLogicXToDevicePixel( nX );
+ }
+
+ if( mbInitLineColor )
+ ImplInitLineColor();
+
+ if( mbInitFillColor )
+ ImplInitFillColor();
+
+ const BOOL bOldMap = mbMap;
+ EnableMapMode( FALSE );
+
+ if( nFlags & GRID_DOTS )
+ {
+ for( long i = 0L; i < nVertCount; i++ )
+ for( long j = 0L, Y = aVertBuf[ i ]; j < nHorzCount; j++ )
+ mpGraphics->DrawPixel( aHorzBuf[ j ], Y, this );
+ }
+ else
+ {
+ if( nFlags & GRID_HORZLINES )
+ {
+ for( long i = 0L; i < nVertCount; i++ )
+ {
+ nY = aVertBuf[ i ];
+ mpGraphics->DrawLine( nStartX, nY, nEndX, nY, this );
+ }
+ }
+
+ if( nFlags & GRID_VERTLINES )
+ {
+ for( long i = 0L; i < nHorzCount; i++ )
+ {
+ nX = aHorzBuf[ i ];
+ mpGraphics->DrawLine( nX, nStartY, nX, nEndY, this );
+ }
+ }
+ }
+
+ EnableMapMode( bOldMap );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawGrid( rRect, rDist, nFlags );
+}
+
+// ------------------------------------------------------------------------
+// Caution: This method is nearly the same as
+// void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
+// so when changes are made here do not forget to make change sthere, too
+
+void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency)
+{
+ DBG_TRACE( "OutputDevice::DrawTransparent(B2D&,transparency)" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // AW: Do NOT paint empty PolyPolygons
+ if(!rB2DPolyPoly.count())
+ return;
+
+ // we need a graphics
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return;
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
+
+ if( mbInitLineColor )
+ ImplInitLineColor();
+ if( mbInitFillColor )
+ ImplInitFillColor();
+
+ if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
+ && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
+ && ROP_OVERPAINT == GetRasterOp() )
+ {
+ // b2dpolygon support not implemented yet on non-UNX platforms
+ const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+ basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
+
+ // transform the polygon into device space and ensure it is closed
+ aB2DPolyPolygon.transform( aTransform );
+ aB2DPolyPolygon.setClosed( true );
+
+ bool bDrawnOk = true;
+ if( IsFillColor() )
+ bDrawnOk = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
+ if( bDrawnOk && IsLineColor() )
+ {
+ const basegfx::B2DVector aHairlineWidth(1,1);
+ const int nPolyCount = aB2DPolyPolygon.count();
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolygon aOnePoly = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
+ mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, ::basegfx::B2DLINEJOIN_NONE, this );
+ }
+ }
+
+ if( bDrawnOk )
+ {
+#if 0
+ // MetaB2DPolyPolygonAction is not implemented yet:
+ // according to AW adding it is very dangerous since there is a lot
+ // of code that uses the metafile actions directly and unless every
+ // place that does this knows about the new action we need to fallback
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly ) );
+#else
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTransparentAction( PolyPolygon( rB2DPolyPoly ), static_cast< sal_uInt16 >(fTransparency * 100.0)));
+#endif
+ return;
+ }
+ }
+
+ // fallback to old polygon drawing if needed
+ const PolyPolygon aToolsPolyPolygon( rB2DPolyPoly );
+ DrawTransparent(PolyPolygon(rB2DPolyPoly), static_cast< sal_uInt16 >(fTransparency * 100.0));
+}
+
+// ------------------------------------------------------------------------
+
+void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
+ USHORT nTransparencePercent )
+{
+ DBG_TRACE( "OutputDevice::DrawTransparent()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // short circuit for drawing an opaque polygon
+ if( (nTransparencePercent < 1) || ((mnDrawMode & DRAWMODE_NOTRANSPARENCY) != 0) )
+ {
+ DrawPolyPolygon( rPolyPoly );
+ return;
+ }
+
+ // short circut for drawing an invisible polygon
+ if( !mbFillColor || (nTransparencePercent >= 100) )
+ {
+ // short circuit if the polygon border is invisible too
+ if( !mbLineColor )
+ return;
+
+ // DrawTransparent() assumes that the border is NOT to be drawn transparently???
+ Push( PUSH_FILLCOLOR );
+ SetFillColor();
+ DrawPolyPolygon( rPolyPoly );
+ Pop();
+ return;
+ }
+
+ // handle metafile recording
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
+
+ bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
+ if( bDrawn )
+ return;
+
+ // get the device graphics as drawing target
+ if( !mpGraphics )
+ if( !ImplGetGraphics() )
+ return;
+
+ // debug helper:
+ static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
+
+ // try hard to draw it directly, because the emulation layers are slower
+ if( !pDisableNative
+ && mpGraphics->supportsOperation( OutDevSupport_B2DDraw )
+#if defined UNX && ! defined QUARTZ
+ && GetBitCount() > 8
+#endif
+#ifdef WIN32
+ // workaround bad dithering on remote displaying when using GDI+ with toolbar buttoin hilighting
+ && !rPolyPoly.IsRect()
+#endif
+ )
+ {
+ // prepare the graphics device
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
+ if( mbInitLineColor )
+ ImplInitLineColor();
+ if( mbInitFillColor )
+ ImplInitFillColor();
+
+ // get the polygon in device coordinates
+ basegfx::B2DPolyPolygon aB2DPolyPolygon( rPolyPoly.getB2DPolyPolygon() );
+ const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+ aB2DPolyPolygon.transform( aTransform );
+
+ const double fTransparency = 0.01 * nTransparencePercent;
+ if( mbFillColor )
+ {
+ // draw the transparent polygon
+ // NOTE: filled polygons are assumed to be drawn as if they were always closed
+ bDrawn = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
+ }
+
+ if( mbLineColor )
+ {
+ // disable the fill color for now
+ mpGraphics->SetFillColor();
+ // draw the border line
+ const basegfx::B2DVector aLineWidths( 1, 1 );
+ const int nPolyCount = aB2DPolyPolygon.count();
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolygon& rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
+ bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths, ::basegfx::B2DLINEJOIN_NONE, this );
+ }
+ // prepare to restore the fill color
+ mbInitFillColor = mbFillColor;
+ }
+ }
+
+ if( bDrawn )
+ return;
+
+ if( 1 )
+ {
+ VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
+
+ // #110958# Disable alpha VDev, we perform the necessary
+ // operation explicitely further below.
+ if( mpAlphaVDev )
+ mpAlphaVDev = NULL;
+
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ mpMetaFile = NULL;
+
+ if( OUTDEV_PRINTER == meOutDevType )
+ {
+ if(100 <= nTransparencePercent)
+ {
+ // #i112959# 100% transparent, draw nothing
+ return;
+ }
+
+ Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
+ const Size aDPISize( LogicToPixel( Size( 1, 1 ), MAP_INCH ) );
+ const long nBaseExtent = Max( FRound( aDPISize.Width() / 300. ), 1L );
+ long nMove;
+ const USHORT nTrans = ( nTransparencePercent < 13 ) ? 0 :
+ ( nTransparencePercent < 38 ) ? 25 :
+ ( nTransparencePercent < 63 ) ? 50 :
+ ( nTransparencePercent < 88 ) ? 75 : 100;
+
+ switch( nTrans )
+ {
+ case( 25 ): nMove = nBaseExtent * 3; break;
+ case( 50 ): nMove = nBaseExtent * 4; break;
+ case( 75 ): nMove = nBaseExtent * 6; break;
+
+ // #i112959# very transparent (88 < nTransparencePercent <= 99)
+ case( 100 ): nMove = nBaseExtent * 8; break;
+
+ // #i112959# not transparent (nTransparencePercent < 13)
+ default: nMove = 0; break;
+ }
+
+ Push( PUSH_CLIPREGION | PUSH_LINECOLOR );
+ IntersectClipRegion( rPolyPoly );
+ SetLineColor( GetFillColor() );
+ const BOOL bOldMap = mbMap;
+ EnableMapMode( FALSE );
+
+ if(nMove)
+ {
+ Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
+ while( aRect.Top() <= aPolyRect.Bottom() )
+ {
+ DrawRect( aRect );
+ aRect.Move( 0, nMove );
+ }
+
+ aRect = Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
+ while( aRect.Left() <= aPolyRect.Right() )
+ {
+ DrawRect( aRect );
+ aRect.Move( nMove, 0 );
+ }
+ }
+ else
+ {
+ // #i112959# if not transparent, draw full rectangle in clip region
+ DrawRect( aPolyRect );
+ }
+
+ EnableMapMode( bOldMap );
+ Pop();
+ }
+ else
+ {
+ PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
+ Rectangle aPolyRect( aPolyPoly.GetBoundRect() );
+ Point aPoint;
+ Rectangle aDstRect( aPoint, GetOutputSizePixel() );
+
+ aDstRect.Intersection( aPolyRect );
+
+ if( OUTDEV_WINDOW == meOutDevType )
+ {
+ const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
+
+ if( !aPaintRgn.IsNull() )
+ aDstRect.Intersection( LogicToPixel( aPaintRgn ).GetBoundRect() );
+ }
+
+ if( !aDstRect.IsEmpty() )
+ {
+ // #i66849# Added fast path for exactly rectangular
+ // polygons
+ // #i83087# Naturally, system alpha blending cannot
+ // work with separate alpha VDev
+ if( !mpAlphaVDev && !pDisableNative && aPolyPoly.IsRect() )
+ {
+ // setup Graphics only here (other cases delegate
+ // to basic OutDev methods)
+ if( 1 )
+ {
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+
+ Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() );
+ Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) );
+
+ if( !mbOutputClipped )
+ {
+ bDrawn = mpGraphics->DrawAlphaRect(
+ aPixelRect.Left(), aPixelRect.Top(),
+ // #i98405# use methods with small g, else one pixel too much will be painted.
+ // This is because the source is a polygon which when painted would not paint
+ // the rightmost and lowest pixel line(s), so use one pixel less for the
+ // rectangle, too.
+ aPixelRect.getWidth(), aPixelRect.getHeight(),
+ sal::static_int_cast<sal_uInt8>(nTransparencePercent),
+ this );
+ }
+ else
+ bDrawn = true;
+ }
+ }
+
+ if( !bDrawn )
+ {
+ VirtualDevice aVDev( *this, 1 );
+ const Size aDstSz( aDstRect.GetSize() );
+ const BYTE cTrans = (BYTE) MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 );
+
+ if( aDstRect.Left() || aDstRect.Top() )
+ aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() );
+
+ if( aVDev.SetOutputSizePixel( aDstSz ) )
+ {
+ const BOOL bOldMap = mbMap;
+
+ EnableMapMode( FALSE );
+
+ aVDev.SetLineColor( COL_BLACK );
+ aVDev.SetFillColor( COL_BLACK );
+ aVDev.DrawPolyPolygon( aPolyPoly );
+
+ Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) );
+ Bitmap aPolyMask( aVDev.GetBitmap( Point(), aDstSz ) );
+
+ // #107766# check for non-empty bitmaps before accessing them
+ if( !!aPaint && !!aPolyMask )
+ {
+ BitmapWriteAccess* pW = aPaint.AcquireWriteAccess();
+ BitmapReadAccess* pR = aPolyMask.AcquireReadAccess();
+
+ if( pW && pR )
+ {
+ BitmapColor aPixCol;
+ const BitmapColor aFillCol( GetFillColor() );
+ const BitmapColor aWhite( pR->GetBestMatchingColor( Color( COL_WHITE ) ) );
+ const BitmapColor aBlack( pR->GetBestMatchingColor( Color( COL_BLACK ) ) );
+ const long nWidth = pW->Width(), nHeight = pW->Height();
+ const long nR = aFillCol.GetRed(), nG = aFillCol.GetGreen(), nB = aFillCol.GetBlue();
+ long nX, nY;
+
+ if( aPaint.GetBitCount() <= 8 )
+ {
+ const BitmapPalette& rPal = pW->GetPalette();
+ const USHORT nCount = rPal.GetEntryCount();
+ BitmapColor* pMap = (BitmapColor*) new BYTE[ nCount * sizeof( BitmapColor ) ];
+
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ BitmapColor aCol( rPal[ i ] );
+ pMap[ i ] = BitmapColor( (BYTE) rPal.GetBestIndex( aCol.Merge( aFillCol, cTrans ) ) );
+ }
+
+ if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
+ pW->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
+ {
+ const BYTE cBlack = aBlack.GetIndex();
+
+ for( nY = 0; nY < nHeight; nY++ )
+ {
+ Scanline pWScan = pW->GetScanline( nY );
+ Scanline pRScan = pR->GetScanline( nY );
+ BYTE cBit = 128;
+
+ for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ )
+ {
+ if( !cBit )
+ cBit = 128, pRScan++;
+
+ if( ( *pRScan & cBit ) == cBlack )
+ *pWScan = (BYTE) pMap[ *pWScan ].GetIndex();
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0; nY < nHeight; nY++ )
+ for( nX = 0; nX < nWidth; nX++ )
+ if( pR->GetPixel( nY, nX ) == aBlack )
+ pW->SetPixel( nY, nX, pMap[ pW->GetPixel( nY, nX ).GetIndex() ] );
+ }
+
+ delete[] (BYTE*) pMap;
+ }
+ else
+ {
+ if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
+ pW->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
+ {
+ const BYTE cBlack = aBlack.GetIndex();
+
+ for( nY = 0; nY < nHeight; nY++ )
+ {
+ Scanline pWScan = pW->GetScanline( nY );
+ Scanline pRScan = pR->GetScanline( nY );
+ BYTE cBit = 128;
+
+ for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 )
+ {
+ if( !cBit )
+ cBit = 128, pRScan++;
+
+ if( ( *pRScan & cBit ) == cBlack )
+ {
+ pWScan[ 0 ] = COLOR_CHANNEL_MERGE( pWScan[ 0 ], nB, cTrans );
+ pWScan[ 1 ] = COLOR_CHANNEL_MERGE( pWScan[ 1 ], nG, cTrans );
+ pWScan[ 2 ] = COLOR_CHANNEL_MERGE( pWScan[ 2 ], nR, cTrans );
+ }
+ }
+ }
+ }
+ else
+ {
+ for( nY = 0; nY < nHeight; nY++ )
+ {
+ for( nX = 0; nX < nWidth; nX++ )
+ {
+ if( pR->GetPixel( nY, nX ) == aBlack )
+ {
+ aPixCol = pW->GetColor( nY, nX );
+ pW->SetPixel( nY, nX, aPixCol.Merge( aFillCol, cTrans ) );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ aPolyMask.ReleaseAccess( pR );
+ aPaint.ReleaseAccess( pW );
+
+ DrawBitmap( aDstRect.TopLeft(), aPaint );
+
+ EnableMapMode( bOldMap );
+
+ if( mbLineColor )
+ {
+ Push( PUSH_FILLCOLOR );
+ SetFillColor();
+ DrawPolyPolygon( rPolyPoly );
+ Pop();
+ }
+ }
+ }
+ else
+ DrawPolyPolygon( rPolyPoly );
+ }
+ }
+ }
+
+ mpMetaFile = pOldMetaFile;
+
+ // #110958# Restore disabled alpha VDev
+ mpAlphaVDev = pOldAlphaVDev;
+
+ // #110958# Apply alpha value also to VDev alpha channel
+ if( mpAlphaVDev )
+ {
+ const Color aFillCol( mpAlphaVDev->GetFillColor() );
+ mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<UINT8>(255*nTransparencePercent/100),
+ sal::static_int_cast<UINT8>(255*nTransparencePercent/100),
+ sal::static_int_cast<UINT8>(255*nTransparencePercent/100)) );
+
+ mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent );
+
+ mpAlphaVDev->SetFillColor( aFillCol );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
+ const Size& rSize, const Gradient& rTransparenceGradient )
+{
+ DBG_TRACE( "OutputDevice::DrawTransparent()" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ const Color aBlack( COL_BLACK );
+
+ if( mpMetaFile )
+ mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) );
+
+ if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) ||
+ ( mnDrawMode & ( DRAWMODE_NOTRANSPARENCY ) ) )
+ {
+ ( (GDIMetaFile&) rMtf ).WindStart();
+ ( (GDIMetaFile&) rMtf ).Play( this, rPos, rSize );
+ ( (GDIMetaFile&) rMtf ).WindStart();
+ }
+ else
+ {
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ Rectangle aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) );
+ Point aPoint;
+ Rectangle aDstRect( aPoint, GetOutputSizePixel() );
+
+ mpMetaFile = NULL;
+ aDstRect.Intersection( aOutRect );
+
+ if( OUTDEV_WINDOW == meOutDevType )
+ {
+ const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
+
+ if( !aPaintRgn.IsNull() )
+ aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) );
+ }
+
+ if( !aDstRect.IsEmpty() )
+ {
+ VirtualDevice* pVDev = new VirtualDevice;
+
+ ((OutputDevice*)pVDev)->mnDPIX = mnDPIX;
+ ((OutputDevice*)pVDev)->mnDPIY = mnDPIY;
+
+ if( pVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
+ {
+ if(GetAntialiasing())
+ {
+ // #i102109#
+ // For MetaFile replay (see task) it may now be neccessary to take
+ // into account that the content is AntiAlialised and needs to be masked
+ // like that. Instead of masking, i will use a copy-modify-paste cycle
+ // here (as i already use in the VclPrimiziveRenderer with successs)
+ pVDev->SetAntialiasing(GetAntialiasing());
+
+ // create MapMode for buffer (offset needed) and set
+ MapMode aMap(GetMapMode());
+ const Point aOutPos(PixelToLogic(aDstRect.TopLeft()));
+ aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y()));
+ pVDev->SetMapMode(aMap);
+
+ // copy MapMode state and disable for target
+ const bool bOrigMapModeEnabled(IsMapModeEnabled());
+ EnableMapMode(false);
+
+ // copy MapMode state and disable for buffer
+ const bool bBufferMapModeEnabled(pVDev->IsMapModeEnabled());
+ pVDev->EnableMapMode(false);
+
+ // copy content from original to buffer
+ pVDev->DrawOutDev(
+ aPoint, pVDev->GetOutputSizePixel(), // dest
+ aDstRect.TopLeft(), pVDev->GetOutputSizePixel(), // source
+ *this);
+
+ // draw MetaFile to buffer
+ pVDev->EnableMapMode(bBufferMapModeEnabled);
+ ((GDIMetaFile&)rMtf).WindStart();
+ ((GDIMetaFile&)rMtf).Play(pVDev, rPos, rSize);
+ ((GDIMetaFile&)rMtf).WindStart();
+
+ // get content bitmap from buffer
+ pVDev->EnableMapMode(false);
+ const Bitmap aPaint(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel()));
+
+ // create alpha mask from gradient and get as Bitmap
+ pVDev->EnableMapMode(bBufferMapModeEnabled);
+ pVDev->SetDrawMode(DRAWMODE_GRAYGRADIENT);
+ pVDev->DrawGradient(Rectangle(rPos, rSize), rTransparenceGradient);
+ pVDev->SetDrawMode(DRAWMODE_DEFAULT);
+ pVDev->EnableMapMode(false);
+ const AlphaMask aAlpha(pVDev->GetBitmap(aPoint, pVDev->GetOutputSizePixel()));
+
+ // draw masked content to target and restore MapMode
+ DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
+ EnableMapMode(bOrigMapModeEnabled);
+ }
+ else
+ {
+ Bitmap aPaint, aMask;
+ AlphaMask aAlpha;
+ MapMode aMap( GetMapMode() );
+ Point aOutPos( PixelToLogic( aDstRect.TopLeft() ) );
+ const BOOL bOldMap = mbMap;
+
+ aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) );
+ pVDev->SetMapMode( aMap );
+ const BOOL bVDevOldMap = pVDev->IsMapModeEnabled();
+
+ // create paint bitmap
+ ( (GDIMetaFile&) rMtf ).WindStart();
+ ( (GDIMetaFile&) rMtf ).Play( pVDev, rPos, rSize );
+ ( (GDIMetaFile&) rMtf ).WindStart();
+ pVDev->EnableMapMode( FALSE );
+ aPaint = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() );
+ pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( TRUE ) here!
+
+ // create mask bitmap
+ pVDev->SetLineColor( COL_BLACK );
+ pVDev->SetFillColor( COL_BLACK );
+ pVDev->DrawRect( Rectangle( pVDev->PixelToLogic( Point() ), pVDev->GetOutputSize() ) );
+ pVDev->SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT |
+ DRAWMODE_WHITEBITMAP | DRAWMODE_WHITEGRADIENT );
+ ( (GDIMetaFile&) rMtf ).WindStart();
+ ( (GDIMetaFile&) rMtf ).Play( pVDev, rPos, rSize );
+ ( (GDIMetaFile&) rMtf ).WindStart();
+ pVDev->EnableMapMode( FALSE );
+ aMask = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() );
+ pVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( TRUE ) here!
+
+ // create alpha mask from gradient
+ pVDev->SetDrawMode( DRAWMODE_GRAYGRADIENT );
+ pVDev->DrawGradient( Rectangle( rPos, rSize ), rTransparenceGradient );
+ pVDev->SetDrawMode( DRAWMODE_DEFAULT );
+ pVDev->EnableMapMode( FALSE );
+ pVDev->DrawMask( Point(), pVDev->GetOutputSizePixel(), aMask, Color( COL_WHITE ) );
+
+ aAlpha = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() );
+
+ delete pVDev;
+
+ EnableMapMode( FALSE );
+ DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) );
+ EnableMapMode( bOldMap );
+ }
+ }
+ else
+ delete pVDev;
+ }
+
+ mpMetaFile = pOldMetaFile;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawColorWallpaper( long nX, long nY,
+ long nWidth, long nHeight,
+ const Wallpaper& rWallpaper )
+{
+ // Wallpaper ohne Umrandung zeichnen
+ Color aOldLineColor = GetLineColor();
+ Color aOldFillColor = GetFillColor();
+ SetLineColor();
+ SetFillColor( rWallpaper.GetColor() );
+ BOOL bMap = mbMap;
+ EnableMapMode( FALSE );
+ DrawRect( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) );
+ SetLineColor( aOldLineColor );
+ SetFillColor( aOldFillColor );
+ EnableMapMode( bMap );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawBitmapWallpaper( long nX, long nY,
+ long nWidth, long nHeight,
+ const Wallpaper& rWallpaper )
+{
+ BitmapEx aBmpEx;
+ const BitmapEx* pCached = rWallpaper.ImplGetImpWallpaper()->ImplGetCachedBitmap();
+ Point aPos;
+ Size aSize;
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ const WallpaperStyle eStyle = rWallpaper.GetStyle();
+ const BOOL bOldMap = mbMap;
+ BOOL bDrawn = FALSE;
+ BOOL bDrawGradientBackground = FALSE;
+ BOOL bDrawColorBackground = FALSE;
+
+ if( pCached )
+ aBmpEx = *pCached;
+ else
+ aBmpEx = rWallpaper.GetBitmap();
+
+ const long nBmpWidth = aBmpEx.GetSizePixel().Width();
+ const long nBmpHeight = aBmpEx.GetSizePixel().Height();
+ const BOOL bTransparent = aBmpEx.IsTransparent();
+
+ // draw background
+ if( bTransparent )
+ {
+ if( rWallpaper.IsGradient() )
+ bDrawGradientBackground = TRUE;
+ else
+ {
+ if( !pCached && !rWallpaper.GetColor().GetTransparency() )
+ {
+ VirtualDevice aVDev( *this );
+ aVDev.SetBackground( rWallpaper.GetColor() );
+ aVDev.SetOutputSizePixel( Size( nBmpWidth, nBmpHeight ) );
+ aVDev.DrawBitmapEx( Point(), aBmpEx );
+ aBmpEx = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
+ }
+
+ bDrawColorBackground = TRUE;
+ }
+ }
+ else if( eStyle != WALLPAPER_TILE && eStyle != WALLPAPER_SCALE )
+ {
+ if( rWallpaper.IsGradient() )
+ bDrawGradientBackground = TRUE;
+ else
+ bDrawColorBackground = TRUE;
+ }
+
+ // background of bitmap?
+ if( bDrawGradientBackground )
+ ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
+ else if( bDrawColorBackground && bTransparent )
+ {
+ ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
+ bDrawColorBackground = FALSE;
+ }
+
+ // calc pos and size
+ if( rWallpaper.IsRect() )
+ {
+ const Rectangle aBound( LogicToPixel( rWallpaper.GetRect() ) );
+ aPos = aBound.TopLeft();
+ aSize = aBound.GetSize();
+ }
+ else
+ {
+ aPos = Point( nX, nY );
+ aSize = Size( nWidth, nHeight );
+ }
+
+ mpMetaFile = NULL;
+ EnableMapMode( FALSE );
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) );
+
+ switch( eStyle )
+ {
+ case( WALLPAPER_SCALE ):
+ {
+ if( !pCached || ( pCached->GetSizePixel() != aSize ) )
+ {
+ if( pCached )
+ rWallpaper.ImplGetImpWallpaper()->ImplReleaseCachedBitmap();
+
+ aBmpEx = rWallpaper.GetBitmap();
+ aBmpEx.Scale( aSize );
+ aBmpEx = BitmapEx( aBmpEx.GetBitmap().CreateDisplayBitmap( this ), aBmpEx.GetMask() );
+ }
+ }
+ break;
+
+ case( WALLPAPER_TOPLEFT ):
+ break;
+
+ case( WALLPAPER_TOP ):
+ aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1;
+ break;
+
+ case( WALLPAPER_TOPRIGHT ):
+ aPos.X() += ( aSize.Width() - nBmpWidth );
+ break;
+
+ case( WALLPAPER_LEFT ):
+ aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1;
+ break;
+
+ case( WALLPAPER_CENTER ):
+ {
+ aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1;
+ aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1;
+ }
+ break;
+
+ case( WALLPAPER_RIGHT ):
+ {
+ aPos.X() += ( aSize.Width() - nBmpWidth );
+ aPos.Y() += ( aSize.Height() - nBmpHeight ) >> 1;
+ }
+ break;
+
+ case( WALLPAPER_BOTTOMLEFT ):
+ aPos.Y() += ( aSize.Height() - nBmpHeight );
+ break;
+
+ case( WALLPAPER_BOTTOM ):
+ {
+ aPos.X() += ( aSize.Width() - nBmpWidth ) >> 1;
+ aPos.Y() += ( aSize.Height() - nBmpHeight );
+ }
+ break;
+
+ case( WALLPAPER_BOTTOMRIGHT ):
+ {
+ aPos.X() += ( aSize.Width() - nBmpWidth );
+ aPos.Y() += ( aSize.Height() - nBmpHeight );
+ }
+ break;
+
+ default:
+ {
+ const long nRight = nX + nWidth - 1L;
+ const long nBottom = nY + nHeight - 1L;
+ long nFirstX;
+ long nFirstY;
+
+ if( eStyle == WALLPAPER_TILE )
+ {
+ nFirstX = aPos.X();
+ nFirstY = aPos.Y();
+ }
+ else
+ {
+ nFirstX = aPos.X() + ( ( aSize.Width() - nBmpWidth ) >> 1 );
+ nFirstY = aPos.Y() + ( ( aSize.Height() - nBmpHeight ) >> 1 );
+ }
+
+ const long nOffX = ( nFirstX - nX ) % nBmpWidth;
+ const long nOffY = ( nFirstY - nY ) % nBmpHeight;
+ long nStartX = nX + nOffX;
+ long nStartY = nY + nOffY;
+
+ if( nOffX > 0L )
+ nStartX -= nBmpWidth;
+
+ if( nOffY > 0L )
+ nStartY -= nBmpHeight;
+
+ for( long nBmpY = nStartY; nBmpY <= nBottom; nBmpY += nBmpHeight )
+ for( long nBmpX = nStartX; nBmpX <= nRight; nBmpX += nBmpWidth )
+ DrawBitmapEx( Point( nBmpX, nBmpY ), aBmpEx );
+
+ bDrawn = TRUE;
+ }
+ break;
+ }
+
+ if( !bDrawn )
+ {
+ // optimized for non-transparent bitmaps
+ if( bDrawColorBackground )
+ {
+ const Size aBmpSize( aBmpEx.GetSizePixel() );
+ const Point aTmpPoint;
+ const Rectangle aOutRect( aTmpPoint, GetOutputSizePixel() );
+ const Rectangle aColRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ Rectangle aWorkRect;
+
+ aWorkRect = Rectangle( 0, 0, aOutRect.Right(), aPos.Y() - 1L );
+ aWorkRect.Justify();
+ aWorkRect.Intersection( aColRect );
+ if( !aWorkRect.IsEmpty() )
+ {
+ ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
+ aWorkRect.GetWidth(), aWorkRect.GetHeight(),
+ rWallpaper );
+ }
+
+ aWorkRect = Rectangle( 0, aPos.Y(), aPos.X() - 1L, aPos.Y() + aBmpSize.Height() - 1L );
+ aWorkRect.Justify();
+ aWorkRect.Intersection( aColRect );
+ if( !aWorkRect.IsEmpty() )
+ {
+ ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
+ aWorkRect.GetWidth(), aWorkRect.GetHeight(),
+ rWallpaper );
+ }
+
+ aWorkRect = Rectangle( aPos.X() + aBmpSize.Width(), aPos.Y(), aOutRect.Right(), aPos.Y() + aBmpSize.Height() - 1L );
+ aWorkRect.Justify();
+ aWorkRect.Intersection( aColRect );
+ if( !aWorkRect.IsEmpty() )
+ {
+ ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
+ aWorkRect.GetWidth(), aWorkRect.GetHeight(),
+ rWallpaper );
+ }
+
+ aWorkRect = Rectangle( 0, aPos.Y() + aBmpSize.Height(), aOutRect.Right(), aOutRect.Bottom() );
+ aWorkRect.Justify();
+ aWorkRect.Intersection( aColRect );
+ if( !aWorkRect.IsEmpty() )
+ {
+ ImplDrawColorWallpaper( aWorkRect.Left(), aWorkRect.Top(),
+ aWorkRect.GetWidth(), aWorkRect.GetHeight(),
+ rWallpaper );
+ }
+ }
+
+ DrawBitmapEx( aPos, aBmpEx );
+ }
+
+ rWallpaper.ImplGetImpWallpaper()->ImplSetCachedBitmap( aBmpEx );
+
+ Pop();
+ EnableMapMode( bOldMap );
+ mpMetaFile = pOldMetaFile;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawGradientWallpaper( long nX, long nY,
+ long nWidth, long nHeight,
+ const Wallpaper& rWallpaper )
+{
+ Rectangle aBound;
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+ const BOOL bOldMap = mbMap;
+ BOOL bNeedGradient = TRUE;
+
+/*
+ if ( rWallpaper.IsRect() )
+ aBound = LogicToPixel( rWallpaper.GetRect() );
+ else
+*/
+ aBound = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
+
+ mpMetaFile = NULL;
+ EnableMapMode( FALSE );
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) );
+
+ if( OUTDEV_WINDOW == meOutDevType && rWallpaper.GetStyle() == WALLPAPER_APPLICATIONGRADIENT )
+ {
+ Window *pWin = dynamic_cast< Window* >( this );
+ if( pWin )
+ {
+ // limit gradient to useful size, so that it still can be noticed
+ // in maximized windows
+ long gradientWidth = pWin->GetDesktopRectPixel().GetSize().Width();
+ if( gradientWidth > 1024 )
+ gradientWidth = 1024;
+ if( mnOutOffX+nWidth > gradientWidth )
+ ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper.GetGradient().GetEndColor() );
+ if( mnOutOffX > gradientWidth )
+ bNeedGradient = FALSE;
+ else
+ aBound = Rectangle( Point( -mnOutOffX, nY ), Size( gradientWidth, nHeight ) );
+ }
+ }
+
+ if( bNeedGradient )
+ DrawGradient( aBound, rWallpaper.GetGradient() );
+
+ Pop();
+ EnableMapMode( bOldMap );
+ mpMetaFile = pOldMetaFile;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDrawWallpaper( long nX, long nY,
+ long nWidth, long nHeight,
+ const Wallpaper& rWallpaper )
+{
+ if( rWallpaper.IsBitmap() )
+ ImplDrawBitmapWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
+ else if( rWallpaper.IsGradient() )
+ ImplDrawGradientWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
+ else
+ ImplDrawColorWallpaper( nX, nY, nWidth, nHeight, rWallpaper );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::DrawWallpaper( const Rectangle& rRect,
+ const Wallpaper& rWallpaper )
+{
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaWallpaperAction( rRect, rWallpaper ) );
+
+ if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ if ( rWallpaper.GetStyle() != WALLPAPER_NULL )
+ {
+ Rectangle aRect = LogicToPixel( rRect );
+ aRect.Justify();
+
+ if ( !aRect.IsEmpty() )
+ {
+ ImplDrawWallpaper( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
+ rWallpaper );
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawWallpaper( rRect, rWallpaper );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::Erase()
+{
+ if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ BOOL bNativeOK = FALSE;
+ if( meOutDevType == OUTDEV_WINDOW )
+ {
+ Window* pWindow = static_cast<Window*>(this);
+ ControlPart aCtrlPart = pWindow->ImplGetWindowImpl()->mnNativeBackground;
+ if( aCtrlPart != 0 && ! pWindow->IsControlBackground() )
+ {
+ ImplControlValue aControlValue;
+ Point aGcc3WorkaroundTemporary;
+ Rectangle aCtrlRegion( aGcc3WorkaroundTemporary, GetOutputSizePixel() );
+ ControlState nState = 0;
+
+ if( pWindow->IsEnabled() ) nState |= CTRL_STATE_ENABLED;
+ bNativeOK = pWindow->DrawNativeControl( CTRL_WINDOW_BACKGROUND, aCtrlPart, aCtrlRegion,
+ nState, aControlValue, rtl::OUString() );
+ }
+ }
+
+ if ( mbBackground && ! bNativeOK )
+ {
+ RasterOp eRasterOp = GetRasterOp();
+ if ( eRasterOp != ROP_OVERPAINT )
+ SetRasterOp( ROP_OVERPAINT );
+ ImplDrawWallpaper( 0, 0, mnOutWidth, mnOutHeight, maBackground );
+ if ( eRasterOp != ROP_OVERPAINT )
+ SetRasterOp( eRasterOp );
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->Erase();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::ImplDraw2ColorFrame( const Rectangle& rRect,
+ const Color& rLeftTopColor,
+ const Color& rRightBottomColor )
+{
+ SetFillColor( rLeftTopColor );
+ DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Left(), rRect.Bottom()-1 ) ) );
+ DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Right()-1, rRect.Top() ) ) );
+ SetFillColor( rRightBottomColor );
+ DrawRect( Rectangle( rRect.BottomLeft(), rRect.BottomRight() ) );
+ DrawRect( Rectangle( rRect.TopRight(), rRect.BottomRight() ) );
+}
+
+// -----------------------------------------------------------------------
+
+bool OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize,
+ const GfxLink& rGfxLink, GDIMetaFile* pSubst )
+{
+ bool bDrawn(true);
+
+ if ( mpMetaFile )
+ {
+ GDIMetaFile aSubst;
+
+ if( pSubst )
+ aSubst = *pSubst;
+
+ mpMetaFile->AddAction( new MetaEPSAction( rPoint, rSize, rGfxLink, aSubst ) );
+ }
+
+ if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return bDrawn;
+
+ if( mbOutputClipped )
+ return bDrawn;
+
+ Rectangle aRect( ImplLogicToDevicePixel( Rectangle( rPoint, rSize ) ) );
+
+ if( !aRect.IsEmpty() )
+ {
+ // draw the real EPS graphics
+ if( rGfxLink.GetData() && rGfxLink.GetDataSize() )
+ {
+ if( !mpGraphics && !ImplGetGraphics() )
+ return bDrawn;
+
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ aRect.Justify();
+ bDrawn = mpGraphics->DrawEPS( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
+ (BYTE*) rGfxLink.GetData(), rGfxLink.GetDataSize(), this );
+ }
+
+ // else draw the substitution graphics
+ if( !bDrawn && pSubst )
+ {
+ GDIMetaFile* pOldMetaFile = mpMetaFile;
+
+ mpMetaFile = NULL;
+ Graphic( *pSubst ).Draw( this, rPoint, rSize );
+ mpMetaFile = pOldMetaFile;
+ }
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->DrawEPS( rPoint, rSize, rGfxLink, pSubst );
+
+ return bDrawn;
+}
diff --git a/vcl/source/gdi/outdevnative.cxx b/vcl/source/gdi/outdevnative.cxx
new file mode 100644
index 000000000000..521f4d7ea62d
--- /dev/null
+++ b/vcl/source/gdi/outdevnative.cxx
@@ -0,0 +1,376 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/outdev.hxx"
+#include "vcl/window.hxx"
+#include "vcl/salgdi.hxx"
+#include "vcl/salnativewidgets.hxx"
+#include "vcl/pdfextoutdevdata.hxx"
+
+// -----------------------------------------------------------------------
+
+static bool lcl_enableNativeWidget( const OutputDevice& i_rDevice )
+{
+ const OutDevType eType( i_rDevice.GetOutDevType() );
+ switch ( eType )
+ {
+
+ case OUTDEV_WINDOW:
+ return dynamic_cast< const Window* >( &i_rDevice )->IsNativeWidgetEnabled();
+
+ case OUTDEV_VIRDEV:
+ {
+ const ::vcl::ExtOutDevData* pOutDevData( i_rDevice.GetExtOutDevData() );
+ const ::vcl::PDFExtOutDevData* pPDFData( dynamic_cast< const ::vcl::PDFExtOutDevData* >( pOutDevData ) );
+ if ( pPDFData != NULL )
+ return false;
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+ImplControlValue::~ImplControlValue()
+{
+}
+
+ScrollbarValue::~ScrollbarValue()
+{
+}
+
+SliderValue::~SliderValue()
+{
+}
+
+TabitemValue::~TabitemValue()
+{
+}
+
+SpinbuttonValue::~SpinbuttonValue()
+{
+}
+
+ToolbarValue::~ToolbarValue()
+{
+}
+
+MenubarValue::~MenubarValue()
+{
+}
+
+PushButtonValue::~PushButtonValue()
+{
+}
+
+// -----------------------------------------------------------------------
+// These functions are mainly passthrough functions that allow access to
+// the SalFrame behind a Window object for native widget rendering purposes.
+// -----------------------------------------------------------------------
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ if( !lcl_enableNativeWidget( *this ) )
+ return FALSE;
+
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return FALSE;
+
+ return( mpGraphics->IsNativeControlSupported(nType, nPart) );
+}
+
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::HitTestNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ const Point& aPos,
+ BOOL& rIsInside )
+{
+ if( !lcl_enableNativeWidget( *this ) )
+ return FALSE;
+
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return FALSE;
+
+ Point aWinOffs( mnOutOffX, mnOutOffY );
+ Rectangle screenRegion( rControlRegion );
+ screenRegion.Move( aWinOffs.X(), aWinOffs.Y());
+
+ return( mpGraphics->HitTestNativeControl(nType, nPart, screenRegion, Point( aPos.X() + mnOutOffX, aPos.Y() + mnOutOffY ),
+ rIsInside, this ) );
+}
+
+// -----------------------------------------------------------------------
+
+static boost::shared_ptr< ImplControlValue > lcl_transformControlValue( const ImplControlValue& rVal, OutputDevice& rDev )
+{
+ boost::shared_ptr< ImplControlValue > aResult;
+ switch( rVal.getType() )
+ {
+ case CTRL_SLIDER:
+ {
+ const SliderValue* pSlVal = static_cast<const SliderValue*>(&rVal);
+ SliderValue* pNew = new SliderValue( *pSlVal );
+ aResult.reset( pNew );
+ pNew->maThumbRect = rDev.ImplLogicToDevicePixel( pSlVal->maThumbRect );
+ }
+ break;
+ case CTRL_SCROLLBAR:
+ {
+ const ScrollbarValue* pScVal = static_cast<const ScrollbarValue*>(&rVal);
+ ScrollbarValue* pNew = new ScrollbarValue( *pScVal );
+ aResult.reset( pNew );
+ pNew->maThumbRect = rDev.ImplLogicToDevicePixel( pScVal->maThumbRect );
+ pNew->maButton1Rect = rDev.ImplLogicToDevicePixel( pScVal->maButton1Rect );
+ pNew->maButton2Rect = rDev.ImplLogicToDevicePixel( pScVal->maButton2Rect );
+ }
+ break;
+ case CTRL_SPINBUTTONS:
+ {
+ const SpinbuttonValue* pSpVal = static_cast<const SpinbuttonValue*>(&rVal);
+ SpinbuttonValue* pNew = new SpinbuttonValue( *pSpVal );
+ aResult.reset( pNew );
+ pNew->maUpperRect = rDev.ImplLogicToDevicePixel( pSpVal->maUpperRect );
+ pNew->maLowerRect = rDev.ImplLogicToDevicePixel( pSpVal->maLowerRect );
+ }
+ break;
+ case CTRL_TOOLBAR:
+ {
+ const ToolbarValue* pTVal = static_cast<const ToolbarValue*>(&rVal);
+ ToolbarValue* pNew = new ToolbarValue( *pTVal );
+ aResult.reset( pNew );
+ pNew->maGripRect = rDev.ImplLogicToDevicePixel( pTVal->maGripRect );
+ }
+ break;
+ case CTRL_TAB_ITEM:
+ {
+ const TabitemValue* pTIVal = static_cast<const TabitemValue*>(&rVal);
+ TabitemValue* pNew = new TabitemValue( *pTIVal );
+ aResult.reset( pNew );
+ }
+ break;
+ case CTRL_MENUBAR:
+ {
+ const MenubarValue* pMVal = static_cast<const MenubarValue*>(&rVal);
+ MenubarValue* pNew = new MenubarValue( *pMVal );
+ aResult.reset( pNew );
+ }
+ break;
+ case CTRL_PUSHBUTTON:
+ {
+ const PushButtonValue* pBVal = static_cast<const PushButtonValue*>(&rVal);
+ PushButtonValue* pNew = new PushButtonValue( *pBVal );
+ aResult.reset( pNew );
+ }
+ break;
+ case CTRL_GENERIC:
+ aResult.reset( new ImplControlValue( rVal ) );
+ break;
+ default:
+ OSL_ENSURE( 0, "unknown ImplControlValue type !" );
+ break;
+ }
+ return aResult;
+}
+
+#if 0
+static void lcl_moveControlValue( ControlType nType, const ImplControlValue& aValue, const Point& rDelta )
+{
+ switch( aValue.getType() )
+ {
+ case CTRL_SLIDER:
+ {
+ SliderValue* pSlVal = static_cast<SliderValue*>(const_cast<ImplControlValue*>(&aValue));
+ pSlVal->maThumbRect.Move( rDelta.X(), rDelta.Y() );
+ }
+ break;
+ case CTRL_SCROLLBAR:
+ {
+ ScrollbarValue* pScVal = static_cast<ScrollbarValue*>(const_cast<ImplControlValue*>(&aValue));
+ pScVal->maThumbRect.Move( rDelta.X(), rDelta.Y() );
+ pScVal->maButton1Rect.Move( rDelta.X(), rDelta.Y() );
+ pScVal->maButton2Rect.Move( rDelta.X(), rDelta.Y() );
+ }
+ break;
+ case CTRL_SPINBOX:
+ case CTRL_SPINBUTTONS:
+ {
+ SpinbuttonValue* pSpVal = static_cast<SpinbuttonValue*>(const_cast<ImplControlValue*>(&aValue));
+ pSpVal->maUpperRect.Move( rDelta.X(), rDelta.Y() );
+ pSpVal->maLowerRect.Move( rDelta.X(), rDelta.Y() );
+ }
+ break;
+ case CTRL_TOOLBAR:
+ {
+ ToolbarValue* pTVal = static_cast<ToolbarValue*>(const_cast<ImplControlValue*>(&aValue));
+ pTVal->maGripRect.Move( rDelta.X(), rDelta.Y() );
+ }
+ break;
+ }
+}
+#endif
+
+BOOL OutputDevice::DrawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ ::rtl::OUString aCaption )
+{
+ if( !lcl_enableNativeWidget( *this ) )
+ return FALSE;
+
+ /*
+ if( !IsInPaint() && IsPaintTransparent() )
+ {
+ // only required if called directly (ie, we're not in Paint() ):
+ // force redraw (Paint()) for transparent controls
+ // to trigger a repaint of the background
+ Region aClipRgn( GetClipRegion() );
+ if( !rControlRegion.IsEmpty() )
+ aClipRgn.Intersect( rControlRegion );
+ Invalidate( aClipRgn, INVALIDATE_UPDATE );
+ return TRUE;
+ }
+ */
+
+ // make sure the current clip region is initialized correctly
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return FALSE;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return TRUE;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+
+ // Convert the coordinates from relative to Window-absolute, so we draw
+ // in the correct place in platform code
+ boost::shared_ptr< ImplControlValue > aScreenCtrlValue( lcl_transformControlValue( aValue, *this ) );
+ Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );
+
+ Region aTestRegion( GetActiveClipRegion() );
+ aTestRegion.Intersect( rControlRegion );
+ if( aTestRegion == rControlRegion )
+ nState |= CTRL_CACHING_ALLOWED; // control is not clipped, caching allowed
+
+ BOOL bRet = mpGraphics->DrawNativeControl(nType, nPart, screenRegion, nState, *aScreenCtrlValue, aCaption, this );
+
+ return bRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::DrawNativeControlText(ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ ::rtl::OUString aCaption )
+{
+ if( !lcl_enableNativeWidget( *this ) )
+ return FALSE;
+
+ // make sure the current clip region is initialized correctly
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return false;
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+ if ( mbOutputClipped )
+ return true;
+
+ if ( mbInitLineColor )
+ ImplInitLineColor();
+ if ( mbInitFillColor )
+ ImplInitFillColor();
+
+ // Convert the coordinates from relative to Window-absolute, so we draw
+ // in the correct place in platform code
+ boost::shared_ptr< ImplControlValue > aScreenCtrlValue( lcl_transformControlValue( aValue, *this ) );
+ Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );
+
+ BOOL bRet = mpGraphics->DrawNativeControlText(nType, nPart, screenRegion, nState, *aScreenCtrlValue, aCaption, this );
+
+ return bRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ ::rtl::OUString aCaption,
+ Rectangle &rNativeBoundingRegion,
+ Rectangle &rNativeContentRegion )
+{
+ if( !lcl_enableNativeWidget( *this ) )
+ return FALSE;
+
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return FALSE;
+
+ // Convert the coordinates from relative to Window-absolute, so we draw
+ // in the correct place in platform code
+ boost::shared_ptr< ImplControlValue > aScreenCtrlValue( lcl_transformControlValue( aValue, *this ) );
+ Rectangle screenRegion( ImplLogicToDevicePixel( rControlRegion ) );
+
+ BOOL bRet = mpGraphics->GetNativeControlRegion(nType, nPart, screenRegion, nState, *aScreenCtrlValue,
+ aCaption, rNativeBoundingRegion,
+ rNativeContentRegion, this );
+ if( bRet )
+ {
+ // transform back native regions
+ rNativeBoundingRegion = ImplDevicePixelToLogic( rNativeBoundingRegion );
+ rNativeContentRegion = ImplDevicePixelToLogic( rNativeContentRegion );
+ }
+
+ return bRet;
+}
+
+
diff --git a/vcl/source/gdi/outmap.cxx b/vcl/source/gdi/outmap.cxx
new file mode 100644
index 000000000000..189ba4c29e59
--- /dev/null
+++ b/vcl/source/gdi/outmap.cxx
@@ -0,0 +1,2507 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <limits.h>
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <tools/bigint.hxx>
+#include <tools/debug.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svdata.hxx>
+#include <tools/poly.hxx>
+#include <vcl/region.hxx>
+#include <vcl/region.h>
+#include <vcl/window.h>
+#include <vcl/wrkwin.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/outdev.h>
+#include <vcl/salgdi.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+#define USE_64BIT_INTS
+
+// =======================================================================
+
+DBG_NAMEEX( OutputDevice )
+DBG_NAMEEX( Polygon )
+DBG_NAMEEX( PolyPolygon )
+DBG_NAMEEX( Region )
+
+// =======================================================================
+
+static long aImplNumeratorAry[MAP_PIXEL+1] =
+ { 1, 1, 5, 50, 1, 1, 1, 1, 1, 1, 1 };
+static long aImplDenominatorAry[MAP_PIXEL+1] =
+ { 2540, 254, 127, 127, 1000, 100, 10, 1, 72, 1440, 1 };
+
+// -----------------------------------------------------------------------
+
+/*
+Reduziert die Genauigkeit bis eine Fraction draus wird (sollte mal
+ein Fraction ctor werden) koennte man dann auch mit BigInts machen
+*/
+
+static Fraction ImplMakeFraction( long nN1, long nN2, long nD1, long nD2 )
+{
+ long i = 1;
+
+ if ( nN1 < 0 ) { i = -i; nN1 = -nN1; }
+ if ( nN2 < 0 ) { i = -i; nN2 = -nN2; }
+ if ( nD1 < 0 ) { i = -i; nD1 = -nD1; }
+ if ( nD2 < 0 ) { i = -i; nD2 = -nD2; }
+ // alle positiv; i Vorzeichen
+
+ Fraction aF( i*nN1, nD1 );
+ aF *= Fraction( nN2, nD2 );
+
+ if( nD1 == 0 || nD2 == 0 ) //under these bad circumstances the following while loop will be endless
+ {
+ DBG_ASSERT(false,"Invalid parameter for ImplMakeFraction");
+ return Fraction( 1, 1 );
+ }
+
+ while ( aF.GetDenominator() == -1 )
+ {
+ if ( nN1 > nN2 )
+ nN1 = (nN1 + 1) / 2;
+ else
+ nN2 = (nN2 + 1) / 2;
+ if ( nD1 > nD2 )
+ nD1 = (nD1 + 1) / 2;
+ else
+ nD2 = (nD2 + 1) / 2;
+
+ aF = Fraction( i*nN1, nD1 );
+ aF *= Fraction( nN2, nD2 );
+ }
+
+ return aF;
+}
+
+// -----------------------------------------------------------------------
+
+// Fraction.GetNumerator()
+// Fraction.GetDenominator() > 0
+// rOutRes.nPixPerInch? > 0
+// rMapRes.nMapScNum?
+// rMapRes.nMapScDenom? > 0
+
+static void ImplCalcBigIntThreshold( long nDPIX, long nDPIY,
+ const ImplMapRes& rMapRes,
+ ImplThresholdRes& rThresRes )
+{
+ if ( nDPIX && (LONG_MAX / nDPIX < Abs( rMapRes.mnMapScNumX ) ) ) // #111139# avoid div by zero
+ {
+ rThresRes.mnThresLogToPixX = 0;
+ rThresRes.mnThresPixToLogX = 0;
+ }
+ else
+ {
+ // Schwellenwerte fuer BigInt Arithmetik berechnen
+ long nDenomHalfX = rMapRes.mnMapScDenomX / 2;
+ ULONG nDenomX = rMapRes.mnMapScDenomX;
+ long nProductX = nDPIX * rMapRes.mnMapScNumX;
+
+ if ( !nProductX )
+ rThresRes.mnThresLogToPixX = LONG_MAX;
+ else
+ rThresRes.mnThresLogToPixX = Abs( (LONG_MAX - nDenomHalfX) / nProductX );
+
+ if ( !nDenomX )
+ rThresRes.mnThresPixToLogX = LONG_MAX;
+ else if ( nProductX >= 0 )
+ rThresRes.mnThresPixToLogX = (long)(((ULONG)LONG_MAX - (ULONG)( nProductX/2)) / nDenomX);
+ else
+ rThresRes.mnThresPixToLogX = (long)(((ULONG)LONG_MAX + (ULONG)(-nProductX/2)) / nDenomX);
+ }
+
+ if ( nDPIY && (LONG_MAX / nDPIY < Abs( rMapRes.mnMapScNumY ) ) ) // #111139# avoid div by zero
+ {
+ rThresRes.mnThresLogToPixY = 0;
+ rThresRes.mnThresPixToLogY = 0;
+ }
+ else
+ {
+ // Schwellenwerte fuer BigInt Arithmetik berechnen
+ long nDenomHalfY = rMapRes.mnMapScDenomY / 2;
+ ULONG nDenomY = rMapRes.mnMapScDenomY;
+ long nProductY = nDPIY * rMapRes.mnMapScNumY;
+
+ if ( !nProductY )
+ rThresRes.mnThresLogToPixY = LONG_MAX;
+ else
+ rThresRes.mnThresLogToPixY = Abs( (LONG_MAX - nDenomHalfY) / nProductY );
+
+ if ( !nDenomY )
+ rThresRes.mnThresPixToLogY = LONG_MAX;
+ else if ( nProductY >= 0 )
+ rThresRes.mnThresPixToLogY = (long)(((ULONG)LONG_MAX - (ULONG)( nProductY/2)) / nDenomY);
+ else
+ rThresRes.mnThresPixToLogY = (long)(((ULONG)LONG_MAX + (ULONG)(-nProductY/2)) / nDenomY);
+ }
+
+#ifdef USE_64BIT_INTS
+ rThresRes.mnThresLogToPixX /= 2;
+ rThresRes.mnThresLogToPixY /= 2;
+ rThresRes.mnThresPixToLogX /= 2;
+ rThresRes.mnThresPixToLogY /= 2;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCalcMapResolution( const MapMode& rMapMode,
+ long nDPIX, long nDPIY, ImplMapRes& rMapRes )
+{
+ switch ( rMapMode.GetMapUnit() )
+ {
+ case MAP_RELATIVE:
+ break;
+ case MAP_100TH_MM:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 2540;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 2540;
+ break;
+ case MAP_10TH_MM:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 254;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 254;
+ break;
+ case MAP_MM:
+ rMapRes.mnMapScNumX = 5; // 10
+ rMapRes.mnMapScDenomX = 127; // 254
+ rMapRes.mnMapScNumY = 5; // 10
+ rMapRes.mnMapScDenomY = 127; // 254
+ break;
+ case MAP_CM:
+ rMapRes.mnMapScNumX = 50; // 100
+ rMapRes.mnMapScDenomX = 127; // 254
+ rMapRes.mnMapScNumY = 50; // 100
+ rMapRes.mnMapScDenomY = 127; // 254
+ break;
+ case MAP_1000TH_INCH:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 1000;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 1000;
+ break;
+ case MAP_100TH_INCH:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 100;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 100;
+ break;
+ case MAP_10TH_INCH:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 10;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 10;
+ break;
+ case MAP_INCH:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 1;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 1;
+ break;
+ case MAP_POINT:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 72;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 72;
+ break;
+ case MAP_TWIP:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = 1440;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = 1440;
+ break;
+ case MAP_PIXEL:
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = nDPIX;
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = nDPIY;
+ break;
+ case MAP_SYSFONT:
+ case MAP_APPFONT:
+ case MAP_REALAPPFONT:
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maGDIData.mnAppFontX )
+ {
+ if( pSVData->maWinData.mpFirstFrame )
+ Window::ImplInitAppFontData( pSVData->maWinData.mpFirstFrame );
+ else
+ {
+ WorkWindow* pWin = new WorkWindow( NULL, 0 );
+ Window::ImplInitAppFontData( pWin );
+ delete pWin;
+ }
+ }
+ if ( rMapMode.GetMapUnit() == MAP_REALAPPFONT )
+ rMapRes.mnMapScNumX = pSVData->maGDIData.mnRealAppFontX;
+ else
+ rMapRes.mnMapScNumX = pSVData->maGDIData.mnAppFontX;
+ rMapRes.mnMapScDenomX = nDPIX * 40;
+ rMapRes.mnMapScNumY = pSVData->maGDIData.mnAppFontY;;
+ rMapRes.mnMapScDenomY = nDPIY * 80;
+ }
+ break;
+ default:
+ DBG_ERROR( "unhandled MapUnit" );
+ break;
+ }
+
+ Fraction aScaleX = rMapMode.GetScaleX();
+ Fraction aScaleY = rMapMode.GetScaleY();
+
+ // Offset laut MapMode setzen
+ Point aOrigin = rMapMode.GetOrigin();
+ if ( rMapMode.GetMapUnit() != MAP_RELATIVE )
+ {
+ rMapRes.mnMapOfsX = aOrigin.X();
+ rMapRes.mnMapOfsY = aOrigin.Y();
+ }
+ else
+ {
+ BigInt aX( rMapRes.mnMapOfsX );
+ aX *= BigInt( aScaleX.GetDenominator() );
+ if ( rMapRes.mnMapOfsX >= 0 )
+ {
+ if ( aScaleX.GetNumerator() >= 0 )
+ aX += BigInt( aScaleX.GetNumerator()/2 );
+ else
+ aX -= BigInt( (aScaleX.GetNumerator()+1)/2 );
+ }
+ else
+ {
+ if ( aScaleX.GetNumerator() >= 0 )
+ aX -= BigInt( (aScaleX.GetNumerator()-1)/2 );
+ else
+ aX += BigInt( aScaleX.GetNumerator()/2 );
+ }
+ aX /= BigInt( aScaleX.GetNumerator() );
+ rMapRes.mnMapOfsX = (long)aX + aOrigin.X();
+ BigInt aY( rMapRes.mnMapOfsY );
+ aY *= BigInt( aScaleY.GetDenominator() );
+ if( rMapRes.mnMapOfsY >= 0 )
+ {
+ if ( aScaleY.GetNumerator() >= 0 )
+ aY += BigInt( aScaleY.GetNumerator()/2 );
+ else
+ aY -= BigInt( (aScaleY.GetNumerator()+1)/2 );
+ }
+ else
+ {
+ if ( aScaleY.GetNumerator() >= 0 )
+ aY -= BigInt( (aScaleY.GetNumerator()-1)/2 );
+ else
+ aY += BigInt( aScaleY.GetNumerator()/2 );
+ }
+ aY /= BigInt( aScaleY.GetNumerator() );
+ rMapRes.mnMapOfsY = (long)aY + aOrigin.Y();
+ }
+
+ // Scaling Faktor laut MapMode einberechnen
+ // aTemp? = rMapRes.mnMapSc? * aScale?
+ Fraction aTempX = ImplMakeFraction( rMapRes.mnMapScNumX,
+ aScaleX.GetNumerator(),
+ rMapRes.mnMapScDenomX,
+ aScaleX.GetDenominator() );
+ Fraction aTempY = ImplMakeFraction( rMapRes.mnMapScNumY,
+ aScaleY.GetNumerator(),
+ rMapRes.mnMapScDenomY,
+ aScaleY.GetDenominator() );
+ rMapRes.mnMapScNumX = aTempX.GetNumerator();
+ rMapRes.mnMapScDenomX = aTempX.GetDenominator();
+ rMapRes.mnMapScNumY = aTempY.GetNumerator();
+ rMapRes.mnMapScDenomY = aTempY.GetDenominator();
+
+ // hack: 0/n ungef"ahr 1/max
+ if ( !rMapRes.mnMapScNumX )
+ {
+ rMapRes.mnMapScNumX = 1;
+ rMapRes.mnMapScDenomX = LONG_MAX;
+ }
+ if ( !rMapRes.mnMapScNumY )
+ {
+ rMapRes.mnMapScNumY = 1;
+ rMapRes.mnMapScDenomY = LONG_MAX;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline void ImplCalcMapResolution( const MapMode& rMapMode,
+ long nDPIX, long nDPIY,
+ ImplMapRes& rMapRes,
+ ImplThresholdRes& rThresRes )
+{
+ ImplCalcMapResolution( rMapMode, nDPIX, nDPIY, rMapRes );
+ ImplCalcBigIntThreshold( nDPIX, nDPIY, rMapRes, rThresRes );
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplLogicToPixel( long n, long nDPI, long nMapNum, long nMapDenom,
+ long nThres )
+{
+ // To "use" it...
+ (void) nThres;
+#ifdef USE_64BIT_INTS
+#if (SAL_TYPES_SIZEOFLONG < 8)
+ if( (+n < nThres) && (-n < nThres) )
+ {
+ n *= nMapNum * nDPI;
+ if( nMapDenom != 1 )
+ {
+ n = (2 * n) / nMapDenom;
+ if( n < 0 ) --n; else ++n;
+ n /= 2;
+ }
+ }
+ else
+#endif
+ {
+ sal_Int64 n64 = n;
+ n64 *= nMapNum;
+ n64 *= nDPI;
+ if( nMapDenom == 1 )
+ n = (long)n64;
+ else
+ {
+ n = (long)(2 * n64 / nMapDenom);
+ if( n < 0 ) --n; else ++n;
+ n /= 2;
+ }
+ }
+ return n;
+#else // USE_64BIT_INTS
+ if ( Abs( n ) < nThres )
+ {
+ n *= nDPI * nMapNum;
+ n += n >= 0 ? nMapDenom/2 : -((nMapDenom-1)/2);
+ return (n / nMapDenom);
+ }
+ else
+ {
+ BigInt aTemp( n );
+ aTemp *= BigInt( nDPI );
+ aTemp *= BigInt( nMapNum );
+
+ if ( aTemp.IsNeg() )
+ {
+ BigInt aMapScDenom2( (nMapDenom-1)/2 );
+ aTemp -= aMapScDenom2;
+ }
+ else
+ {
+ BigInt aMapScDenom2( nMapDenom/2 );
+ aTemp += aMapScDenom2;
+ }
+
+ aTemp /= BigInt( nMapDenom );
+ return (long)aTemp;
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplPixelToLogic( long n, long nDPI, long nMapNum, long nMapDenom,
+ long nThres )
+{
+ // To "use" it...
+ (void) nThres;
+#ifdef USE_64BIT_INTS
+#if (SAL_TYPES_SIZEOFLONG < 8)
+ if( (+n < nThres) && (-n < nThres) )
+ n = (2 * n * nMapDenom) / (nDPI * nMapNum);
+ else
+#endif
+ {
+ sal_Int64 n64 = n;
+ n64 *= nMapDenom;
+ long nDenom = nDPI * nMapNum;
+ n = (long)(2 * n64 / nDenom);
+ }
+ if( n < 0 ) --n; else ++n;
+ return (n / 2);
+#else // USE_64BIT_INTS
+ if ( Abs( n ) < nThres )
+ {
+ long nDenom = nDPI * nMapNum;
+ long nNum = n * nMapDenom;
+ if( (nNum ^ nDenom) >= 0 )
+ nNum += nDenom/2;
+ else
+ nNum -= nDenom/2;
+ return (nNum / nDenom);
+ }
+ else
+ {
+ BigInt aDenom( nDPI );
+ aDenom *= BigInt( nMapNum );
+
+ BigInt aNum( n );
+ aNum *= BigInt( nMapDenom );
+
+ BigInt aDenom2( aDenom );
+ if ( aNum.IsNeg() )
+ {
+ if ( aDenom.IsNeg() )
+ {
+ aDenom2 /= BigInt(2);
+ aNum += aDenom2;
+ }
+ else
+ {
+ aDenom2 -= 1;
+ aDenom2 /= BigInt(2);
+ aNum -= aDenom2;
+ }
+ }
+ else
+ {
+ if ( aDenom.IsNeg() )
+ {
+ aDenom2 += 1;
+ aDenom2 /= BigInt(2);
+ aNum -= aDenom2;
+ }
+ else
+ {
+ aDenom2 /= BigInt(2);
+ aNum += aDenom2;
+ }
+ }
+
+ aNum /= aDenom;
+ return (long)aNum;
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplLogicXToDevicePixel( long nX ) const
+{
+ if ( !mbMap )
+ return nX+mnOutOffX;
+
+ return ImplLogicToPixel( nX + maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffX+mnOutOffOrigX;
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplLogicYToDevicePixel( long nY ) const
+{
+ if ( !mbMap )
+ return nY+mnOutOffY;
+
+ return ImplLogicToPixel( nY + maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffY+mnOutOffOrigY;
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplLogicWidthToDevicePixel( long nWidth ) const
+{
+ if ( !mbMap )
+ return nWidth;
+
+ return ImplLogicToPixel( nWidth, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX );
+}
+
+float OutputDevice::ImplFloatLogicWidthToDevicePixel( float fLogicWidth) const
+{
+ if( !mbMap)
+ return fLogicWidth;
+ // TODO: consolidate the calculation into one multiplication
+ float fPixelWidth = (fLogicWidth * mnDPIX * maMapRes.mnMapScNumX) / maMapRes.mnMapScDenomX;
+ return fPixelWidth;
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplLogicHeightToDevicePixel( long nHeight ) const
+{
+ if ( !mbMap )
+ return nHeight;
+
+ return ImplLogicToPixel( nHeight, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY );
+}
+
+float OutputDevice::ImplFloatLogicHeightToDevicePixel( float fLogicHeight) const
+{
+ if( !mbMap)
+ return fLogicHeight;
+ float fPixelHeight = (fLogicHeight * mnDPIY * maMapRes.mnMapScNumY) / maMapRes.mnMapScDenomY;
+ return fPixelHeight;
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplDevicePixelToLogicWidth( long nWidth ) const
+{
+ if ( !mbMap )
+ return nWidth;
+
+ return ImplPixelToLogic( nWidth, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX );
+}
+
+float OutputDevice::ImplFloatDevicePixelToLogicWidth( float fPixelWidth) const
+{
+ if( !mbMap)
+ return fPixelWidth;
+ float fLogicHeight = (fPixelWidth * maMapRes.mnMapScDenomX) / (mnDPIX * maMapRes.mnMapScNumX);
+ return fLogicHeight;
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::ImplDevicePixelToLogicHeight( long nHeight ) const
+{
+ if ( !mbMap )
+ return nHeight;
+
+ return ImplPixelToLogic( nHeight, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY );
+}
+
+float OutputDevice::ImplFloatDevicePixelToLogicHeight( float fPixelHeight) const
+{
+ if( !mbMap)
+ return fPixelHeight;
+ float fLogicHeight = (fPixelHeight * maMapRes.mnMapScDenomY) / (mnDPIY * maMapRes.mnMapScNumY);
+ return fLogicHeight;
+}
+
+
+// -----------------------------------------------------------------------
+
+Point OutputDevice::ImplLogicToDevicePixel( const Point& rLogicPt ) const
+{
+ if ( !mbMap )
+ return Point( rLogicPt.X()+mnOutOffX, rLogicPt.Y()+mnOutOffY );
+
+ return Point( ImplLogicToPixel( rLogicPt.X() + maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffX+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicPt.Y() + maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffY+mnOutOffOrigY );
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::ImplLogicToDevicePixel( const Size& rLogicSize ) const
+{
+ if ( !mbMap )
+ return rLogicSize;
+
+ return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX ),
+ ImplLogicToPixel( rLogicSize.Height(), mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY ) );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::ImplLogicToDevicePixel( const Rectangle& rLogicRect ) const
+{
+ if ( rLogicRect.IsEmpty() )
+ return rLogicRect;
+
+ if ( !mbMap )
+ {
+ return Rectangle( rLogicRect.Left()+mnOutOffX, rLogicRect.Top()+mnOutOffY,
+ rLogicRect.Right()+mnOutOffX, rLogicRect.Bottom()+mnOutOffY );
+ }
+
+ return Rectangle( ImplLogicToPixel( rLogicRect.Left()+maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffX+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicRect.Top()+maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffY+mnOutOffOrigY,
+ ImplLogicToPixel( rLogicRect.Right()+maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffX+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicRect.Bottom()+maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffY+mnOutOffOrigY );
+}
+
+// -----------------------------------------------------------------------
+
+Polygon OutputDevice::ImplLogicToDevicePixel( const Polygon& rLogicPoly ) const
+{
+ if ( !mbMap && !mnOutOffX && !mnOutOffY )
+ return rLogicPoly;
+
+ USHORT i;
+ USHORT nPoints = rLogicPoly.GetSize();
+ Polygon aPoly( rLogicPoly );
+
+ // Pointer auf das Point-Array holen (Daten werden kopiert)
+ const Point* pPointAry = aPoly.GetConstPointAry();
+
+ if ( mbMap )
+ {
+ for ( i = 0; i < nPoints; i++ )
+ {
+ const Point* pPt = &(pPointAry[i]);
+ Point aPt;
+ aPt.X() = ImplLogicToPixel( pPt->X()+maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffX+mnOutOffOrigX;
+ aPt.Y() = ImplLogicToPixel( pPt->Y()+maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffY+mnOutOffOrigY;
+ aPoly[i] = aPt;
+ }
+ }
+ else
+ {
+ for ( i = 0; i < nPoints; i++ )
+ {
+ Point aPt = pPointAry[i];
+ aPt.X() += mnOutOffX;
+ aPt.Y() += mnOutOffY;
+ aPoly[i] = aPt;
+ }
+ }
+
+ return aPoly;
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon OutputDevice::ImplLogicToDevicePixel( const PolyPolygon& rLogicPolyPoly ) const
+{
+ if ( !mbMap && !mnOutOffX && !mnOutOffY )
+ return rLogicPolyPoly;
+
+ PolyPolygon aPolyPoly( rLogicPolyPoly );
+ USHORT nPoly = aPolyPoly.Count();
+ for( USHORT i = 0; i < nPoly; i++ )
+ {
+ Polygon& rPoly = aPolyPoly[i];
+ rPoly = ImplLogicToDevicePixel( rPoly );
+ }
+ return aPolyPoly;
+}
+
+// -----------------------------------------------------------------------
+
+LineInfo OutputDevice::ImplLogicToDevicePixel( const LineInfo& rLineInfo ) const
+{
+ LineInfo aInfo( rLineInfo );
+
+ if( aInfo.GetStyle() == LINE_DASH )
+ {
+ if( aInfo.GetDotCount() && aInfo.GetDotLen() )
+ aInfo.SetDotLen( Max( ImplLogicWidthToDevicePixel( aInfo.GetDotLen() ), 1L ) );
+ else
+ aInfo.SetDotCount( 0 );
+
+ if( aInfo.GetDashCount() && aInfo.GetDashLen() )
+ aInfo.SetDashLen( Max( ImplLogicWidthToDevicePixel( aInfo.GetDashLen() ), 1L ) );
+ else
+ aInfo.SetDashCount( 0 );
+
+ aInfo.SetDistance( ImplLogicWidthToDevicePixel( aInfo.GetDistance() ) );
+
+ if( ( !aInfo.GetDashCount() && !aInfo.GetDotCount() ) || !aInfo.GetDistance() )
+ aInfo.SetStyle( LINE_SOLID );
+ }
+
+ aInfo.SetWidth( ImplLogicWidthToDevicePixel( aInfo.GetWidth() ) );
+
+ return aInfo;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::ImplDevicePixelToLogic( const Rectangle& rPixelRect ) const
+{
+ if ( rPixelRect.IsEmpty() )
+ return rPixelRect;
+
+ if ( !mbMap )
+ {
+ return Rectangle( rPixelRect.Left()-mnOutOffX, rPixelRect.Top()-mnOutOffY,
+ rPixelRect.Right()-mnOutOffX, rPixelRect.Bottom()-mnOutOffY );
+ }
+
+ return Rectangle( ImplPixelToLogic( rPixelRect.Left()-mnOutOffX-mnOutOffOrigX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX )-maMapRes.mnMapOfsX,
+ ImplPixelToLogic( rPixelRect.Top()-mnOutOffY-mnOutOffOrigY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY )-maMapRes.mnMapOfsY,
+ ImplPixelToLogic( rPixelRect.Right()-mnOutOffX-mnOutOffOrigX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX )-maMapRes.mnMapOfsX,
+ ImplPixelToLogic( rPixelRect.Bottom()-mnOutOffY-mnOutOffOrigY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY )-maMapRes.mnMapOfsY );
+}
+
+// -----------------------------------------------------------------------
+
+Region OutputDevice::ImplPixelToDevicePixel( const Region& rRegion ) const
+{
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+
+ if ( !mnOutOffX && !mnOutOffY )
+ return rRegion;
+
+ Region aRegion( rRegion );
+ aRegion.Move( mnOutOffX+mnOutOffOrigX, mnOutOffY+mnOutOffOrigY );
+ return aRegion;
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::EnableMapMode( BOOL bEnable )
+{
+ mbMap = (bEnable != 0);
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->EnableMapMode( bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetMapMode()
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaMapModeAction( MapMode() ) );
+
+ if ( mbMap || !maMapMode.IsDefault() )
+ {
+ mbMap = FALSE;
+ maMapMode = MapMode();
+
+ // create new objects (clip region werden nicht neu skaliert)
+ mbNewFont = TRUE;
+ mbInitFont = TRUE;
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ if ( ((Window*)this)->mpWindowImpl->mpCursor )
+ ((Window*)this)->mpWindowImpl->mpCursor->ImplNew();
+ }
+
+ // #106426# Adapt logical offset when changing mapmode
+ mnOutOffLogicX = mnOutOffOrigX; // no mapping -> equal offsets
+ mnOutOffLogicY = mnOutOffOrigY;
+
+ // #i75163#
+ ImplInvalidateViewTransform();
+ }
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetMapMode();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetMapMode( const MapMode& rNewMapMode )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ BOOL bRelMap = (rNewMapMode.GetMapUnit() == MAP_RELATIVE);
+
+ if ( mpMetaFile )
+ {
+ mpMetaFile->AddAction( new MetaMapModeAction( rNewMapMode ) );
+#ifdef DBG_UTIL
+ if ( GetOutDevType() != OUTDEV_PRINTER )
+ DBG_ASSERTWARNING( bRelMap, "Please record only relative MapModes!" );
+#endif
+ }
+
+ // Ist der MapMode der gleiche wie vorher, dann mache nichts
+ if ( maMapMode == rNewMapMode )
+ return;
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetMapMode( rNewMapMode );
+
+ // Ist Default-MapMode, dann bereche nichts
+ BOOL bOldMap = mbMap;
+ mbMap = !rNewMapMode.IsDefault();
+ if ( mbMap )
+ {
+ // Falls nur der Orign umgesetzt wird, dann scaliere nichts neu
+ if ( (rNewMapMode.GetMapUnit() == maMapMode.GetMapUnit()) &&
+ (rNewMapMode.GetScaleX() == maMapMode.GetScaleX()) &&
+ (rNewMapMode.GetScaleY() == maMapMode.GetScaleY()) &&
+ (bOldMap == mbMap) )
+ {
+ // Offset setzen
+ Point aOrigin = rNewMapMode.GetOrigin();
+ maMapRes.mnMapOfsX = aOrigin.X();
+ maMapRes.mnMapOfsY = aOrigin.Y();
+ maMapMode = rNewMapMode;
+
+ // #i75163#
+ ImplInvalidateViewTransform();
+
+ return;
+ }
+ if ( !bOldMap && bRelMap )
+ {
+ maMapRes.mnMapScNumX = 1;
+ maMapRes.mnMapScNumY = 1;
+ maMapRes.mnMapScDenomX = mnDPIX;
+ maMapRes.mnMapScDenomY = mnDPIY;
+ maMapRes.mnMapOfsX = 0;
+ maMapRes.mnMapOfsY = 0;
+ }
+
+ // Neue MapMode-Aufloesung berechnen
+ ImplCalcMapResolution( rNewMapMode, mnDPIX, mnDPIY, maMapRes, maThresRes );
+ }
+
+ // Neuen MapMode setzen
+ if ( bRelMap )
+ {
+ Point aOrigin( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
+ // aScale? = maMapMode.GetScale?() * rNewMapMode.GetScale?()
+ Fraction aScaleX = ImplMakeFraction( maMapMode.GetScaleX().GetNumerator(),
+ rNewMapMode.GetScaleX().GetNumerator(),
+ maMapMode.GetScaleX().GetDenominator(),
+ rNewMapMode.GetScaleX().GetDenominator() );
+ Fraction aScaleY = ImplMakeFraction( maMapMode.GetScaleY().GetNumerator(),
+ rNewMapMode.GetScaleY().GetNumerator(),
+ maMapMode.GetScaleY().GetDenominator(),
+ rNewMapMode.GetScaleY().GetDenominator() );
+ maMapMode.SetOrigin( aOrigin );
+ maMapMode.SetScaleX( aScaleX );
+ maMapMode.SetScaleY( aScaleY );
+ }
+ else
+ maMapMode = rNewMapMode;
+
+ // create new objects (clip region werden nicht neu skaliert)
+ mbNewFont = TRUE;
+ mbInitFont = TRUE;
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ if ( ((Window*)this)->mpWindowImpl->mpCursor )
+ ((Window*)this)->mpWindowImpl->mpCursor->ImplNew();
+ }
+
+ // #106426# Adapt logical offset when changing mapmode
+ mnOutOffLogicX = ImplPixelToLogic( mnOutOffOrigX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX );
+ mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY );
+
+ // #i75163#
+ ImplInvalidateViewTransform();
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetRelativeMapMode( const MapMode& rNewMapMode )
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // Ist der MapMode der gleiche wie vorher, dann mache nichts
+ if ( maMapMode == rNewMapMode )
+ return;
+
+ MapUnit eOld = maMapMode.GetMapUnit();
+ MapUnit eNew = rNewMapMode.GetMapUnit();
+
+ // a?F = rNewMapMode.GetScale?() / maMapMode.GetScale?()
+ Fraction aXF = ImplMakeFraction( rNewMapMode.GetScaleX().GetNumerator(),
+ maMapMode.GetScaleX().GetDenominator(),
+ rNewMapMode.GetScaleX().GetDenominator(),
+ maMapMode.GetScaleX().GetNumerator() );
+ Fraction aYF = ImplMakeFraction( rNewMapMode.GetScaleY().GetNumerator(),
+ maMapMode.GetScaleY().GetDenominator(),
+ rNewMapMode.GetScaleY().GetDenominator(),
+ maMapMode.GetScaleY().GetNumerator() );
+
+ Point aPt( LogicToLogic( Point(), NULL, &rNewMapMode ) );
+ if ( eNew != eOld )
+ {
+ if ( eOld > MAP_PIXEL )
+ {
+ DBG_ERRORFILE( "Not implemented MapUnit" );
+ }
+ else if ( eNew > MAP_PIXEL )
+ {
+ DBG_ERRORFILE( "Not implemented MapUnit" );
+ }
+ else
+ {
+ Fraction aF( aImplNumeratorAry[eNew] * aImplDenominatorAry[eOld],
+ aImplNumeratorAry[eOld] * aImplDenominatorAry[eNew] );
+
+ // a?F = a?F * aF
+ aXF = ImplMakeFraction( aXF.GetNumerator(), aF.GetNumerator(),
+ aXF.GetDenominator(), aF.GetDenominator() );
+ aYF = ImplMakeFraction( aYF.GetNumerator(), aF.GetNumerator(),
+ aYF.GetDenominator(), aF.GetDenominator() );
+ if ( eOld == MAP_PIXEL )
+ {
+ aXF *= Fraction( mnDPIX, 1 );
+ aYF *= Fraction( mnDPIY, 1 );
+ }
+ else if ( eNew == MAP_PIXEL )
+ {
+ aXF *= Fraction( 1, mnDPIX );
+ aYF *= Fraction( 1, mnDPIY );
+ }
+ }
+ }
+
+ MapMode aNewMapMode( MAP_RELATIVE, Point( -aPt.X(), -aPt.Y() ), aXF, aYF );
+ SetMapMode( aNewMapMode );
+
+ if ( eNew != eOld )
+ maMapMode = rNewMapMode;
+
+ // #106426# Adapt logical offset when changing mapmode
+ mnOutOffLogicX = ImplPixelToLogic( mnOutOffOrigX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX );
+ mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetRelativeMapMode( rNewMapMode );
+}
+
+// -----------------------------------------------------------------------
+
+// #i75163#
+basegfx::B2DHomMatrix OutputDevice::GetViewTransformation() const
+{
+ if(mbMap)
+ {
+ // #i82615#
+ if(!mpOutDevData)
+ {
+ const_cast< OutputDevice* >(this)->ImplInitOutDevData();
+ }
+
+ if(!mpOutDevData->mpViewTransform)
+ {
+ mpOutDevData->mpViewTransform = new basegfx::B2DHomMatrix;
+
+ const double fScaleFactorX((double)mnDPIX * (double)maMapRes.mnMapScNumX / (double)maMapRes.mnMapScDenomX);
+ const double fScaleFactorY((double)mnDPIY * (double)maMapRes.mnMapScNumY / (double)maMapRes.mnMapScDenomY);
+ const double fZeroPointX(((double)maMapRes.mnMapOfsX * fScaleFactorX) + (double)mnOutOffOrigX);
+ const double fZeroPointY(((double)maMapRes.mnMapOfsY * fScaleFactorY) + (double)mnOutOffOrigY);
+
+ mpOutDevData->mpViewTransform->set(0, 0, fScaleFactorX);
+ mpOutDevData->mpViewTransform->set(1, 1, fScaleFactorY);
+ mpOutDevData->mpViewTransform->set(0, 2, fZeroPointX);
+ mpOutDevData->mpViewTransform->set(1, 2, fZeroPointY);
+ }
+
+ return *mpOutDevData->mpViewTransform;
+ }
+ else
+ {
+ return basegfx::B2DHomMatrix();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// #i75163#
+basegfx::B2DHomMatrix OutputDevice::GetInverseViewTransformation() const
+{
+ if(mbMap)
+ {
+ // #i82615#
+ if(!mpOutDevData)
+ {
+ const_cast< OutputDevice* >(this)->ImplInitOutDevData();
+ }
+
+ if(!mpOutDevData->mpInverseViewTransform)
+ {
+ GetViewTransformation();
+ mpOutDevData->mpInverseViewTransform = new basegfx::B2DHomMatrix(*mpOutDevData->mpViewTransform);
+ mpOutDevData->mpInverseViewTransform->invert();
+ }
+
+ return *mpOutDevData->mpInverseViewTransform;
+ }
+ else
+ {
+ return basegfx::B2DHomMatrix();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// #i75163#
+basegfx::B2DHomMatrix OutputDevice::GetViewTransformation( const MapMode& rMapMode ) const
+{
+ // #i82615#
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ basegfx::B2DHomMatrix aTransform;
+
+ const double fScaleFactorX((double)mnDPIX * (double)aMapRes.mnMapScNumX / (double)aMapRes.mnMapScDenomX);
+ const double fScaleFactorY((double)mnDPIY * (double)aMapRes.mnMapScNumY / (double)aMapRes.mnMapScDenomY);
+ const double fZeroPointX(((double)aMapRes.mnMapOfsX * fScaleFactorX) + (double)mnOutOffOrigX);
+ const double fZeroPointY(((double)aMapRes.mnMapOfsY * fScaleFactorY) + (double)mnOutOffOrigY);
+
+ aTransform.set(0, 0, fScaleFactorX);
+ aTransform.set(1, 1, fScaleFactorY);
+ aTransform.set(0, 2, fZeroPointX);
+ aTransform.set(1, 2, fZeroPointY);
+
+ return aTransform;
+}
+
+// -----------------------------------------------------------------------
+
+// #i75163#
+basegfx::B2DHomMatrix OutputDevice::GetInverseViewTransformation( const MapMode& rMapMode ) const
+{
+ basegfx::B2DHomMatrix aMatrix( GetViewTransformation( rMapMode ) );
+ aMatrix.invert();
+ return aMatrix;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DHomMatrix OutputDevice::ImplGetDeviceTransformation() const
+{
+ basegfx::B2DHomMatrix aTransformation = GetViewTransformation();
+ // TODO: is it worth to cache the transformed result?
+ if( mnOutOffX || mnOutOffY )
+ aTransformation.translate( mnOutOffX, mnOutOffY );
+ return aTransformation;
+}
+
+// -----------------------------------------------------------------------
+
+Point OutputDevice::LogicToPixel( const Point& rLogicPt ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !mbMap )
+ return rLogicPt;
+
+ return Point( ImplLogicToPixel( rLogicPt.X() + maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicPt.Y() + maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffOrigY );
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::LogicToPixel( const Size& rLogicSize ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !mbMap )
+ return rLogicSize;
+
+ return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX ),
+ ImplLogicToPixel( rLogicSize.Height(), mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY ) );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::LogicToPixel( const Rectangle& rLogicRect ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !mbMap || rLogicRect.IsEmpty() )
+ return rLogicRect;
+
+ return Rectangle( ImplLogicToPixel( rLogicRect.Left() + maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicRect.Top() + maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffOrigY,
+ ImplLogicToPixel( rLogicRect.Right() + maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicRect.Bottom() + maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffOrigY );
+}
+
+// -----------------------------------------------------------------------
+
+Polygon OutputDevice::LogicToPixel( const Polygon& rLogicPoly ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rLogicPoly, Polygon, NULL );
+
+ if ( !mbMap )
+ return rLogicPoly;
+
+ USHORT i;
+ USHORT nPoints = rLogicPoly.GetSize();
+ Polygon aPoly( rLogicPoly );
+
+ // Pointer auf das Point-Array holen (Daten werden kopiert)
+ const Point* pPointAry = aPoly.GetConstPointAry();
+
+ for ( i = 0; i < nPoints; i++ )
+ {
+ const Point* pPt = &(pPointAry[i]);
+ Point aPt;
+ aPt.X() = ImplLogicToPixel( pPt->X() + maMapRes.mnMapOfsX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresLogToPixX )+mnOutOffOrigX;
+ aPt.Y() = ImplLogicToPixel( pPt->Y() + maMapRes.mnMapOfsY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresLogToPixY )+mnOutOffOrigY;
+ aPoly[i] = aPt;
+ }
+
+ return aPoly;
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon OutputDevice::LogicToPixel( const PolyPolygon& rLogicPolyPoly ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rLogicPolyPoly, PolyPolygon, NULL );
+
+ if ( !mbMap )
+ return rLogicPolyPoly;
+
+ PolyPolygon aPolyPoly( rLogicPolyPoly );
+ USHORT nPoly = aPolyPoly.Count();
+ for( USHORT i = 0; i < nPoly; i++ )
+ {
+ Polygon& rPoly = aPolyPoly[i];
+ rPoly = LogicToPixel( rPoly );
+ }
+ return aPolyPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolygon& rLogicPoly ) const
+{
+ basegfx::B2DPolygon aTransformedPoly = rLogicPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetViewTransformation();
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolyPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolyPolygon& rLogicPolyPoly ) const
+{
+ basegfx::B2DPolyPolygon aTransformedPoly = rLogicPolyPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetViewTransformation();
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+Region OutputDevice::LogicToPixel( const Region& rLogicRegion ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rLogicRegion, Region, ImplDbgTestRegion );
+
+ RegionType eType = rLogicRegion.GetType();
+
+ if ( !mbMap || (eType == REGION_EMPTY) || (eType == REGION_NULL) )
+ return rLogicRegion;
+
+ Region aRegion;
+ const ImplRegion& rImplRegion = *rLogicRegion.ImplGetImplRegion();
+ const PolyPolygon* pPolyPoly = rImplRegion.mpPolyPoly;
+ const basegfx::B2DPolyPolygon* pB2DPolyPoly = rImplRegion.mpB2DPolyPoly;
+
+ if ( pPolyPoly )
+ aRegion = Region( LogicToPixel( *pPolyPoly ) );
+ else if( pB2DPolyPoly )
+ {
+ basegfx::B2DPolyPolygon aTransformedPoly = *pB2DPolyPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetViewTransformation();
+ aTransformedPoly.transform( rTransformationMatrix );
+ aRegion = Region( aTransformedPoly );
+ }
+ else
+ {
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+
+ aRegion.ImplBeginAddRect();
+ bRegionRect = rLogicRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ while ( bRegionRect )
+ {
+ Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ aRegion.ImplAddRect( LogicToPixel( aRect ) );
+ bRegionRect = rLogicRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ aRegion.ImplEndAddRect();
+ }
+
+ return aRegion;
+}
+
+// -----------------------------------------------------------------------
+
+Point OutputDevice::LogicToPixel( const Point& rLogicPt,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( rMapMode.IsDefault() )
+ return rLogicPt;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ return Point( ImplLogicToPixel( rLogicPt.X() + aMapRes.mnMapOfsX, mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresLogToPixX )+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicPt.Y() + aMapRes.mnMapOfsY, mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresLogToPixY )+mnOutOffOrigY );
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::LogicToPixel( const Size& rLogicSize,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( rMapMode.IsDefault() )
+ return rLogicSize;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresLogToPixX ),
+ ImplLogicToPixel( rLogicSize.Height(), mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresLogToPixY ) );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::LogicToPixel( const Rectangle& rLogicRect,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( rMapMode.IsDefault() || rLogicRect.IsEmpty() )
+ return rLogicRect;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ return Rectangle( ImplLogicToPixel( rLogicRect.Left() + aMapRes.mnMapOfsX, mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresLogToPixX )+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicRect.Top() + aMapRes.mnMapOfsY, mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresLogToPixY )+mnOutOffOrigY,
+ ImplLogicToPixel( rLogicRect.Right() + aMapRes.mnMapOfsX, mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresLogToPixX )+mnOutOffOrigX,
+ ImplLogicToPixel( rLogicRect.Bottom() + aMapRes.mnMapOfsY, mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresLogToPixY )+mnOutOffOrigY );
+}
+
+// -----------------------------------------------------------------------
+
+Polygon OutputDevice::LogicToPixel( const Polygon& rLogicPoly,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rLogicPoly, Polygon, NULL );
+
+ if ( rMapMode.IsDefault() )
+ return rLogicPoly;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ USHORT i;
+ USHORT nPoints = rLogicPoly.GetSize();
+ Polygon aPoly( rLogicPoly );
+
+ // Pointer auf das Point-Array holen (Daten werden kopiert)
+ const Point* pPointAry = aPoly.GetConstPointAry();
+
+ for ( i = 0; i < nPoints; i++ )
+ {
+ const Point* pPt = &(pPointAry[i]);
+ Point aPt;
+ aPt.X() = ImplLogicToPixel( pPt->X() + aMapRes.mnMapOfsX, mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresLogToPixX )+mnOutOffOrigX;
+ aPt.Y() = ImplLogicToPixel( pPt->Y() + aMapRes.mnMapOfsY, mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresLogToPixY )+mnOutOffOrigY;
+ aPoly[i] = aPt;
+ }
+
+ return aPoly;
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon OutputDevice::LogicToPixel( const PolyPolygon& rLogicPolyPoly,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rLogicPolyPoly, PolyPolygon, NULL );
+
+ if ( rMapMode.IsDefault() )
+ return rLogicPolyPoly;
+
+ PolyPolygon aPolyPoly( rLogicPolyPoly );
+ USHORT nPoly = aPolyPoly.Count();
+ for( USHORT i = 0; i < nPoly; i++ )
+ {
+ Polygon& rPoly = aPolyPoly[i];
+ rPoly = LogicToPixel( rPoly, rMapMode );
+ }
+ return aPolyPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolyPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolyPolygon& rLogicPolyPoly,
+ const MapMode& rMapMode ) const
+{
+ basegfx::B2DPolyPolygon aTransformedPoly = rLogicPolyPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetViewTransformation( rMapMode );
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolygon& rLogicPoly,
+ const MapMode& rMapMode ) const
+{
+ basegfx::B2DPolygon aTransformedPoly = rLogicPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetViewTransformation( rMapMode );
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+Region OutputDevice::LogicToPixel( const Region& rLogicRegion,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rLogicRegion, Region, ImplDbgTestRegion );
+
+ RegionType eType = rLogicRegion.GetType();
+
+ if ( rMapMode.IsDefault() || (eType == REGION_EMPTY) || (eType == REGION_NULL) )
+ return rLogicRegion;
+
+ Region aRegion;
+ PolyPolygon* pPolyPoly = rLogicRegion.ImplGetImplRegion()->mpPolyPoly;
+
+ if( pPolyPoly )
+ aRegion = Region( LogicToPixel( *pPolyPoly, rMapMode ) );
+ else
+ {
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+
+ aRegion.ImplBeginAddRect();
+ bRegionRect = rLogicRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ while ( bRegionRect )
+ {
+ Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ aRegion.ImplAddRect( LogicToPixel( aRect, rMapMode ) );
+ bRegionRect = rLogicRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ aRegion.ImplEndAddRect();
+ }
+
+ return aRegion;
+}
+
+// -----------------------------------------------------------------------
+
+Point OutputDevice::PixelToLogic( const Point& rDevicePt ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !mbMap )
+ return rDevicePt;
+
+ return Point( ImplPixelToLogic( rDevicePt.X(), mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX - mnOutOffLogicX,
+ ImplPixelToLogic( rDevicePt.Y(), mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY - mnOutOffLogicY );
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::PixelToLogic( const Size& rDeviceSize ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !mbMap )
+ return rDeviceSize;
+
+ return Size( ImplPixelToLogic( rDeviceSize.Width(), mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX ),
+ ImplPixelToLogic( rDeviceSize.Height(), mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY ) );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::PixelToLogic( const Rectangle& rDeviceRect ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ if ( !mbMap || rDeviceRect.IsEmpty() )
+ return rDeviceRect;
+
+ return Rectangle( ImplPixelToLogic( rDeviceRect.Left(), mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX - mnOutOffLogicX,
+ ImplPixelToLogic( rDeviceRect.Top(), mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY - mnOutOffLogicY,
+ ImplPixelToLogic( rDeviceRect.Right(), mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX - mnOutOffLogicX,
+ ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY - mnOutOffLogicY );
+}
+
+// -----------------------------------------------------------------------
+
+Polygon OutputDevice::PixelToLogic( const Polygon& rDevicePoly ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rDevicePoly, Polygon, NULL );
+
+ if ( !mbMap )
+ return rDevicePoly;
+
+ USHORT i;
+ USHORT nPoints = rDevicePoly.GetSize();
+ Polygon aPoly( rDevicePoly );
+
+ // Pointer auf das Point-Array holen (Daten werden kopiert)
+ const Point* pPointAry = aPoly.GetConstPointAry();
+
+ for ( i = 0; i < nPoints; i++ )
+ {
+ const Point* pPt = &(pPointAry[i]);
+ Point aPt;
+ aPt.X() = ImplPixelToLogic( pPt->X(), mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX - mnOutOffLogicX;
+ aPt.Y() = ImplPixelToLogic( pPt->Y(), mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY - mnOutOffLogicY;
+ aPoly[i] = aPt;
+ }
+
+ return aPoly;
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon OutputDevice::PixelToLogic( const PolyPolygon& rDevicePolyPoly ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rDevicePolyPoly, PolyPolygon, NULL );
+
+ if ( !mbMap )
+ return rDevicePolyPoly;
+
+ PolyPolygon aPolyPoly( rDevicePolyPoly );
+ USHORT nPoly = aPolyPoly.Count();
+ for( USHORT i = 0; i < nPoly; i++ )
+ {
+ Polygon& rPoly = aPolyPoly[i];
+ rPoly = PixelToLogic( rPoly );
+ }
+ return aPolyPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolygon& rPixelPoly ) const
+{
+ basegfx::B2DPolygon aTransformedPoly = rPixelPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetInverseViewTransformation();
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolyPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolyPolygon& rPixelPolyPoly ) const
+{
+ basegfx::B2DPolyPolygon aTransformedPoly = rPixelPolyPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetInverseViewTransformation();
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+Region OutputDevice::PixelToLogic( const Region& rDeviceRegion ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rDeviceRegion, Region, ImplDbgTestRegion );
+
+ RegionType eType = rDeviceRegion.GetType();
+
+ if ( !mbMap || (eType == REGION_EMPTY) || (eType == REGION_NULL) )
+ return rDeviceRegion;
+
+ Region aRegion;
+ PolyPolygon* pPolyPoly = rDeviceRegion.ImplGetImplRegion()->mpPolyPoly;
+
+ if ( pPolyPoly )
+ aRegion = Region( PixelToLogic( *pPolyPoly ) );
+ else
+ {
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+
+ aRegion.ImplBeginAddRect();
+ bRegionRect = rDeviceRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ while ( bRegionRect )
+ {
+ Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ aRegion.ImplAddRect( PixelToLogic( aRect ) );
+ bRegionRect = rDeviceRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ aRegion.ImplEndAddRect();
+ }
+
+ return aRegion;
+}
+
+// -----------------------------------------------------------------------
+
+Point OutputDevice::PixelToLogic( const Point& rDevicePt,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // Ist Default-MapMode, dann bereche nichts
+ if ( rMapMode.IsDefault() )
+ return rDevicePt;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ return Point( ImplPixelToLogic( rDevicePt.X(), mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX - mnOutOffLogicX,
+ ImplPixelToLogic( rDevicePt.Y(), mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY - mnOutOffLogicY );
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::PixelToLogic( const Size& rDeviceSize,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // Ist Default-MapMode, dann bereche nichts
+ if ( rMapMode.IsDefault() )
+ return rDeviceSize;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ return Size( ImplPixelToLogic( rDeviceSize.Width(), mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresPixToLogX ),
+ ImplPixelToLogic( rDeviceSize.Height(), mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresPixToLogY ) );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::PixelToLogic( const Rectangle& rDeviceRect,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // Ist Default-MapMode, dann bereche nichts
+ if ( rMapMode.IsDefault() || rDeviceRect.IsEmpty() )
+ return rDeviceRect;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ return Rectangle( ImplPixelToLogic( rDeviceRect.Left(), mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX - mnOutOffLogicX,
+ ImplPixelToLogic( rDeviceRect.Top(), mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY - mnOutOffLogicY,
+ ImplPixelToLogic( rDeviceRect.Right(), mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX - mnOutOffLogicX,
+ ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY - mnOutOffLogicY );
+}
+
+// -----------------------------------------------------------------------
+
+Polygon OutputDevice::PixelToLogic( const Polygon& rDevicePoly,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rDevicePoly, Polygon, NULL );
+
+ // Ist Default-MapMode, dann bereche nichts
+ if ( rMapMode.IsDefault() )
+ return rDevicePoly;
+
+ // MapMode-Aufloesung berechnen und Umrechnen
+ ImplMapRes aMapRes;
+ ImplThresholdRes aThresRes;
+ ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes );
+
+ USHORT i;
+ USHORT nPoints = rDevicePoly.GetSize();
+ Polygon aPoly( rDevicePoly );
+
+ // Pointer auf das Point-Array holen (Daten werden kopiert)
+ const Point* pPointAry = aPoly.GetConstPointAry();
+
+ for ( i = 0; i < nPoints; i++ )
+ {
+ const Point* pPt = &(pPointAry[i]);
+ Point aPt;
+ aPt.X() = ImplPixelToLogic( pPt->X(), mnDPIX,
+ aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX,
+ aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX - mnOutOffLogicX;
+ aPt.Y() = ImplPixelToLogic( pPt->Y(), mnDPIY,
+ aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY,
+ aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY - mnOutOffLogicY;
+ aPoly[i] = aPt;
+ }
+
+ return aPoly;
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon OutputDevice::PixelToLogic( const PolyPolygon& rDevicePolyPoly,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rDevicePolyPoly, PolyPolygon, NULL );
+
+ if ( rMapMode.IsDefault() )
+ return rDevicePolyPoly;
+
+ PolyPolygon aPolyPoly( rDevicePolyPoly );
+ USHORT nPoly = aPolyPoly.Count();
+ for( USHORT i = 0; i < nPoly; i++ )
+ {
+ Polygon& rPoly = aPolyPoly[i];
+ rPoly = PixelToLogic( rPoly, rMapMode );
+ }
+ return aPolyPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolygon& rPixelPoly,
+ const MapMode& rMapMode ) const
+{
+ basegfx::B2DPolygon aTransformedPoly = rPixelPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetInverseViewTransformation( rMapMode );
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolyPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolyPolygon& rPixelPolyPoly,
+ const MapMode& rMapMode ) const
+{
+ basegfx::B2DPolyPolygon aTransformedPoly = rPixelPolyPoly;
+ const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetInverseViewTransformation( rMapMode );
+ aTransformedPoly.transform( rTransformationMatrix );
+ return aTransformedPoly;
+}
+
+// -----------------------------------------------------------------------
+
+Region OutputDevice::PixelToLogic( const Region& rDeviceRegion,
+ const MapMode& rMapMode ) const
+{
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DBG_CHKOBJ( &rDeviceRegion, Region, ImplDbgTestRegion );
+
+ RegionType eType = rDeviceRegion.GetType();
+
+ if ( rMapMode.IsDefault() || (eType == REGION_EMPTY) || (eType == REGION_NULL) )
+ return rDeviceRegion;
+
+ Region aRegion;
+ PolyPolygon* pPolyPoly = rDeviceRegion.ImplGetImplRegion()->mpPolyPoly;
+
+ if ( pPolyPoly )
+ aRegion = Region( PixelToLogic( *pPolyPoly, rMapMode ) );
+ else
+ {
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+
+ aRegion.ImplBeginAddRect();
+ bRegionRect = rDeviceRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ while ( bRegionRect )
+ {
+ Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ aRegion.ImplAddRect( PixelToLogic( aRect, rMapMode ) );
+ bRegionRect = rDeviceRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ aRegion.ImplEndAddRect();
+ }
+
+ return aRegion;
+}
+
+// -----------------------------------------------------------------------
+
+#define ENTER0( rSource, pMapModeSource, pMapModeDest ) \
+ if ( !pMapModeSource ) \
+ pMapModeSource = &maMapMode; \
+ if ( !pMapModeDest ) \
+ pMapModeDest = &maMapMode; \
+ if ( *pMapModeSource == *pMapModeDest ) \
+ return rSource
+
+// -----------------------------------------------------------------------
+
+#define ENTER1( rSource, pMapModeSource, pMapModeDest ) \
+ ENTER0( rSource, pMapModeSource, pMapModeDest ); \
+ \
+ ImplMapRes aMapResSource; \
+ ImplMapRes aMapResDest; \
+ \
+ if ( !mbMap || pMapModeSource != &maMapMode ) \
+ { \
+ if ( pMapModeSource->GetMapUnit() == MAP_RELATIVE ) \
+ aMapResSource = maMapRes; \
+ ImplCalcMapResolution( *pMapModeSource, \
+ mnDPIX, mnDPIY, aMapResSource ); \
+ } \
+ else \
+ aMapResSource = maMapRes; \
+ if ( !mbMap || pMapModeDest != &maMapMode ) \
+ { \
+ if ( pMapModeDest->GetMapUnit() == MAP_RELATIVE ) \
+ aMapResDest = maMapRes; \
+ ImplCalcMapResolution( *pMapModeDest, \
+ mnDPIX, mnDPIY, aMapResDest ); \
+ } \
+ else \
+ aMapResDest = maMapRes
+
+// -----------------------------------------------------------------------
+
+#define ENTER2( eUnitSource, eUnitDest ) \
+ DBG_ASSERT( eUnitSource != MAP_SYSFONT \
+ && eUnitSource != MAP_APPFONT \
+ && eUnitSource != MAP_RELATIVE, \
+ "Source MapUnit nicht erlaubt" ); \
+ DBG_ASSERT( eUnitDest != MAP_SYSFONT \
+ && eUnitDest != MAP_APPFONT \
+ && eUnitDest != MAP_RELATIVE, \
+ "Destination MapUnit nicht erlaubt" ); \
+ DBG_ASSERTWARNING( eUnitSource != MAP_PIXEL, \
+ "MAP_PIXEL mit 72dpi angenaehert" ); \
+ DBG_ASSERTWARNING( eUnitDest != MAP_PIXEL, \
+ "MAP_PIXEL mit 72dpi angenaehert" )
+
+// -----------------------------------------------------------------------
+
+#define ENTER3( eUnitSource, eUnitDest ) \
+ long nNumerator = 1; \
+ long nDenominator = 1; \
+ DBG_ASSERT( eUnitSource < MAP_LASTENUMDUMMY, "Invalid source map unit"); \
+ DBG_ASSERT( eUnitDest < MAP_LASTENUMDUMMY, "Invalid destination map unit"); \
+ if( (eUnitSource < MAP_LASTENUMDUMMY) && (eUnitDest < MAP_LASTENUMDUMMY) ) \
+ { \
+ nNumerator = aImplNumeratorAry[eUnitSource] * \
+ aImplDenominatorAry[eUnitDest]; \
+ nDenominator = aImplNumeratorAry[eUnitDest] * \
+ aImplDenominatorAry[eUnitSource]; \
+ } \
+ if ( eUnitSource == MAP_PIXEL ) \
+ nDenominator *= 72; \
+ else if( eUnitDest == MAP_PIXEL ) \
+ nNumerator *= 72
+
+// -----------------------------------------------------------------------
+
+#define ENTER4( rMapModeSource, rMapModeDest ) \
+ ImplMapRes aMapResSource; \
+ ImplMapRes aMapResDest; \
+ \
+ ImplCalcMapResolution( rMapModeSource, 72, 72, aMapResSource ); \
+ ImplCalcMapResolution( rMapModeDest, 72, 72, aMapResDest )
+
+// -----------------------------------------------------------------------
+
+// return (n1 * n2 * n3) / (n4 * n5)
+static long fn5( const long n1,
+ const long n2,
+ const long n3,
+ const long n4,
+ const long n5 )
+{
+ if ( n1 == 0 || n2 == 0 || n3 == 0 || n4 == 0 || n5 == 0 )
+ return 0;
+ if ( LONG_MAX / Abs(n2) < Abs(n3) )
+ {
+ // a6 wird "ubersprungen
+ BigInt a7 = n2;
+ a7 *= n3;
+ a7 *= n1;
+
+ if ( LONG_MAX / Abs(n4) < Abs(n5) )
+ {
+ BigInt a8 = n4;
+ a8 *= n5;
+
+ BigInt a9 = a8;
+ a9 /= 2;
+ if ( a7.IsNeg() )
+ a7 -= a9;
+ else
+ a7 += a9;
+
+ a7 /= a8;
+ } // of if
+ else
+ {
+ long n8 = n4 * n5;
+
+ if ( a7.IsNeg() )
+ a7 -= n8 / 2;
+ else
+ a7 += n8 / 2;
+
+ a7 /= n8;
+ } // of else
+ return (long)a7;
+ } // of if
+ else
+ {
+ long n6 = n2 * n3;
+
+ if ( LONG_MAX / Abs(n1) < Abs(n6) )
+ {
+ BigInt a7 = n1;
+ a7 *= n6;
+
+ if ( LONG_MAX / Abs(n4) < Abs(n5) )
+ {
+ BigInt a8 = n4;
+ a8 *= n5;
+
+ BigInt a9 = a8;
+ a9 /= 2;
+ if ( a7.IsNeg() )
+ a7 -= a9;
+ else
+ a7 += a9;
+
+ a7 /= a8;
+ } // of if
+ else
+ {
+ long n8 = n4 * n5;
+
+ if ( a7.IsNeg() )
+ a7 -= n8 / 2;
+ else
+ a7 += n8 / 2;
+
+ a7 /= n8;
+ } // of else
+ return (long)a7;
+ } // of if
+ else
+ {
+ long n7 = n1 * n6;
+
+ if ( LONG_MAX / Abs(n4) < Abs(n5) )
+ {
+ BigInt a7 = n7;
+ BigInt a8 = n4;
+ a8 *= n5;
+
+ BigInt a9 = a8;
+ a9 /= 2;
+ if ( a7.IsNeg() )
+ a7 -= a9;
+ else
+ a7 += a9;
+
+ a7 /= a8;
+ return (long)a7;
+ } // of if
+ else
+ {
+ const long n8 = n4 * n5;
+ const long n8_2 = n8 / 2;
+
+ if( n7 < 0 )
+ {
+ if( ( n7 - LONG_MIN ) >= n8_2 )
+ n7 -= n8_2;
+ }
+ else if( ( LONG_MAX - n7 ) >= n8_2 )
+ n7 += n8_2;
+
+ return n7 / n8;
+ } // of else
+ } // of else
+ } // of else
+}
+
+// -----------------------------------------------------------------------
+
+// return (n1 * n2) / n3
+static long fn3( const long n1, const long n2, const long n3 )
+{
+ if ( n1 == 0 || n2 == 0 || n3 == 0 )
+ return 0;
+ if ( LONG_MAX / Abs(n1) < Abs(n2) )
+ {
+ BigInt a4 = n1;
+ a4 *= n2;
+
+ if ( a4.IsNeg() )
+ a4 -= n3 / 2;
+ else
+ a4 += n3 / 2;
+
+ a4 /= n3;
+ return (long)a4;
+ } // of if
+ else
+ {
+ long n4 = n1 * n2;
+ const long n3_2 = n3 / 2;
+
+ if( n4 < 0 )
+ {
+ if( ( n4 - LONG_MIN ) >= n3_2 )
+ n4 -= n3_2;
+ }
+ else if( ( LONG_MAX - n4 ) >= n3_2 )
+ n4 += n3_2;
+
+ return n4 / n3;
+ } // of else
+}
+
+// -----------------------------------------------------------------------
+
+Point OutputDevice::LogicToLogic( const Point& rPtSource,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const
+{
+ ENTER1( rPtSource, pMapModeSource, pMapModeDest );
+
+ return Point( fn5( rPtSource.X() + aMapResSource.mnMapOfsX,
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
+ aMapResDest.mnMapOfsX,
+ fn5( rPtSource.Y() + aMapResSource.mnMapOfsY,
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
+ aMapResDest.mnMapOfsY );
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::LogicToLogic( const Size& rSzSource,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const
+{
+ ENTER1( rSzSource, pMapModeSource, pMapModeDest );
+
+ return Size( fn5( rSzSource.Width(),
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ),
+ fn5( rSzSource.Height(),
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::LogicToLogic( const Rectangle& rRectSource,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const
+{
+ ENTER1( rRectSource, pMapModeSource, pMapModeDest );
+
+ return Rectangle( fn5( rRectSource.Left() + aMapResSource.mnMapOfsX,
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
+ aMapResDest.mnMapOfsX,
+ fn5( rRectSource.Top() + aMapResSource.mnMapOfsY,
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
+ aMapResDest.mnMapOfsY,
+ fn5( rRectSource.Right() + aMapResSource.mnMapOfsX,
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
+ aMapResDest.mnMapOfsX,
+ fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY,
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
+ aMapResDest.mnMapOfsY );
+}
+
+// -----------------------------------------------------------------------
+
+long* OutputDevice::LogicToLogic( long* pX, USHORT nCount,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const
+{
+ ENTER1( pX, pMapModeSource, pMapModeDest );
+
+ for( ; nCount; nCount--, pX++ )
+ {
+ *pX = fn5( *pX,
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX );
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Point OutputDevice::LogicToLogic( const Point& rPtSource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest )
+{
+ if ( rMapModeSource == rMapModeDest )
+ return rPtSource;
+
+ MapUnit eUnitSource = rMapModeSource.GetMapUnit();
+ MapUnit eUnitDest = rMapModeDest.GetMapUnit();
+ ENTER2( eUnitSource, eUnitDest );
+
+ if ( rMapModeSource.mpImplMapMode->mbSimple &&
+ rMapModeDest.mpImplMapMode->mbSimple )
+ {
+ ENTER3( eUnitSource, eUnitDest );
+
+ return Point( fn3( rPtSource.X(), nNumerator, nDenominator ),
+ fn3( rPtSource.Y(), nNumerator, nDenominator ) );
+ }
+ else
+ {
+ ENTER4( rMapModeSource, rMapModeDest );
+
+ return Point( fn5( rPtSource.X() + aMapResSource.mnMapOfsX,
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
+ aMapResDest.mnMapOfsX,
+ fn5( rPtSource.Y() + aMapResSource.mnMapOfsY,
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
+ aMapResDest.mnMapOfsY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::LogicToLogic( const Size& rSzSource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest )
+{
+ if ( rMapModeSource == rMapModeDest )
+ return rSzSource;
+
+ MapUnit eUnitSource = rMapModeSource.GetMapUnit();
+ MapUnit eUnitDest = rMapModeDest.GetMapUnit();
+ ENTER2( eUnitSource, eUnitDest );
+
+ if ( rMapModeSource.mpImplMapMode->mbSimple &&
+ rMapModeDest.mpImplMapMode->mbSimple )
+ {
+ ENTER3( eUnitSource, eUnitDest );
+
+ return Size( fn3( rSzSource.Width(), nNumerator, nDenominator ),
+ fn3( rSzSource.Height(), nNumerator, nDenominator ) );
+ }
+ else
+ {
+ ENTER4( rMapModeSource, rMapModeDest );
+
+ return Size( fn5( rSzSource.Width(),
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ),
+ fn5( rSzSource.Height(),
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolygon OutputDevice::LogicToLogic( const basegfx::B2DPolygon& rPolySource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest )
+{
+ if ( rMapModeSource == rMapModeDest )
+ return rPolySource;
+
+ MapUnit eUnitSource = rMapModeSource.GetMapUnit();
+ MapUnit eUnitDest = rMapModeDest.GetMapUnit();
+ ENTER2( eUnitSource, eUnitDest );
+
+ basegfx::B2DHomMatrix aTransform;
+
+ if ( rMapModeSource.mpImplMapMode->mbSimple &&
+ rMapModeDest.mpImplMapMode->mbSimple )
+ {
+ ENTER3( eUnitSource, eUnitDest );
+
+ const double fScaleFactor((double)nNumerator / (double)nDenominator);
+ aTransform.set(0, 0, fScaleFactor);
+ aTransform.set(1, 1, fScaleFactor);
+ }
+ else
+ {
+ ENTER4( rMapModeSource, rMapModeDest );
+
+ const double fScaleFactorX( (double(aMapResSource.mnMapScNumX) * double(aMapResDest.mnMapScDenomX))
+ / (double(aMapResSource.mnMapScDenomX) * double(aMapResDest.mnMapScNumX)) );
+ const double fScaleFactorY( (double(aMapResSource.mnMapScNumY) * double(aMapResDest.mnMapScDenomY))
+ / (double(aMapResSource.mnMapScDenomY) * double(aMapResDest.mnMapScNumY)) );
+ const double fZeroPointX(double(aMapResSource.mnMapOfsX) * fScaleFactorX - double(aMapResDest.mnMapOfsX));
+ const double fZeroPointY(double(aMapResSource.mnMapOfsY) * fScaleFactorY - double(aMapResDest.mnMapOfsY));
+
+ aTransform.set(0, 0, fScaleFactorX);
+ aTransform.set(1, 1, fScaleFactorY);
+ aTransform.set(0, 2, fZeroPointX);
+ aTransform.set(1, 2, fZeroPointY);
+ }
+ basegfx::B2DPolygon aPoly( rPolySource );
+ aPoly.transform( aTransform );
+ return aPoly;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolyPolygon OutputDevice::LogicToLogic( const basegfx::B2DPolyPolygon& rPolySource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest )
+{
+ if ( rMapModeSource == rMapModeDest )
+ return rPolySource;
+
+ MapUnit eUnitSource = rMapModeSource.GetMapUnit();
+ MapUnit eUnitDest = rMapModeDest.GetMapUnit();
+ ENTER2( eUnitSource, eUnitDest );
+
+ basegfx::B2DHomMatrix aTransform;
+
+ if ( rMapModeSource.mpImplMapMode->mbSimple &&
+ rMapModeDest.mpImplMapMode->mbSimple )
+ {
+ ENTER3( eUnitSource, eUnitDest );
+
+ const double fScaleFactor((double)nNumerator / (double)nDenominator);
+ aTransform.set(0, 0, fScaleFactor);
+ aTransform.set(1, 1, fScaleFactor);
+ }
+ else
+ {
+ ENTER4( rMapModeSource, rMapModeDest );
+
+ const double fScaleFactorX( (double(aMapResSource.mnMapScNumX) * double(aMapResDest.mnMapScDenomX))
+ / (double(aMapResSource.mnMapScDenomX) * double(aMapResDest.mnMapScNumX)) );
+ const double fScaleFactorY( (double(aMapResSource.mnMapScNumY) * double(aMapResDest.mnMapScDenomY))
+ / (double(aMapResSource.mnMapScDenomY) * double(aMapResDest.mnMapScNumY)) );
+ const double fZeroPointX(double(aMapResSource.mnMapOfsX) * fScaleFactorX - double(aMapResDest.mnMapOfsX));
+ const double fZeroPointY(double(aMapResSource.mnMapOfsY) * fScaleFactorY - double(aMapResDest.mnMapOfsY));
+
+ aTransform.set(0, 0, fScaleFactorX);
+ aTransform.set(1, 1, fScaleFactorY);
+ aTransform.set(0, 2, fZeroPointX);
+ aTransform.set(1, 2, fZeroPointY);
+ }
+ basegfx::B2DPolyPolygon aPoly( rPolySource );
+ aPoly.transform( aTransform );
+ return aPoly;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle OutputDevice::LogicToLogic( const Rectangle& rRectSource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest )
+{
+ if ( rMapModeSource == rMapModeDest )
+ return rRectSource;
+
+ MapUnit eUnitSource = rMapModeSource.GetMapUnit();
+ MapUnit eUnitDest = rMapModeDest.GetMapUnit();
+ ENTER2( eUnitSource, eUnitDest );
+
+ if ( rMapModeSource.mpImplMapMode->mbSimple &&
+ rMapModeDest.mpImplMapMode->mbSimple )
+ {
+ ENTER3( eUnitSource, eUnitDest );
+
+ return Rectangle( fn3( rRectSource.Left(), nNumerator, nDenominator ),
+ fn3( rRectSource.Top(), nNumerator, nDenominator ),
+ fn3( rRectSource.Right(), nNumerator, nDenominator ),
+ fn3( rRectSource.Bottom(), nNumerator, nDenominator ) );
+ }
+ else
+ {
+ ENTER4( rMapModeSource, rMapModeDest );
+
+ return Rectangle( fn5( rRectSource.Left() + aMapResSource.mnMapOfsX,
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
+ aMapResDest.mnMapOfsX,
+ fn5( rRectSource.Top() + aMapResSource.mnMapOfsY,
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
+ aMapResDest.mnMapOfsY,
+ fn5( rRectSource.Right() + aMapResSource.mnMapOfsX,
+ aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
+ aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
+ aMapResDest.mnMapOfsX,
+ fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY,
+ aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
+ aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
+ aMapResDest.mnMapOfsY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long OutputDevice::LogicToLogic( long nLongSource,
+ MapUnit eUnitSource, MapUnit eUnitDest )
+{
+ if ( eUnitSource == eUnitDest )
+ return nLongSource;
+
+ ENTER2( eUnitSource, eUnitDest );
+ ENTER3( eUnitSource, eUnitDest );
+
+ return fn3( nLongSource, nNumerator, nDenominator );
+}
+
+// -----------------------------------------------------------------------
+
+void OutputDevice::SetPixelOffset( const Size& rOffset )
+{
+ mnOutOffOrigX = rOffset.Width();
+ mnOutOffOrigY = rOffset.Height();
+
+ mnOutOffLogicX = ImplPixelToLogic( mnOutOffOrigX, mnDPIX,
+ maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX,
+ maThresRes.mnThresPixToLogX );
+ mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY,
+ maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY,
+ maThresRes.mnThresPixToLogY );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetPixelOffset( rOffset );
+}
+
+// -----------------------------------------------------------------------
+
+Size OutputDevice::GetPixelOffset() const
+{
+ return Size(mnOutOffOrigX, mnOutOffOrigY);
+}
+
+// -----------------------------------------------------------------------
+
+long Window::ImplLogicUnitToPixelX( long nX, MapUnit eUnit )
+{
+ if ( eUnit != MAP_PIXEL )
+ {
+ ImplFrameData* pFrameData = mpWindowImpl->mpFrameData;
+
+ // Map-Einheit verschieden, dann neu berechnen
+ if ( pFrameData->meMapUnit != eUnit )
+ {
+ pFrameData->meMapUnit = eUnit;
+ ImplCalcMapResolution( MapMode( eUnit ), mnDPIX, mnDPIY,
+ pFrameData->maMapUnitRes );
+ }
+
+ // Es wird kein BigInt gebraucht, da diese Funktion nur zur Umrechnung
+ // von Fensterposition benutzt wird
+ nX = nX * mnDPIX * pFrameData->maMapUnitRes.mnMapScNumX;
+ nX += nX >= 0 ? (pFrameData->maMapUnitRes.mnMapScDenomX/2) :
+ -((pFrameData->maMapUnitRes.mnMapScDenomX-1)/2);
+ nX /= pFrameData->maMapUnitRes.mnMapScDenomX;
+ }
+
+ return nX;
+}
+
+// -----------------------------------------------------------------------
+
+long Window::ImplLogicUnitToPixelY( long nY, MapUnit eUnit )
+{
+ if ( eUnit != MAP_PIXEL )
+ {
+ ImplFrameData* pFrameData = mpWindowImpl->mpFrameData;
+
+ // Map-Einheit verschieden, dann neu berechnen
+ if ( pFrameData->meMapUnit != eUnit )
+ {
+ pFrameData->meMapUnit = eUnit;
+ ImplCalcMapResolution( MapMode( eUnit ), mnDPIX, mnDPIY,
+ pFrameData->maMapUnitRes );
+ }
+
+ // Es wird kein BigInt gebraucht, da diese Funktion nur zur Umrechnung
+ // von Fensterposition benutzt wird
+ nY = nY * mnDPIY * pFrameData->maMapUnitRes.mnMapScNumY;
+ nY += nY >= 0 ? (pFrameData->maMapUnitRes.mnMapScDenomY/2) :
+ -((pFrameData->maMapUnitRes.mnMapScDenomY-1)/2);
+ nY /= pFrameData->maMapUnitRes.mnMapScDenomY;
+ }
+
+ return nY;
+}
diff --git a/vcl/source/gdi/pdfextoutdevdata.cxx b/vcl/source/gdi/pdfextoutdevdata.cxx
new file mode 100644
index 000000000000..046bc4a8951d
--- /dev/null
+++ b/vcl/source/gdi/pdfextoutdevdata.cxx
@@ -0,0 +1,798 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include "vcl/pdfextoutdevdata.hxx"
+#include "vcl/graph.hxx"
+#include "vcl/outdev.hxx"
+#include "vcl/gfxlink.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+
+
+#include <boost/shared_ptr.hpp>
+#include <set>
+
+namespace vcl
+{
+struct PDFExtOutDevDataSync
+{
+ enum Action{ CreateNamedDest,
+ CreateDest,
+ CreateLink,
+ SetLinkDest,
+ SetLinkURL,
+ CreateOutlineItem,
+ SetOutlineItemParent,
+ SetOutlineItemText,
+ SetOutlineItemDest,
+ CreateNote,
+ SetAutoAdvanceTime,
+ SetPageTransition,
+
+ BeginStructureElement,
+ EndStructureElement,
+ SetCurrentStructureElement,
+ SetStructureAttribute,
+ SetStructureAttributeNumerical,
+ SetStructureBoundingBox,
+ SetActualText,
+ SetAlternateText,
+ CreateControl,
+ BeginGroup,
+ EndGroup,
+ EndGroupGfxLink
+ };
+
+ sal_uInt32 nIdx;
+ Action eAct;
+};
+
+struct GlobalSyncData
+{
+ std::deque< PDFExtOutDevDataSync::Action > mActions;
+ std::deque< MapMode > mParaMapModes;
+ std::deque< Rectangle > mParaRects;
+ std::deque< sal_Int32 > mParaInts;
+ std::deque< sal_uInt32 > mParauInts;
+ std::deque< rtl::OUString > mParaOUStrings;
+ std::deque< PDFWriter::DestAreaType > mParaDestAreaTypes;
+ std::deque< PDFNote > mParaPDFNotes;
+ std::deque< PDFWriter::PageTransition > mParaPageTransitions;
+
+ sal_Int32 GetMappedId();
+ sal_Int32 GetMappedStructId( sal_Int32 );
+
+ sal_Int32 mCurId;
+ std::vector< sal_Int32 > mParaIds;
+ std::vector< sal_Int32 > mStructIdMap;
+
+ sal_Int32 mCurrentStructElement;
+ std::vector< sal_Int32 > mStructParents;
+ GlobalSyncData() :
+ mCurId ( 0 ),
+ mCurrentStructElement( 0 )
+ {
+ mStructParents.push_back( 0 );
+ mStructIdMap.push_back( 0 );
+ }
+ void PlayGlobalActions( PDFWriter& rWriter );
+};
+
+sal_Int32 GlobalSyncData::GetMappedId()
+{
+ sal_Int32 nLinkId = mParaInts.front();
+ mParaInts.pop_front();
+
+ /* negative values are intentionally passed as invalid IDs
+ * e.g. to create a new top level outline item
+ */
+ if( nLinkId >= 0 )
+ {
+ if ( (sal_uInt32)nLinkId < mParaIds.size() )
+ nLinkId = mParaIds[ nLinkId ];
+ else
+ nLinkId = -1;
+
+ DBG_ASSERT( nLinkId >= 0, "unmapped id in GlobalSyncData" );
+ }
+
+ return nLinkId;
+}
+
+sal_Int32 GlobalSyncData::GetMappedStructId( sal_Int32 nStructId )
+{
+ if ( (sal_uInt32)nStructId < mStructIdMap.size() )
+ nStructId = mStructIdMap[ nStructId ];
+ else
+ nStructId = -1;
+
+ DBG_ASSERT( nStructId >= 0, "unmapped structure id in GlobalSyncData" );
+
+ return nStructId;
+}
+
+void GlobalSyncData::PlayGlobalActions( PDFWriter& rWriter )
+{
+ std::deque< PDFExtOutDevDataSync::Action >::iterator aIter( mActions.begin() );
+ std::deque< PDFExtOutDevDataSync::Action >::iterator aEnd( mActions.end() );
+ while( aIter != aEnd )
+ {
+ switch( *aIter )
+ {
+ case PDFExtOutDevDataSync::CreateNamedDest : //i56629
+ {
+ rWriter.Push( PUSH_MAPMODE );
+ rWriter.SetMapMode( mParaMapModes.front() );
+ mParaMapModes.pop_front();
+ mParaIds.push_back( rWriter.CreateNamedDest( mParaOUStrings.front(), mParaRects.front(), mParaInts.front(), mParaDestAreaTypes.front() ) );
+ mParaOUStrings.pop_front();
+ mParaRects.pop_front();
+ mParaInts.pop_front();
+ mParaDestAreaTypes.pop_front();
+ rWriter.Pop();
+ }
+ break;
+ case PDFExtOutDevDataSync::CreateDest :
+ {
+ rWriter.Push( PUSH_MAPMODE );
+ rWriter.SetMapMode( mParaMapModes.front() );
+ mParaMapModes.pop_front();
+ mParaIds.push_back( rWriter.CreateDest( mParaRects.front(), mParaInts.front(), mParaDestAreaTypes.front() ) );
+ mParaRects.pop_front();
+ mParaInts.pop_front();
+ mParaDestAreaTypes.pop_front();
+ rWriter.Pop();
+ }
+ break;
+ case PDFExtOutDevDataSync::CreateLink :
+ {
+ rWriter.Push( PUSH_MAPMODE );
+ rWriter.SetMapMode( mParaMapModes.front() );
+ mParaMapModes.pop_front();
+ mParaIds.push_back( rWriter.CreateLink( mParaRects.front(), mParaInts.front() ) );
+ // resolve LinkAnnotation structural attribute
+ rWriter.SetLinkPropertyID( mParaIds.back(), sal_Int32(mParaIds.size()-1) );
+ mParaRects.pop_front();
+ mParaInts.pop_front();
+ rWriter.Pop();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetLinkDest :
+ {
+ sal_Int32 nLinkId = GetMappedId();
+ sal_Int32 nDestId = GetMappedId();
+ rWriter.SetLinkDest( nLinkId, nDestId );
+ }
+ break;
+ case PDFExtOutDevDataSync::SetLinkURL :
+ {
+ sal_Int32 nLinkId = GetMappedId();
+ rWriter.SetLinkURL( nLinkId, mParaOUStrings.front() );
+ mParaOUStrings.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::CreateOutlineItem :
+ {
+ sal_Int32 nParent = GetMappedId();
+ sal_Int32 nLinkId = GetMappedId();
+ mParaIds.push_back( rWriter.CreateOutlineItem( nParent, mParaOUStrings.front(), nLinkId ) );
+ mParaOUStrings.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetOutlineItemParent :
+ {
+ sal_Int32 nItem = GetMappedId();
+ sal_Int32 nNewParent = GetMappedId();
+ rWriter.SetOutlineItemParent( nItem, nNewParent );
+ }
+ break;
+ case PDFExtOutDevDataSync::SetOutlineItemText :
+ {
+ sal_Int32 nItem = GetMappedId();
+ rWriter.SetOutlineItemText( nItem, mParaOUStrings.front() );
+ mParaOUStrings.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetOutlineItemDest :
+ {
+ sal_Int32 nItem = GetMappedId();
+ sal_Int32 nDestId = GetMappedId();
+ rWriter.SetOutlineItemDest( nItem, nDestId );
+ }
+ break;
+ case PDFExtOutDevDataSync::CreateNote :
+ {
+ rWriter.Push( PUSH_MAPMODE );
+ rWriter.SetMapMode( mParaMapModes.front() );
+ rWriter.CreateNote( mParaRects.front(), mParaPDFNotes.front(), mParaInts.front() );
+ mParaMapModes.pop_front();
+ mParaRects.pop_front();
+ mParaPDFNotes.pop_front();
+ mParaInts.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetAutoAdvanceTime :
+ {
+ rWriter.SetAutoAdvanceTime( mParauInts.front(), mParaInts.front() );
+ mParauInts.pop_front();
+ mParaInts.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetPageTransition :
+ {
+ rWriter.SetPageTransition( mParaPageTransitions.front(), mParauInts.front(), mParaInts.front() );
+ mParaPageTransitions.pop_front();
+ mParauInts.pop_front();
+ mParaInts.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::BeginStructureElement:
+ case PDFExtOutDevDataSync::EndStructureElement:
+ case PDFExtOutDevDataSync::SetCurrentStructureElement:
+ case PDFExtOutDevDataSync::SetStructureAttribute:
+ case PDFExtOutDevDataSync::SetStructureAttributeNumerical:
+ case PDFExtOutDevDataSync::SetStructureBoundingBox:
+ case PDFExtOutDevDataSync::SetActualText:
+ case PDFExtOutDevDataSync::SetAlternateText:
+ case PDFExtOutDevDataSync::CreateControl:
+ case PDFExtOutDevDataSync::BeginGroup:
+ case PDFExtOutDevDataSync::EndGroup:
+ case PDFExtOutDevDataSync::EndGroupGfxLink:
+ break;
+ }
+ aIter++;
+ }
+}
+
+struct PageSyncData
+{
+ std::deque< PDFExtOutDevDataSync > mActions;
+ std::deque< Rectangle > mParaRects;
+ std::deque< sal_Int32 > mParaInts;
+ std::deque< rtl::OUString > mParaOUStrings;
+ std::deque< PDFWriter::StructElement > mParaStructElements;
+ std::deque< PDFWriter::StructAttribute > mParaStructAttributes;
+ std::deque< PDFWriter::StructAttributeValue > mParaStructAttributeValues;
+ std::deque< Graphic > mGraphics;
+ std::deque< ::boost::shared_ptr< PDFWriter::AnyWidget > >
+ mControls;
+ GlobalSyncData* mpGlobalData;
+
+ sal_Bool mbGroupIgnoreGDIMtfActions;
+
+ PageSyncData( GlobalSyncData* pGlobal ) : mbGroupIgnoreGDIMtfActions ( sal_False ) { mpGlobalData = pGlobal; }
+
+ void PushAction( const OutputDevice& rOutDev, const PDFExtOutDevDataSync::Action eAct );
+ sal_Bool PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rCurGDIMtfAction, const PDFExtOutDevData& rOutDevData );
+};
+void PageSyncData::PushAction( const OutputDevice& rOutDev, const PDFExtOutDevDataSync::Action eAct )
+{
+ GDIMetaFile* pMtf = rOutDev.GetConnectMetaFile();
+ DBG_ASSERT( pMtf, "PageSyncData::PushAction -> no ConnectMetaFile !!!" );
+
+ PDFExtOutDevDataSync aSync;
+ aSync.eAct = eAct;
+ if ( pMtf )
+ aSync.nIdx = pMtf->GetActionCount();
+ else
+ aSync.nIdx = 0x7fffffff; // sync not possible
+ mActions.push_back( aSync );
+}
+sal_Bool PageSyncData::PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rCurGDIMtfAction, const PDFExtOutDevData& rOutDevData )
+{
+ sal_Bool bRet = sal_False;
+ if ( mActions.size() && ( mActions.front().nIdx == rCurGDIMtfAction ) )
+ {
+ bRet = sal_True;
+ PDFExtOutDevDataSync aDataSync = mActions.front();
+ mActions.pop_front();
+ switch( aDataSync.eAct )
+ {
+ case PDFExtOutDevDataSync::BeginStructureElement :
+ {
+ sal_Int32 nNewEl = rWriter.BeginStructureElement( mParaStructElements.front(), mParaOUStrings.front() ) ;
+ mParaStructElements.pop_front();
+ mParaOUStrings.pop_front();
+ mpGlobalData->mStructIdMap.push_back( nNewEl );
+ }
+ break;
+ case PDFExtOutDevDataSync::EndStructureElement :
+ {
+ rWriter.EndStructureElement();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetCurrentStructureElement:
+ {
+ rWriter.SetCurrentStructureElement( mpGlobalData->GetMappedStructId( mParaInts.front() ) );
+ mParaInts.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetStructureAttribute :
+ {
+ rWriter.SetStructureAttribute( mParaStructAttributes.front(), mParaStructAttributeValues.front() );
+ mParaStructAttributeValues.pop_front();
+ mParaStructAttributes.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetStructureAttributeNumerical :
+ {
+ rWriter.SetStructureAttributeNumerical( mParaStructAttributes.front(), mParaInts.front() );
+ mParaStructAttributes.pop_front();
+ mParaInts.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetStructureBoundingBox :
+ {
+ rWriter.SetStructureBoundingBox( mParaRects.front() );
+ mParaRects.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetActualText :
+ {
+ rWriter.SetActualText( mParaOUStrings.front() );
+ mParaOUStrings.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::SetAlternateText :
+ {
+ rWriter.SetAlternateText( mParaOUStrings.front() );
+ mParaOUStrings.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::CreateControl:
+ {
+ ::boost::shared_ptr< PDFWriter::AnyWidget > pControl( mControls.front() );
+ DBG_ASSERT( pControl.get(), "PageSyncData::PlaySyncPageAct: invalid widget!" );
+ if ( pControl.get() )
+ rWriter.CreateControl( *pControl );
+ mControls.pop_front();
+ }
+ break;
+ case PDFExtOutDevDataSync::BeginGroup :
+ {
+ /* first determining if this BeginGroup is starting a GfxLink,
+ by searching for a EndGroup or a EndGroupGfxLink */
+ mbGroupIgnoreGDIMtfActions = sal_False;
+ std::deque< PDFExtOutDevDataSync >::iterator aBeg = mActions.begin();
+ std::deque< PDFExtOutDevDataSync >::iterator aEnd = mActions.end();
+ while ( aBeg != aEnd )
+ {
+ if ( aBeg->eAct == PDFExtOutDevDataSync::EndGroup )
+ {
+ break;
+ }
+ else if ( aBeg->eAct == PDFExtOutDevDataSync::EndGroupGfxLink )
+ {
+ if ( rOutDevData.GetIsLosslessCompression() && !rOutDevData.GetIsReduceImageResolution() )
+ {
+ Graphic& rGraphic = mGraphics.front();
+ if ( rGraphic.IsLink() && rGraphic.GetLink().GetType() == GFX_LINK_TYPE_NATIVE_JPG )
+ {
+ mbGroupIgnoreGDIMtfActions = sal_True;
+ }
+ }
+ break;
+ }
+ aBeg++;
+ }
+ }
+ break;
+ case PDFExtOutDevDataSync::EndGroup :
+ {
+ mbGroupIgnoreGDIMtfActions = sal_False;
+ }
+ break;
+ case PDFExtOutDevDataSync::EndGroupGfxLink :
+ {
+ sal_Int32 nTransparency;
+ Rectangle aOutputRect, aVisibleOutputRect;
+ Graphic aGraphic( mGraphics.front() );
+
+ mGraphics.pop_front();
+ nTransparency = mParaInts.front();
+ mParaInts.pop_front();
+ aOutputRect = mParaRects.front();
+ mParaRects.pop_front();
+ aVisibleOutputRect = mParaRects.front();
+ mParaRects.pop_front();
+
+ if ( mbGroupIgnoreGDIMtfActions )
+ {
+ sal_Bool bClippingNeeded = ( aOutputRect != aVisibleOutputRect ) && !aVisibleOutputRect.IsEmpty();
+
+ GfxLink aGfxLink( aGraphic.GetLink() );
+ if ( aGfxLink.GetType() == GFX_LINK_TYPE_NATIVE_JPG )
+ {
+ if ( bClippingNeeded )
+ {
+ rWriter.Push();
+ basegfx::B2DPolyPolygon aRect( basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRectangle( aVisibleOutputRect.Left(), aVisibleOutputRect.Top(),
+ aVisibleOutputRect.Right(), aVisibleOutputRect.Bottom() ) ) );
+ rWriter.SetClipRegion( aRect);
+ }
+ Bitmap aMask;
+ SvMemoryStream aTmp;
+ const sal_uInt8* pData = aGfxLink.GetData();
+ sal_uInt32 nBytes = aGfxLink.GetDataSize();
+ if( pData && nBytes )
+ {
+ aTmp.Write( pData, nBytes );
+ rWriter.DrawJPGBitmap( aTmp, aGraphic.GetBitmap().GetBitCount() > 8, aGraphic.GetSizePixel(), aOutputRect, aMask );
+ }
+
+ if ( bClippingNeeded )
+ rWriter.Pop();
+ }
+ mbGroupIgnoreGDIMtfActions = sal_False;
+ }
+ }
+ break;
+ case PDFExtOutDevDataSync::CreateNamedDest:
+ case PDFExtOutDevDataSync::CreateDest:
+ case PDFExtOutDevDataSync::CreateLink:
+ case PDFExtOutDevDataSync::SetLinkDest:
+ case PDFExtOutDevDataSync::SetLinkURL:
+ case PDFExtOutDevDataSync::CreateOutlineItem:
+ case PDFExtOutDevDataSync::SetOutlineItemParent:
+ case PDFExtOutDevDataSync::SetOutlineItemText:
+ case PDFExtOutDevDataSync::SetOutlineItemDest:
+ case PDFExtOutDevDataSync::CreateNote:
+ case PDFExtOutDevDataSync::SetAutoAdvanceTime:
+ case PDFExtOutDevDataSync::SetPageTransition:
+ break;
+ }
+ }
+ else if ( mbGroupIgnoreGDIMtfActions )
+ {
+ rCurGDIMtfAction++;
+ bRet = sal_True;
+ }
+ return bRet;
+}
+
+TYPEINIT1(PDFExtOutDevData,ExtOutDevData);
+PDFExtOutDevData::PDFExtOutDevData( const OutputDevice& rOutDev ) :
+ mrOutDev ( rOutDev ),
+ mbTaggedPDF ( sal_False ),
+ mbExportNotes ( sal_True ),
+ mbTransitionEffects ( sal_True ),
+ mbUseLosslessCompression( sal_True ),
+ mbReduceImageResolution ( sal_False ),
+ mbExportNDests ( sal_False ),
+ mnFormsFormat ( 0 ),
+ mnPage ( -1 ),
+ mpPageSyncData ( NULL ),
+ mpGlobalSyncData ( new GlobalSyncData() )
+{
+ mpPageSyncData = new PageSyncData( mpGlobalSyncData );
+}
+
+PDFExtOutDevData::~PDFExtOutDevData()
+{
+ delete mpPageSyncData;
+ delete mpGlobalSyncData;
+}
+
+const com::sun::star::lang::Locale& PDFExtOutDevData::GetDocumentLocale() const
+{
+ return maDocLocale;
+}
+void PDFExtOutDevData::SetDocumentLocale( const com::sun::star::lang::Locale& rLoc )
+{
+ maDocLocale = rLoc;
+}
+sal_Int32 PDFExtOutDevData::GetCurrentPageNumber() const
+{
+ return mnPage;
+}
+void PDFExtOutDevData::SetCurrentPageNumber( const sal_Int32 nPage )
+{
+ mnPage = nPage;
+}
+sal_Bool PDFExtOutDevData::GetIsLosslessCompression() const
+{
+ return mbUseLosslessCompression;
+}
+void PDFExtOutDevData::SetIsLosslessCompression( const sal_Bool bUseLosslessCompression )
+{
+ mbUseLosslessCompression = bUseLosslessCompression;
+}
+sal_Bool PDFExtOutDevData::GetIsReduceImageResolution() const
+{
+ return mbReduceImageResolution;
+}
+void PDFExtOutDevData::SetIsReduceImageResolution( const sal_Bool bReduceImageResolution )
+{
+ mbReduceImageResolution = bReduceImageResolution;
+}
+sal_Bool PDFExtOutDevData::GetIsExportNotes() const
+{
+ return mbExportNotes;
+}
+void PDFExtOutDevData::SetIsExportNotes( const sal_Bool bExportNotes )
+{
+ mbExportNotes = bExportNotes;
+}
+sal_Bool PDFExtOutDevData::GetIsExportTaggedPDF() const
+{
+ return mbTaggedPDF;
+}
+void PDFExtOutDevData::SetIsExportTaggedPDF( const sal_Bool bTaggedPDF )
+{
+ mbTaggedPDF = bTaggedPDF;
+}
+sal_Bool PDFExtOutDevData::GetIsExportTransitionEffects() const
+{
+ return mbTransitionEffects;
+}
+void PDFExtOutDevData::SetIsExportTransitionEffects( const sal_Bool bTransitionEffects )
+{
+ mbTransitionEffects = bTransitionEffects;
+}
+sal_Bool PDFExtOutDevData::GetIsExportFormFields() const
+{
+ return mbExportFormFields;
+}
+void PDFExtOutDevData::SetIsExportFormFields( const sal_Bool bExportFomtFields )
+{
+ mbExportFormFields = bExportFomtFields;
+}
+sal_Int32 PDFExtOutDevData::GetFormsFormat() const
+{
+ return mnFormsFormat;
+}
+void PDFExtOutDevData::SetFormsFormat( const sal_Int32 nFormsFormat )
+{
+ mnFormsFormat = nFormsFormat;
+}
+sal_Bool PDFExtOutDevData::GetIsExportBookmarks() const
+{
+ return mbExportBookmarks;
+}
+void PDFExtOutDevData::SetIsExportBookmarks( const sal_Bool bExportBookmarks )
+{
+ mbExportBookmarks = bExportBookmarks;
+}
+std::vector< PDFExtOutDevBookmarkEntry >& PDFExtOutDevData::GetBookmarks()
+{
+ return maBookmarks;
+}
+sal_Bool PDFExtOutDevData::GetIsExportNamedDestinations() const
+{
+ return mbExportNDests;
+}
+void PDFExtOutDevData::SetIsExportNamedDestinations( const sal_Bool bExportNDests )
+{
+ mbExportNDests = bExportNDests;
+}
+void PDFExtOutDevData::ResetSyncData()
+{
+ *mpPageSyncData = PageSyncData( mpGlobalSyncData );
+}
+sal_Bool PDFExtOutDevData::PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rIdx )
+{
+ return mpPageSyncData->PlaySyncPageAct( rWriter, rIdx, *this );
+}
+void PDFExtOutDevData::PlayGlobalActions( PDFWriter& rWriter )
+{
+ mpGlobalSyncData->PlayGlobalActions( rWriter );
+}
+
+/* global actions, syncronisation to the recorded metafile isn't needed,
+ all actions will be played after the last page was recorded
+*/
+//--->i56629
+sal_Int32 PDFExtOutDevData::CreateNamedDest(const String& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateNamedDest );
+ mpGlobalSyncData->mParaOUStrings.push_back( sDestName );
+ mpGlobalSyncData->mParaRects.push_back( rRect );
+ mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
+ mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
+ mpGlobalSyncData->mParaDestAreaTypes.push_back( eType );
+ return mpGlobalSyncData->mCurId++;
+}
+//<---i56629
+sal_Int32 PDFExtOutDevData::CreateDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateDest );
+ mpGlobalSyncData->mParaRects.push_back( rRect );
+ mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
+ mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
+ mpGlobalSyncData->mParaDestAreaTypes.push_back( eType );
+ return mpGlobalSyncData->mCurId++;
+}
+sal_Int32 PDFExtOutDevData::CreateLink( const Rectangle& rRect, sal_Int32 nPageNr )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateLink );
+ mpGlobalSyncData->mParaRects.push_back( rRect );
+ mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
+ mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
+ return mpGlobalSyncData->mCurId++;
+}
+sal_Int32 PDFExtOutDevData::SetLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetLinkDest );
+ mpGlobalSyncData->mParaInts.push_back( nLinkId );
+ mpGlobalSyncData->mParaInts.push_back( nDestId );
+ return 0;
+}
+sal_Int32 PDFExtOutDevData::SetLinkURL( sal_Int32 nLinkId, const rtl::OUString& rURL )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetLinkURL );
+ mpGlobalSyncData->mParaInts.push_back( nLinkId );
+ mpGlobalSyncData->mParaOUStrings.push_back( rURL );
+ return 0;
+}
+sal_Int32 PDFExtOutDevData::CreateOutlineItem( sal_Int32 nParent, const rtl::OUString& rText, sal_Int32 nDestID )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateOutlineItem );
+ mpGlobalSyncData->mParaInts.push_back( nParent );
+ mpGlobalSyncData->mParaOUStrings.push_back( rText );
+ mpGlobalSyncData->mParaInts.push_back( nDestID );
+ return mpGlobalSyncData->mCurId++;
+}
+sal_Int32 PDFExtOutDevData::SetOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetOutlineItemParent );
+ mpGlobalSyncData->mParaInts.push_back( nItem );
+ mpGlobalSyncData->mParaInts.push_back( nNewParent );
+ return 0;
+}
+sal_Int32 PDFExtOutDevData::SetOutlineItemText( sal_Int32 nItem, const rtl::OUString& rText )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetOutlineItemText );
+ mpGlobalSyncData->mParaInts.push_back( nItem );
+ mpGlobalSyncData->mParaOUStrings.push_back( rText );
+ return 0;
+}
+sal_Int32 PDFExtOutDevData::SetOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetOutlineItemDest );
+ mpGlobalSyncData->mParaInts.push_back( nItem );
+ mpGlobalSyncData->mParaInts.push_back( nDestID );
+ return 0;
+}
+void PDFExtOutDevData::CreateNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateNote );
+ mpGlobalSyncData->mParaRects.push_back( rRect );
+ mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
+ mpGlobalSyncData->mParaPDFNotes.push_back( rNote );
+ mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
+}
+void PDFExtOutDevData::SetAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetAutoAdvanceTime );
+ mpGlobalSyncData->mParauInts.push_back( nSeconds );
+ mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
+}
+void PDFExtOutDevData::SetPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr )
+{
+ mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetPageTransition );
+ mpGlobalSyncData->mParaPageTransitions.push_back( eType );
+ mpGlobalSyncData->mParauInts.push_back( nMilliSec );
+ mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
+}
+
+/* local (page), actions have to be played synchroniously to the actions of
+ of the recorded metafile (created by each xRenderable->render()) */
+ sal_Int32 PDFExtOutDevData::BeginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::BeginStructureElement );
+ mpPageSyncData->mParaStructElements.push_back( eType );
+ mpPageSyncData->mParaOUStrings.push_back( rAlias );
+ // need a global id
+ sal_Int32 nNewId = mpGlobalSyncData->mStructParents.size();
+ mpGlobalSyncData->mStructParents.push_back( mpGlobalSyncData->mCurrentStructElement );
+ mpGlobalSyncData->mCurrentStructElement = nNewId;
+ return nNewId;
+}
+void PDFExtOutDevData::EndStructureElement()
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::EndStructureElement );
+ mpGlobalSyncData->mCurrentStructElement = mpGlobalSyncData->mStructParents[ mpGlobalSyncData->mCurrentStructElement ];
+}
+bool PDFExtOutDevData::SetCurrentStructureElement( sal_Int32 nStructId )
+{
+ bool bSuccess = false;
+ if( sal_uInt32(nStructId) < mpGlobalSyncData->mStructParents.size() )
+ {
+ mpGlobalSyncData->mCurrentStructElement = nStructId;
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetCurrentStructureElement );
+ mpPageSyncData->mParaInts.push_back( nStructId );
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+sal_Int32 PDFExtOutDevData::GetCurrentStructureElement()
+{
+ return mpGlobalSyncData->mCurrentStructElement;
+}
+bool PDFExtOutDevData::SetStructureAttribute( PDFWriter::StructAttribute eAttr, PDFWriter::StructAttributeValue eVal )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetStructureAttribute );
+ mpPageSyncData->mParaStructAttributes.push_back( eAttr );
+ mpPageSyncData->mParaStructAttributeValues.push_back( eVal );
+ return true;
+}
+bool PDFExtOutDevData::SetStructureAttributeNumerical( PDFWriter::StructAttribute eAttr, sal_Int32 nValue )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetStructureAttributeNumerical );
+ mpPageSyncData->mParaStructAttributes.push_back( eAttr );
+ mpPageSyncData->mParaInts.push_back( nValue );
+ return true;
+}
+void PDFExtOutDevData::SetStructureBoundingBox( const Rectangle& rRect )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetStructureBoundingBox );
+ mpPageSyncData->mParaRects.push_back( rRect );
+}
+void PDFExtOutDevData::SetActualText( const String& rText )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetActualText );
+ mpPageSyncData->mParaOUStrings.push_back( rText );
+}
+void PDFExtOutDevData::SetAlternateText( const String& rText )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetAlternateText );
+ mpPageSyncData->mParaOUStrings.push_back( rText );
+}
+
+void PDFExtOutDevData::CreateControl( const PDFWriter::AnyWidget& rControlType, sal_Int32 /*nPageNr*/ )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::CreateControl );
+
+ ::boost::shared_ptr< PDFWriter::AnyWidget > pClone( rControlType.Clone() );
+ mpPageSyncData->mControls.push_back( pClone );
+}
+
+void PDFExtOutDevData::BeginGroup()
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::BeginGroup );
+}
+
+void PDFExtOutDevData::EndGroup()
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::EndGroup );
+}
+void PDFExtOutDevData::EndGroup( const Graphic& rGraphic,
+ BYTE nTransparency,
+ const Rectangle& rOutputRect,
+ const Rectangle& rVisibleOutputRect )
+{
+ mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::EndGroupGfxLink );
+ mpPageSyncData->mGraphics.push_back( rGraphic );
+ mpPageSyncData->mParaInts.push_back( nTransparency );
+ mpPageSyncData->mParaRects.push_back( rOutputRect );
+ mpPageSyncData->mParaRects.push_back( rVisibleOutputRect );
+}
+
+}
diff --git a/vcl/source/gdi/pdffontcache.cxx b/vcl/source/gdi/pdffontcache.cxx
new file mode 100644
index 000000000000..507ede81ef24
--- /dev/null
+++ b/vcl/source/gdi/pdffontcache.cxx
@@ -0,0 +1,85 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_vcl.hxx"
+
+#include "pdffontcache.hxx"
+#include <vcl/salgdi.hxx>
+#include <vcl/outfont.hxx>
+#include <vcl/sallayout.hxx>
+
+using namespace vcl;
+
+PDFFontCache::FontIdentifier::FontIdentifier( const ImplFontData* pFont, bool bVertical ) :
+ m_nFontId( pFont->GetFontId() ),
+ m_nMagic( pFont->GetFontMagic() ),
+ m_bVertical( bVertical )
+{
+}
+
+PDFFontCache::FontData& PDFFontCache::getFont( const ImplFontData* pFont, bool bVertical )
+{
+ FontIdentifier aId( pFont, bVertical );
+ FontToIndexMap::iterator it = m_aFontToIndex.find( aId );
+ if( it != m_aFontToIndex.end() )
+ return m_aFonts[ it->second ];
+ m_aFontToIndex[ aId ] = sal_uInt32(m_aFonts.size());
+ m_aFonts.push_back( FontData() );
+ return m_aFonts.back();
+}
+
+sal_Int32 PDFFontCache::getGlyphWidth( const ImplFontData* pFont, sal_GlyphId nGlyph, bool bVertical, SalGraphics* pGraphics )
+{
+ sal_Int32 nWidth = 0;
+ FontData& rFontData( getFont( pFont, bVertical ) );
+ if( rFontData.m_nWidths.empty() )
+ {
+ pGraphics->GetGlyphWidths( pFont, bVertical, rFontData.m_nWidths, rFontData.m_aGlyphIdToIndex );
+ }
+ if( ! rFontData.m_nWidths.empty() )
+ {
+ sal_GlyphId nIndex = nGlyph;
+ if( (nGlyph & GF_ISCHAR) != 0 )
+ {
+ const sal_Ucs cCode = static_cast<sal_Ucs>(nGlyph & GF_IDXMASK);
+ Ucs2UIntMap::const_iterator it = rFontData.m_aGlyphIdToIndex.find( cCode );
+
+ // allow symbol aliasing U+00xx -> U+F0xx if there is no direct match
+ if( it == rFontData.m_aGlyphIdToIndex.end()
+ && pFont->IsSymbolFont()
+ && (cCode < 0x0100) )
+ it = rFontData.m_aGlyphIdToIndex.find( cCode+0xF000 );
+
+ nIndex = (it != rFontData.m_aGlyphIdToIndex.end()) ? it->second : 0;
+ }
+ nIndex &= GF_IDXMASK;
+ if( nIndex < rFontData.m_nWidths.size() )
+ nWidth = rFontData.m_nWidths[ nIndex ];
+ }
+ return nWidth;
+}
+
diff --git a/vcl/source/gdi/pdffontcache.hxx b/vcl/source/gdi/pdffontcache.hxx
new file mode 100644
index 000000000000..06ffff86b070
--- /dev/null
+++ b/vcl/source/gdi/pdffontcache.hxx
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef VCL_PDFFONTCACHE_HXX
+#define VCL_PDFFONTCACHE_HXX
+
+#include <sal/types.h>
+
+#include <vcl/sallayout.hxx>
+#include <vcl/salgdi.hxx>
+
+namespace vcl
+{
+ class PDFFontCache
+ {
+ struct FontIdentifier
+ {
+ sal_IntPtr m_nFontId;
+ int m_nMagic;
+ bool m_bVertical;
+
+ FontIdentifier( const ImplFontData*, bool bVertical );
+ FontIdentifier() : m_nFontId(0), m_nMagic(0), m_bVertical( false ) {}
+
+ bool operator==( const FontIdentifier& rRight ) const
+ {
+ return m_nFontId == rRight.m_nFontId &&
+ m_nMagic == rRight.m_nMagic &&
+ m_bVertical == rRight.m_bVertical;
+ }
+ bool operator<( const FontIdentifier& rRight ) const
+ {
+ return m_nFontId < rRight.m_nFontId ||
+ m_nMagic < rRight.m_nMagic ||
+ m_bVertical < rRight.m_bVertical;
+ }
+ };
+ struct FontData
+ {
+ Int32Vector m_nWidths;
+ Ucs2UIntMap m_aGlyphIdToIndex;
+ };
+ typedef std::map< FontIdentifier, sal_uInt32 > FontToIndexMap;
+
+ std::vector< FontData > m_aFonts;
+ FontToIndexMap m_aFontToIndex;
+
+ FontData& getFont( const ImplFontData*, bool bVertical );
+ public:
+ PDFFontCache() {}
+ ~PDFFontCache() {}
+
+ sal_Int32 getGlyphWidth( const ImplFontData*, sal_GlyphId, bool bVertical, SalGraphics* );
+ };
+}
+
+#endif
diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx
new file mode 100644
index 000000000000..5dcce25a0315
--- /dev/null
+++ b/vcl/source/gdi/pdfwriter.cxx
@@ -0,0 +1,571 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <pdfwriter_impl.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/image.hxx>
+
+using namespace vcl;
+
+PDFWriter::AnyWidget::~AnyWidget()
+{
+}
+
+PDFWriter::PDFWriter( const PDFWriter::PDFWriterContext& rContext )
+ :
+ pImplementation( new PDFWriterImpl( rContext ) )
+{
+}
+
+PDFWriter::~PDFWriter()
+{
+ delete (PDFWriterImpl*)pImplementation;
+}
+
+OutputDevice* PDFWriter::GetReferenceDevice()
+{
+ return ((PDFWriterImpl*)pImplementation)->getReferenceDevice();
+}
+
+sal_Int32 PDFWriter::NewPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, Orientation eOrientation )
+{
+ return ((PDFWriterImpl*)pImplementation)->newPage( nPageWidth, nPageHeight, eOrientation );
+}
+
+bool PDFWriter::Emit()
+{
+ return ((PDFWriterImpl*)pImplementation)->emit();
+}
+
+PDFWriter::PDFVersion PDFWriter::GetVersion() const
+{
+ return ((PDFWriterImpl*)pImplementation)->getVersion();
+}
+
+void PDFWriter::SetDocInfo( const PDFDocInfo& rInfo )
+{
+ ((PDFWriterImpl*)pImplementation)->setDocInfo( rInfo );
+}
+
+const PDFDocInfo& PDFWriter::GetDocInfo() const
+{
+ return ((PDFWriterImpl*)pImplementation)->getDocInfo();
+}
+
+void PDFWriter::SetDocumentLocale( const com::sun::star::lang::Locale& rLoc )
+{
+ ((PDFWriterImpl*)pImplementation)->setDocumentLocale( rLoc );
+}
+
+void PDFWriter::SetFont( const Font& rFont )
+{
+ ((PDFWriterImpl*)pImplementation)->setFont( rFont );
+}
+
+void PDFWriter::DrawText( const Point& rPos, const String& rText )
+{
+ ((PDFWriterImpl*)pImplementation)->drawText( rPos, rText );
+}
+
+void PDFWriter::DrawTextLine(
+ const Point& rPos,
+ long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ FontUnderline eOverline,
+ BOOL bUnderlineAbove )
+{
+ ((PDFWriterImpl*)pImplementation)->drawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+}
+
+void PDFWriter::DrawTextArray(
+ const Point& rStartPt,
+ const XubString& rStr,
+ const sal_Int32* pDXAry,
+ xub_StrLen nIndex,
+ xub_StrLen nLen )
+{
+ ((PDFWriterImpl*)pImplementation)->drawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
+}
+
+void PDFWriter::DrawStretchText(
+ const Point& rStartPt,
+ ULONG nWidth,
+ const XubString& rStr,
+ xub_StrLen nIndex,
+ xub_StrLen nLen )
+{
+ ((PDFWriterImpl*)pImplementation)->drawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
+}
+
+void PDFWriter::DrawText(
+ const Rectangle& rRect,
+ const XubString& rStr,
+ USHORT nStyle )
+{
+ ((PDFWriterImpl*)pImplementation)->drawText( rRect, rStr, nStyle );
+}
+
+void PDFWriter::DrawLine( const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawLine( rStart, rStop );
+}
+
+void PDFWriter::DrawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
+{
+ ((PDFWriterImpl*)pImplementation)->drawLine( rStart, rStop, rInfo );
+}
+
+void PDFWriter::DrawPolygon( const Polygon& rPoly )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolygon( rPoly );
+}
+
+void PDFWriter::DrawPolyLine( const Polygon& rPoly )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyLine( rPoly );
+}
+
+void PDFWriter::DrawRect( const Rectangle& rRect )
+{
+ ((PDFWriterImpl*)pImplementation)->drawRectangle( rRect );
+}
+
+void PDFWriter::DrawRect( const Rectangle& rRect, ULONG nHorzRound, ULONG nVertRound )
+{
+ ((PDFWriterImpl*)pImplementation)->drawRectangle( rRect, nHorzRound, nVertRound );
+}
+
+void PDFWriter::DrawEllipse( const Rectangle& rRect )
+{
+ ((PDFWriterImpl*)pImplementation)->drawEllipse( rRect );
+}
+
+void PDFWriter::DrawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawArc( rRect, rStart, rStop, false, false );
+}
+
+void PDFWriter::DrawPie( const Rectangle& rRect, const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawArc( rRect, rStart, rStop, true, false );
+}
+
+void PDFWriter::DrawChord( const Rectangle& rRect, const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawArc( rRect, rStart, rStop, false, true );
+}
+
+void PDFWriter::DrawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyLine( rPoly, rInfo );
+}
+
+void PDFWriter::DrawPolyLine( const Polygon& rPoly, const ExtLineInfo& rInfo )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyLine( rPoly, rInfo );
+}
+
+void PDFWriter::DrawPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyPolygon( rPolyPoly );
+}
+
+void PDFWriter::DrawPixel( const Point& rPos, const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPixel( rPos, rColor );
+}
+
+void PDFWriter::DrawPixel( const Polygon& rPts, const Color* pColors )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPixel( rPts, pColors );
+}
+
+void PDFWriter::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
+{
+ Size aSize = OutputDevice::LogicToLogic( rBitmap.GetPrefSize(),
+ rBitmap.GetPrefMapMode(),
+ ((PDFWriterImpl*)pImplementation)->getMapMode() );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, aSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
+{
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, const Bitmap& rBitmap )
+{
+ Bitmap aBitmap( rBitmap );
+ aBitmap.Crop( Rectangle( rSrcPtPixel, rSrcSizePixel ) );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, aBitmap );
+}
+
+void PDFWriter::DrawBitmapEx( const Point& rDestPt, const BitmapEx& rBitmap )
+{
+ Size aSize = OutputDevice::LogicToLogic( rBitmap.GetPrefSize(),
+ rBitmap.GetPrefMapMode(),
+ ((PDFWriterImpl*)pImplementation)->getMapMode() );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, aSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, const BitmapEx& rBitmap )
+{
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, const BitmapEx& rBitmap )
+{
+ if ( !!rBitmap )
+ {
+ BitmapEx aBitmap( rBitmap );
+ aBitmap.Crop( Rectangle( rSrcPtPixel, rSrcSizePixel ) );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, aBitmap );
+ }
+}
+
+void PDFWriter::DrawMask( const Point& rDestPt, const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ Size aSize = OutputDevice::LogicToLogic( rBitmap.GetPrefSize(),
+ rBitmap.GetPrefMapMode(),
+ ((PDFWriterImpl*)pImplementation)->getMapMode() );
+ ((PDFWriterImpl*)pImplementation)->drawMask( rDestPt, aSize, rBitmap, rMaskColor );
+}
+
+void PDFWriter::DrawMask( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ ((PDFWriterImpl*)pImplementation)->drawMask( rDestPt, rDestSize, rBitmap, rMaskColor );
+}
+
+void PDFWriter::DrawMask( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ Bitmap aBitmap( rBitmap );
+ aBitmap.Crop( Rectangle( rSrcPtPixel, rSrcSizePixel ) );
+ ((PDFWriterImpl*)pImplementation)->drawMask( rDestPt, rDestSize, aBitmap, rMaskColor );
+}
+
+void PDFWriter::DrawGradient( const Rectangle& rRect, const Gradient& rGradient )
+{
+ ((PDFWriterImpl*)pImplementation)->drawGradient( rRect, rGradient );
+}
+
+void PDFWriter::DrawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
+{
+ ((PDFWriterImpl*)pImplementation)->drawGradient( rPolyPoly, rGradient );
+}
+
+void PDFWriter::DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
+{
+ ((PDFWriterImpl*)pImplementation)->drawHatch( rPolyPoly, rHatch );
+}
+
+void PDFWriter::DrawWallpaper( const Rectangle& rRect, const Wallpaper& rWallpaper )
+{
+ ((PDFWriterImpl*)pImplementation)->drawWallpaper( rRect, rWallpaper );
+}
+
+void PDFWriter::DrawTransparent( const PolyPolygon& rPolyPoly, USHORT nTransparencePercent )
+{
+ ((PDFWriterImpl*)pImplementation)->drawTransparent( rPolyPoly, nTransparencePercent );
+}
+
+void PDFWriter::BeginTransparencyGroup()
+{
+ ((PDFWriterImpl*)pImplementation)->beginTransparencyGroup();
+}
+
+void PDFWriter::EndTransparencyGroup( const Rectangle& rRect, USHORT nTransparentPercent )
+{
+ ((PDFWriterImpl*)pImplementation)->endTransparencyGroup( rRect, nTransparentPercent );
+}
+
+void PDFWriter::EndTransparencyGroup( const Rectangle& rRect, const Bitmap& rAlphaMask )
+{
+ ((PDFWriterImpl*)pImplementation)->endTransparencyGroup( rRect, rAlphaMask );
+}
+
+void PDFWriter::Push( USHORT nFlags )
+{
+ ((PDFWriterImpl*)pImplementation)->push( nFlags );
+}
+
+void PDFWriter::Pop()
+{
+ ((PDFWriterImpl*)pImplementation)->pop();
+}
+
+void PDFWriter::SetMapMode( const MapMode& rMapMode )
+{
+ ((PDFWriterImpl*)pImplementation)->setMapMode( rMapMode );
+}
+
+void PDFWriter::SetMapMode()
+{
+ ((PDFWriterImpl*)pImplementation)->setMapMode();
+}
+
+void PDFWriter::SetLineColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setLineColor( rColor );
+}
+
+void PDFWriter::SetFillColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setFillColor( rColor );
+}
+
+void PDFWriter::SetClipRegion()
+{
+ ((PDFWriterImpl*)pImplementation)->clearClipRegion();
+}
+
+void PDFWriter::SetClipRegion( const basegfx::B2DPolyPolygon& rRegion )
+{
+ ((PDFWriterImpl*)pImplementation)->setClipRegion( rRegion );
+}
+
+void PDFWriter::MoveClipRegion( long nHorzMove, long nVertMove )
+{
+ ((PDFWriterImpl*)pImplementation)->moveClipRegion( nHorzMove, nVertMove );
+}
+
+void PDFWriter::IntersectClipRegion( const basegfx::B2DPolyPolygon& rRegion )
+{
+ ((PDFWriterImpl*)pImplementation)->intersectClipRegion( rRegion );
+}
+
+void PDFWriter::IntersectClipRegion( const Rectangle& rRect )
+{
+ ((PDFWriterImpl*)pImplementation)->intersectClipRegion( rRect );
+}
+
+void PDFWriter::SetAntialiasing( USHORT nMode )
+{
+ ((PDFWriterImpl*)pImplementation)->setAntiAlias( (sal_Int32)nMode );
+}
+
+void PDFWriter::SetLayoutMode( ULONG nMode )
+{
+ ((PDFWriterImpl*)pImplementation)->setLayoutMode( (sal_Int32)nMode );
+}
+
+void PDFWriter::SetDigitLanguage( LanguageType eLang )
+{
+ ((PDFWriterImpl*)pImplementation)->setDigitLanguage( eLang );
+}
+
+void PDFWriter::SetTextColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setTextColor( rColor );
+}
+
+void PDFWriter::SetTextFillColor()
+{
+ ((PDFWriterImpl*)pImplementation)->setTextFillColor();
+}
+
+void PDFWriter::SetTextFillColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setTextFillColor( rColor );
+}
+
+void PDFWriter::SetTextLineColor()
+{
+ ((PDFWriterImpl*)pImplementation)->setTextLineColor();
+}
+
+void PDFWriter::SetTextLineColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setTextLineColor( rColor );
+}
+
+void PDFWriter::SetOverlineColor()
+{
+ ((PDFWriterImpl*)pImplementation)->setOverlineColor();
+}
+
+void PDFWriter::SetOverlineColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setOverlineColor( rColor );
+}
+
+void PDFWriter::SetTextAlign( ::TextAlign eAlign )
+{
+ ((PDFWriterImpl*)pImplementation)->setTextAlign( eAlign );
+}
+
+void PDFWriter::DrawJPGBitmap( SvStream& rStreamData, bool bIsTrueColor, const Size& rSrcSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask )
+{
+ ((PDFWriterImpl*)pImplementation)->drawJPGBitmap( rStreamData, bIsTrueColor, rSrcSizePixel, rTargetArea, rMask );
+}
+
+sal_Int32 PDFWriter::CreateLink( const Rectangle& rRect, sal_Int32 nPageNr )
+{
+ return ((PDFWriterImpl*)pImplementation)->createLink( rRect, nPageNr );
+}
+//--->i56629
+sal_Int32 PDFWriter::CreateNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
+{
+ return ((PDFWriterImpl*)pImplementation)->createNamedDest( sDestName, rRect, nPageNr, eType );
+}
+//<---
+sal_Int32 PDFWriter::CreateDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
+{
+ return ((PDFWriterImpl*)pImplementation)->createDest( rRect, nPageNr, eType );
+}
+
+sal_Int32 PDFWriter::SetLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
+{
+ return ((PDFWriterImpl*)pImplementation)->setLinkDest( nLinkId, nDestId );
+}
+
+sal_Int32 PDFWriter::SetLinkURL( sal_Int32 nLinkId, const rtl::OUString& rURL )
+{
+ return ((PDFWriterImpl*)pImplementation)->setLinkURL( nLinkId, rURL );
+}
+
+void PDFWriter::SetLinkPropertyID( sal_Int32 nLinkId, sal_Int32 nPropertyId )
+{
+ ((PDFWriterImpl*)pImplementation)->setLinkPropertyId( nLinkId, nPropertyId );
+}
+
+sal_Int32 PDFWriter::CreateOutlineItem( sal_Int32 nParent, const rtl::OUString& rText, sal_Int32 nDestID )
+{
+ return ((PDFWriterImpl*)pImplementation)->createOutlineItem( nParent, rText, nDestID );
+}
+
+sal_Int32 PDFWriter::SetOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent )
+{
+ return ((PDFWriterImpl*)pImplementation)->setOutlineItemParent( nItem, nNewParent );
+}
+
+sal_Int32 PDFWriter::SetOutlineItemText( sal_Int32 nItem, const rtl::OUString& rText )
+{
+ return ((PDFWriterImpl*)pImplementation)->setOutlineItemText( nItem, rText );
+}
+
+sal_Int32 PDFWriter::SetOutlineItemDest( sal_Int32 nItem, sal_Int32 nDest )
+{
+ return ((PDFWriterImpl*)pImplementation)->setOutlineItemDest( nItem, nDest );
+}
+
+void PDFWriter::CreateNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
+{
+ ((PDFWriterImpl*)pImplementation)->createNote( rRect, rNote, nPageNr );
+}
+
+sal_Int32 PDFWriter::BeginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias )
+{
+ return ((PDFWriterImpl*)pImplementation)->beginStructureElement( eType, rAlias );
+}
+
+void PDFWriter::EndStructureElement()
+{
+ ((PDFWriterImpl*)pImplementation)->endStructureElement();
+}
+
+bool PDFWriter::SetCurrentStructureElement( sal_Int32 nID )
+{
+ return ((PDFWriterImpl*)pImplementation)->setCurrentStructureElement( nID );
+}
+
+sal_Int32 PDFWriter::GetCurrentStructureElement()
+{
+ return ((PDFWriterImpl*)pImplementation)->getCurrentStructureElement();
+}
+
+bool PDFWriter::SetStructureAttribute( enum StructAttribute eAttr, enum StructAttributeValue eVal )
+{
+ return ((PDFWriterImpl*)pImplementation)->setStructureAttribute( eAttr, eVal );
+}
+
+bool PDFWriter::SetStructureAttributeNumerical( enum StructAttribute eAttr, sal_Int32 nValue )
+{
+ return ((PDFWriterImpl*)pImplementation)->setStructureAttributeNumerical( eAttr, nValue );
+}
+
+void PDFWriter::SetStructureBoundingBox( const Rectangle& rRect )
+{
+ ((PDFWriterImpl*)pImplementation)->setStructureBoundingBox( rRect );
+}
+
+void PDFWriter::SetActualText( const String& rText )
+{
+ ((PDFWriterImpl*)pImplementation)->setActualText( rText );
+}
+
+void PDFWriter::SetAlternateText( const String& rText )
+{
+ ((PDFWriterImpl*)pImplementation)->setAlternateText( rText );
+}
+
+void PDFWriter::SetAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr )
+{
+ ((PDFWriterImpl*)pImplementation)->setAutoAdvanceTime( nSeconds, nPageNr );
+}
+
+void PDFWriter::SetPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr )
+{
+ ((PDFWriterImpl*)pImplementation)->setPageTransition( eType, nMilliSec, nPageNr );
+}
+
+sal_Int32 PDFWriter::CreateControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr )
+{
+ return ((PDFWriterImpl*)pImplementation)->createControl( rControl, nPageNr );
+}
+
+PDFOutputStream::~PDFOutputStream()
+{
+}
+
+void PDFWriter::AddStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress )
+{
+ ((PDFWriterImpl*)pImplementation)->addStream( rMimeType, pStream, bCompress );
+}
+
+void PDFWriter::BeginPattern( const Rectangle& rCellRect )
+{
+ ((PDFWriterImpl*)pImplementation)->beginPattern( rCellRect );
+}
+
+sal_Int32 PDFWriter::EndPattern( const SvtGraphicFill::Transform& rTransform )
+{
+ return ((PDFWriterImpl*)pImplementation)->endPattern( rTransform );
+}
+
+void PDFWriter::DrawPolyPolygon( const PolyPolygon& rPolyPoly, sal_Int32 nPattern, bool bEOFill )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyPolygon( rPolyPoly, nPattern, bEOFill );
+}
+
+std::set< PDFWriter::ErrorCode > PDFWriter::GetErrors()
+{
+ return ((PDFWriterImpl*)pImplementation)->getErrors();
+}
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
new file mode 100644
index 000000000000..7b7f3bbcb4d3
--- /dev/null
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -0,0 +1,12305 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <algorithm>
+
+#include <tools/urlobj.hxx>
+#include <pdfwriter_impl.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/debug.hxx>
+#include <tools/zcodec.hxx>
+#include <tools/stream.hxx>
+#include <i18npool/mslangid.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/image.hxx>
+#include <vcl/outdev.h>
+#include <vcl/sallayout.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/fontsubset.hxx>
+#include <vcl/textlayout.hxx>
+#include <svsys.h>
+#include <vcl/salgdi.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/thread.h>
+#include <osl/file.h>
+#include <rtl/crc.h>
+#include <rtl/digest.h>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include "cppuhelper/implbase1.hxx"
+#include <icc/sRGB-IEC61966-2.1.hxx>
+#include <vcl/lineinfo.hxx>
+
+using namespace vcl;
+using namespace rtl;
+
+#if (OSL_DEBUG_LEVEL < 2)
+#define COMPRESS_PAGES
+#else
+#define DEBUG_DISABLE_PDFCOMPRESSION // also do not compress streams
+#endif
+
+#ifdef DO_TEST_PDF
+class PDFTestOutputStream : public PDFOutputStream
+{
+ public:
+ virtual ~PDFTestOutputStream();
+ virtual void write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream );
+};
+
+PDFTestOutputStream::~PDFTestOutputStream()
+{
+}
+
+void PDFTestOutputStream::write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream )
+{
+ OString aStr( "lalala\ntest\ntest\ntest" );
+ com::sun::star::uno::Sequence< sal_Int8 > aData( aStr.getLength() );
+ rtl_copyMemory( aData.getArray(), aStr.getStr(), aStr.getLength() );
+ xStream->writeBytes( aData );
+}
+
+// this test code cannot be used to test PDF/A-1 because it forces
+// control item (widgets) to bypass the structure controlling
+// the embedding of such elements in actual run
+void doTestCode()
+{
+ static const char* pHome = getenv( "HOME" );
+ rtl::OUString aTestFile( RTL_CONSTASCII_USTRINGPARAM( "file://" ) );
+ aTestFile += rtl::OUString( pHome, strlen( pHome ), RTL_TEXTENCODING_MS_1252 );
+ aTestFile += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/pdf_export_test.pdf" ) );
+
+ PDFWriter::PDFWriterContext aContext;
+ aContext.URL = aTestFile;
+ aContext.Version = PDFWriter::PDF_1_4;
+ aContext.Tagged = true;
+ aContext.InitialPage = 2;
+
+ PDFWriter aWriter( aContext );
+ PDFDocInfo aDocInfo;
+ aDocInfo.Title = OUString( RTL_CONSTASCII_USTRINGPARAM( "PDF export test document" ) );
+ aDocInfo.Producer = OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL" ) );
+ aWriter.SetDocInfo( aDocInfo );
+ aWriter.NewPage( 595, 842 );
+ aWriter.BeginStructureElement( PDFWriter::Document );
+ // set duration of 3 sec for first page
+ aWriter.SetAutoAdvanceTime( 3 );
+ aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
+
+ aWriter.SetFillColor( Color( COL_LIGHTRED ) );
+ aWriter.SetLineColor( Color( COL_LIGHTGREEN ) );
+ aWriter.DrawRect( Rectangle( Point( 2000, 200 ), Size( 8000, 3000 ) ), 5000, 2000 );
+
+ aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
+ aWriter.SetTextColor( Color( COL_BLACK ) );
+ aWriter.SetLineColor( Color( COL_BLACK ) );
+ aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
+
+ Rectangle aRect( Point( 5000, 5000 ), Size( 6000, 3000 ) );
+ aWriter.DrawRect( aRect );
+ aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 1" ) ) );
+ sal_Int32 nFirstLink = aWriter.CreateLink( aRect );
+ PDFNote aNote;
+ aNote.Title = String( RTL_CONSTASCII_USTRINGPARAM( "A small test note" ) );
+ aNote.Contents = String( RTL_CONSTASCII_USTRINGPARAM( "There is no business like show business like no business i know. Everything about it is appealing." ) );
+ aWriter.CreateNote( Rectangle( Point( aRect.Right(), aRect.Top() ), Size( 6000, 3000 ) ), aNote );
+
+ Rectangle aTargetRect( Point( 3000, 23000 ), Size( 12000, 6000 ) );
+ aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
+ aWriter.DrawRect( aTargetRect );
+ aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest second link" ) ) );
+ sal_Int32 nSecondDest = aWriter.CreateDest( aTargetRect );
+
+ aWriter.BeginStructureElement( PDFWriter::Section );
+ aWriter.BeginStructureElement( PDFWriter::Heading );
+ aWriter.DrawText( Point(4500, 9000), String( RTL_CONSTASCII_USTRINGPARAM( "A small structure test" ) ) );
+ aWriter.EndStructureElement();
+ aWriter.BeginStructureElement( PDFWriter::Paragraph );
+ aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
+ aWriter.SetStructureAttribute( PDFWriter::TextDecorationType, PDFWriter::Underline );
+ aWriter.DrawText( Rectangle( Point( 4500, 10000 ), Size( 12000, 6000 ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "It was the best of PDF, it was the worst of PDF ... or so. This is a pretty nonsensical text to denote a paragraph. I suggest you stop reading it. Because if you read on you might get bored. So continue on your on risk. Hey, you're still here ? Why do you continue to read this as it is of no use at all ? OK, it's your time, but still... . Woah, i even get bored writing this, so let's end this here and now." ) ),
+ TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
+ );
+ aWriter.SetActualText( String( RTL_CONSTASCII_USTRINGPARAM( "It was the best of PDF, it was the worst of PDF ... or so. This is a pretty nonsensical text to denote a paragraph. I suggest you stop reading it. Because if you read on you might get bored. So continue on your on risk. Hey, you're still here ? Why do you continue to read this as it is of no use at all ? OK, it's your time, but still... . Woah, i even get bored writing this, so let's end this here and now." ) ) );
+ aWriter.SetAlternateText( String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph contains some lengthy nonsense to test structural element emission of PDFWriter." ) ) );
+ aWriter.EndStructureElement();
+ sal_Int32 nLongPara = aWriter.BeginStructureElement( PDFWriter::Paragraph );
+ aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
+ aWriter.DrawText( Rectangle( Point( 4500, 19000 ), Size( 12000, 1000 ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph is nothing special either but ends on the next page structurewise" ) ),
+ TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
+ );
+
+ aWriter.NewPage( 595, 842 );
+ // test AddStream interface
+ aWriter.AddStream( String( RTL_CONSTASCII_USTRINGPARAM( "text/plain" ) ), new PDFTestOutputStream(), true );
+ // set transitional mode
+ aWriter.SetPageTransition( PDFWriter::WipeRightToLeft, 1500 );
+ aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
+ aWriter.SetTextColor( Color( COL_BLACK ) );
+ aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
+ aWriter.DrawText( Rectangle( Point( 4500, 1500 ), Size( 12000, 3000 ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "Here's where all things come to an end ... well at least the paragaph from the last page." ) ),
+ TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
+ );
+ aWriter.EndStructureElement();
+
+ aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
+ // disable structure
+ aWriter.BeginStructureElement( PDFWriter::NonStructElement );
+ aWriter.DrawRect( aRect );
+ aWriter.BeginStructureElement( PDFWriter::Paragraph );
+ aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 2" ) ) );
+ sal_Int32 nSecondLink = aWriter.CreateLink( aRect );
+
+ aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
+ aWriter.BeginStructureElement( PDFWriter::ListItem );
+ aWriter.DrawRect( aTargetRect );
+ aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest first link" ) ) );
+ sal_Int32 nFirstDest = aWriter.CreateDest( aTargetRect );
+ // enable structure
+ aWriter.EndStructureElement();
+ // add something to the long paragraph as an afterthought
+ sal_Int32 nSaveStruct = aWriter.GetCurrentStructureElement();
+ aWriter.SetCurrentStructureElement( nLongPara );
+ aWriter.DrawText( Rectangle( Point( 4500,4500 ), Size( 12000, 1000 ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "Add something to the longish paragraph above." ) ),
+ TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
+ aWriter.SetCurrentStructureElement( nSaveStruct );
+ aWriter.EndStructureElement();
+ aWriter.EndStructureElement();
+ aWriter.BeginStructureElement( PDFWriter::Figure );
+ aWriter.BeginStructureElement( PDFWriter::Caption );
+ aWriter.DrawText( Point( 4500, 9000 ), String( RTL_CONSTASCII_USTRINGPARAM( "Some drawing stuff inside the structure" ) ) );
+ aWriter.EndStructureElement();
+
+ // test clipping
+ basegfx::B2DPolyPolygon aClip;
+ basegfx::B2DPolygon aClipPoly;
+ aClipPoly.append( basegfx::B2DPoint( 8250, 9600 ) );
+ aClipPoly.append( basegfx::B2DPoint( 16500, 11100 ) );
+ aClipPoly.append( basegfx::B2DPoint( 8250, 12600 ) );
+ aClipPoly.append( basegfx::B2DPoint( 4500, 11100 ) );
+ aClipPoly.setClosed( true );
+ //aClipPoly.flip();
+ aClip.append( aClipPoly );
+
+ aWriter.Push( PUSH_CLIPREGION | PUSH_FILLCOLOR );
+ aWriter.SetClipRegion( aClip );
+ aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
+ aWriter.MoveClipRegion( 1000, 500 );
+ aWriter.SetFillColor( Color( COL_RED ) );
+ aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
+ aWriter.Pop();
+ // test transparency
+ // draw background
+ Rectangle aTranspRect( Point( 7500, 13500 ), Size( 9000, 6000 ) );
+ aWriter.SetFillColor( Color( COL_LIGHTRED ) );
+ aWriter.DrawRect( aTranspRect );
+ aWriter.BeginTransparencyGroup();
+
+ aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
+ aWriter.DrawEllipse( aTranspRect );
+ aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
+ aWriter.DrawText( aTranspRect,
+ String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
+ TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
+
+ aWriter.EndTransparencyGroup( aTranspRect, 50 );
+
+ // prepare an alpha mask
+ Bitmap aTransMask( Size( 256, 256 ), 8, &Bitmap::GetGreyPalette( 256 ) );
+ BitmapWriteAccess* pAcc = aTransMask.AcquireWriteAccess();
+ for( int nX = 0; nX < 256; nX++ )
+ for( int nY = 0; nY < 256; nY++ )
+ pAcc->SetPixel( nX, nY, BitmapColor( (BYTE)((nX+nY)/2) ) );
+ aTransMask.ReleaseAccess( pAcc );
+ aTransMask.SetPrefMapMode( MAP_MM );
+ aTransMask.SetPrefSize( Size( 10, 10 ) );
+
+ aWriter.DrawBitmap( Point( 600, 13500 ), Size( 3000, 3000 ), aTransMask );
+
+ aTranspRect = Rectangle( Point( 4200, 13500 ), Size( 3000, 3000 ) );
+ aWriter.SetFillColor( Color( COL_LIGHTRED ) );
+ aWriter.DrawRect( aTranspRect );
+ aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
+ aWriter.DrawEllipse( aTranspRect );
+ aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
+ aWriter.DrawText( aTranspRect,
+ String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
+ TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
+ aTranspRect = Rectangle( Point( 1500, 16500 ), Size( 4800, 3000 ) );
+ aWriter.SetFillColor( Color( COL_LIGHTRED ) );
+ aWriter.DrawRect( aTranspRect );
+ aWriter.BeginTransparencyGroup();
+ aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
+ aWriter.DrawEllipse( aTranspRect );
+ aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
+ aWriter.DrawText( aTranspRect,
+ String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
+ TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
+ aWriter.EndTransparencyGroup( aTranspRect, aTransMask );
+
+ Bitmap aImageBmp( Size( 256, 256 ), 24 );
+ pAcc = aImageBmp.AcquireWriteAccess();
+ pAcc->SetFillColor( Color( 0xff, 0, 0xff ) );
+ pAcc->FillRect( Rectangle( Point( 0, 0 ), Size( 256, 256 ) ) );
+ aImageBmp.ReleaseAccess( pAcc );
+ BitmapEx aBmpEx( aImageBmp, AlphaMask( aTransMask ) );
+ aWriter.DrawBitmapEx( Point( 1500, 19500 ), Size( 4800, 3000 ), aBmpEx );
+
+
+ aWriter.EndStructureElement();
+ aWriter.EndStructureElement();
+
+ LineInfo aLI( LINE_DASH, 3 );
+ aLI.SetDashCount( 2 );
+ aLI.SetDashLen( 50 );
+ aLI.SetDotCount( 2 );
+ aLI.SetDotLen( 25 );
+ aLI.SetDistance( 15 );
+ Point aLIPoints[] = { Point( 4000, 10000 ),
+ Point( 8000, 12000 ),
+ Point( 3000, 19000 ) };
+ Polygon aLIPoly( 3, aLIPoints );
+ aWriter.SetLineColor( Color( COL_BLUE ) );
+ aWriter.SetFillColor();
+ aWriter.DrawPolyLine( aLIPoly, aLI );
+
+ aLI.SetDashCount( 4 );
+ aLIPoly.Move( 1000, 1000 );
+ aWriter.DrawPolyLine( aLIPoly, aLI );
+
+ aWriter.NewPage( 595, 842 );
+ aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
+ Wallpaper aWall( aTransMask );
+ aWall.SetStyle( WALLPAPER_TILE );
+ aWriter.DrawWallpaper( Rectangle( Point( 4400, 4200 ), Size( 10200, 6300 ) ), aWall );
+
+ aWriter.Push( PUSH_ALL );
+ aWriter.BeginPattern(Rectangle(Point(0,0),Size(2000,1000)));
+ aWriter.SetFillColor( Color( COL_RED ) );
+ aWriter.SetLineColor( Color( COL_LIGHTBLUE ) );
+ Point aFillPoints[] = { Point( 1000, 0 ),
+ Point( 0, 1000 ),
+ Point( 2000, 1000 ) };
+ aWriter.DrawPolygon( Polygon( 3, aFillPoints ) );
+ aWriter.DrawBitmap( Point( 200, 200 ), Size( 1600, 600 ), aTransMask );
+ aWriter.DrawText( Rectangle( Point( 200, 200 ), Size( 1600, 600 ) ), String( RTL_CONSTASCII_USTRINGPARAM( "Pattern" ) ) );
+ sal_Int32 nPattern = aWriter.EndPattern( SvtGraphicFill::Transform() );
+ aWriter.Pop();
+ Rectangle aPolyRect( Point( 3800, 11200 ), Size( 10200, 6300 ) );
+ aWriter.DrawPolyPolygon( PolyPolygon( Polygon( aPolyRect ) ), nPattern, true );
+ aWriter.SetFillColor();
+ aWriter.SetLineColor( Color( COL_LIGHTBLUE ) );
+ aWriter.DrawRect( aPolyRect );
+
+ aWriter.NewPage( 595, 842 );
+ aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
+ aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
+ aWriter.SetTextColor( Color( COL_BLACK ) );
+ aRect = Rectangle( Point( 4500, 6000 ), Size( 6000, 1500 ) );
+ aWriter.DrawRect( aRect );
+ aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "www.heise.de" ) ) );
+ sal_Int32 nURILink = aWriter.CreateLink( aRect );
+ aWriter.SetLinkURL( nURILink, OUString( RTL_CONSTASCII_USTRINGPARAM( "http://www.heise.de" ) ) );
+
+ aWriter.SetLinkDest( nFirstLink, nFirstDest );
+ aWriter.SetLinkDest( nSecondLink, nSecondDest );
+
+ // include a button
+ PDFWriter::PushButtonWidget aBtn;
+ aBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testButton" ) );
+ aBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test button" ) );
+ aBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "hit me" ) );
+ aBtn.Location = Rectangle( Point( 4500, 9000 ), Size( 4500, 3000 ) );
+ aBtn.Border = aBtn.Background = true;
+ aWriter.CreateControl( aBtn );
+
+ // include a uri button
+ PDFWriter::PushButtonWidget aUriBtn;
+ aUriBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "wwwButton" ) );
+ aUriBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A URI button" ) );
+ aUriBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "to www" ) );
+ aUriBtn.Location = Rectangle( Point( 9500, 9000 ), Size( 4500, 3000 ) );
+ aUriBtn.Border = aUriBtn.Background = true;
+ aUriBtn.URL = OUString( RTL_CONSTASCII_USTRINGPARAM( "http://www.heise.de" ) );
+ aWriter.CreateControl( aUriBtn );
+
+ // include a dest button
+ PDFWriter::PushButtonWidget aDstBtn;
+ aDstBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "destButton" ) );
+ aDstBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A Dest button" ) );
+ aDstBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "to paragraph" ) );
+ aDstBtn.Location = Rectangle( Point( 14500, 9000 ), Size( 4500, 3000 ) );
+ aDstBtn.Border = aDstBtn.Background = true;
+ aDstBtn.Dest = nFirstDest;
+ aWriter.CreateControl( aDstBtn );
+
+ PDFWriter::CheckBoxWidget aCBox;
+ aCBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "textCheckBox" ) );
+ aCBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test check box" ) );
+ aCBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "check me" ) );
+ aCBox.Location = Rectangle( Point( 4500, 13500 ), Size( 3000, 750 ) );
+ aCBox.Checked = true;
+ aCBox.Border = aCBox.Background = false;
+ aWriter.CreateControl( aCBox );
+
+ PDFWriter::CheckBoxWidget aCBox2;
+ aCBox2.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "textCheckBox2" ) );
+ aCBox2.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "Another test check box" ) );
+ aCBox2.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "check me right" ) );
+ aCBox2.Location = Rectangle( Point( 4500, 14250 ), Size( 3000, 750 ) );
+ aCBox2.Checked = true;
+ aCBox2.Border = aCBox2.Background = false;
+ aCBox2.ButtonIsLeft = false;
+ aWriter.CreateControl( aCBox2 );
+
+ PDFWriter::RadioButtonWidget aRB1;
+ aRB1.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb1_1" ) );
+ aRB1.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 1 button 1" ) );
+ aRB1.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Despair" ) );
+ aRB1.Location = Rectangle( Point( 4500, 15000 ), Size( 6000, 1000 ) );
+ aRB1.Selected = true;
+ aRB1.RadioGroup = 1;
+ aRB1.Border = aRB1.Background = true;
+ aRB1.ButtonIsLeft = false;
+ aRB1.BorderColor = Color( COL_LIGHTGREEN );
+ aRB1.BackgroundColor = Color( COL_LIGHTBLUE );
+ aRB1.TextColor = Color( COL_LIGHTRED );
+ aRB1.TextFont = Font( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ), Size( 0, 800 ) );
+ aWriter.CreateControl( aRB1 );
+
+ PDFWriter::RadioButtonWidget aRB2;
+ aRB2.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb2_1" ) );
+ aRB2.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 2 button 1" ) );
+ aRB2.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Joy" ) );
+ aRB2.Location = Rectangle( Point( 10500, 15000 ), Size( 3000, 1000 ) );
+ aRB2.Selected = true;
+ aRB2.RadioGroup = 2;
+ aWriter.CreateControl( aRB2 );
+
+ PDFWriter::RadioButtonWidget aRB3;
+ aRB3.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb1_2" ) );
+ aRB3.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 1 button 2" ) );
+ aRB3.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Desperation" ) );
+ aRB3.Location = Rectangle( Point( 4500, 16000 ), Size( 3000, 1000 ) );
+ aRB3.Selected = true;
+ aRB3.RadioGroup = 1;
+ aWriter.CreateControl( aRB3 );
+
+ PDFWriter::EditWidget aEditBox;
+ aEditBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testEdit" ) );
+ aEditBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test edit field" ) );
+ aEditBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "A little test text" ) );
+ aEditBox.TextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER;
+ aEditBox.Location = Rectangle( Point( 10000, 18000 ), Size( 5000, 1500 ) );
+ aEditBox.MaxLen = 100;
+ aEditBox.Border = aEditBox.Background = true;
+ aEditBox.BorderColor = Color( COL_BLACK );
+ aWriter.CreateControl( aEditBox );
+
+ // normal list box
+ PDFWriter::ListBoxWidget aLstBox;
+ aLstBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testListBox" ) );
+ aLstBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "One" ) );
+ aLstBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "select me" ) );
+ aLstBox.Location = Rectangle( Point( 4500, 18000 ), Size( 3000, 1500 ) );
+ aLstBox.Sort = true;
+ aLstBox.MultiSelect = true;
+ aLstBox.Border = aLstBox.Background = true;
+ aLstBox.BorderColor = Color( COL_BLACK );
+ aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "One" ) ) );
+ aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Two" ) ) );
+ aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Three" ) ) );
+ aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Four" ) ) );
+ aLstBox.SelectedEntries.push_back( 1 );
+ aLstBox.SelectedEntries.push_back( 2 );
+ aWriter.CreateControl( aLstBox );
+
+ // dropdown list box
+ aLstBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testDropDownListBox" ) );
+ aLstBox.DropDown = true;
+ aLstBox.Location = Rectangle( Point( 4500, 19500 ), Size( 3000, 500 ) );
+ aWriter.CreateControl( aLstBox );
+
+ // combo box
+ PDFWriter::ComboBoxWidget aComboBox;
+ aComboBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testComboBox" ) );
+ aComboBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "test a combobox" ) );
+ aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Larry" ) ) );
+ aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Curly" ) ) );
+ aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Moe" ) ) );
+ aComboBox.Location = Rectangle( Point( 4500, 20000 ), Size( 3000, 500 ) );
+ aWriter.CreateControl( aComboBox );
+
+ // test outlines
+ sal_Int32 nPage1OL = aWriter.CreateOutlineItem();
+ aWriter.SetOutlineItemText( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Page 1" ) ) );
+ aWriter.SetOutlineItemDest( nPage1OL, nSecondDest );
+ aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2" ) ), nSecondDest );
+ aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2 revisited" ) ), nSecondDest );
+ aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2 again" ) ), nSecondDest );
+ sal_Int32 nPage2OL = aWriter.CreateOutlineItem();
+ aWriter.SetOutlineItemText( nPage2OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Page 2" ) ) );
+ aWriter.CreateOutlineItem( nPage2OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 1" ) ), nFirstDest );
+
+ aWriter.EndStructureElement(); // close document
+ aWriter.Emit();
+}
+#endif
+
+static const sal_Int32 nLog10Divisor = 1;
+static const double fDivisor = 10.0;
+
+static inline double pixelToPoint( sal_Int32 px ) { return double(px)/fDivisor; }
+static inline double pixelToPoint( double px ) { return px/fDivisor; }
+static inline sal_Int32 pointToPixel( double pt ) { return sal_Int32(pt*fDivisor); }
+
+static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer )
+{
+ static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
+ rBuffer.append( pHexDigits[ nInt & 15 ] );
+}
+
+static void appendName( const OUString& rStr, OStringBuffer& rBuffer )
+{
+// FIXME i59651 add a check for max length of 127 chars? Per PDF spec 1.4, appendix C.1
+// I guess than when reading the #xx sequence it will count for a single character.
+ OString aStr( OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ) );
+ const sal_Char* pStr = aStr.getStr();
+ int nLen = aStr.getLength();
+ for( int i = 0; i < nLen; i++ )
+ {
+ /* #i16920# PDF recommendation: output UTF8, any byte
+ * outside the interval [33(=ASCII'!');126(=ASCII'~')]
+ * should be escaped hexadecimal
+ * for the sake of ghostscript which also reads PDF
+ * but has a narrower acceptance rate we only pass
+ * alphanumerics and '-' literally.
+ */
+ if( (pStr[i] >= 'A' && pStr[i] <= 'Z' ) ||
+ (pStr[i] >= 'a' && pStr[i] <= 'z' ) ||
+ (pStr[i] >= '0' && pStr[i] <= '9' ) ||
+ pStr[i] == '-' )
+ {
+ rBuffer.append( pStr[i] );
+ }
+ else
+ {
+ rBuffer.append( '#' );
+ appendHex( (sal_Int8)pStr[i], rBuffer );
+ }
+ }
+}
+
+static void appendName( const sal_Char* pStr, OStringBuffer& rBuffer )
+{
+//FIXME i59651 see above
+ while( pStr && *pStr )
+ {
+ if( (*pStr >= 'A' && *pStr <= 'Z' ) ||
+ (*pStr >= 'a' && *pStr <= 'z' ) ||
+ (*pStr >= '0' && *pStr <= '9' ) ||
+ *pStr == '-' )
+ {
+ rBuffer.append( *pStr );
+ }
+ else
+ {
+ rBuffer.append( '#' );
+ appendHex( (sal_Int8)*pStr, rBuffer );
+ }
+ pStr++;
+ }
+}
+
+//used only to emit encoded passwords
+static void appendLiteralString( const sal_Char* pStr, sal_Int32 nLength, OStringBuffer& rBuffer )
+{
+ while( nLength )
+ {
+ switch( *pStr )
+ {
+ case '\n' :
+ rBuffer.append( "\\n" );
+ break;
+ case '\r' :
+ rBuffer.append( "\\r" );
+ break;
+ case '\t' :
+ rBuffer.append( "\\t" );
+ break;
+ case '\b' :
+ rBuffer.append( "\\b" );
+ break;
+ case '\f' :
+ rBuffer.append( "\\f" );
+ break;
+ case '(' :
+ case ')' :
+ case '\\' :
+ rBuffer.append( "\\" );
+ rBuffer.append( (sal_Char) *pStr );
+ break;
+ default:
+ rBuffer.append( (sal_Char) *pStr );
+ break;
+ }
+ pStr++;
+ nLength--;
+ }
+}
+
+/**--->i56629
+ * Convert a string before using it.
+ *
+ * This string conversion function is needed because the destination name
+ * in a PDF file seen through an Internet browser should be
+ * specially crafted, in order to be used directly by the browser.
+ * In this way the fragment part of a hyperlink to a PDF file (e.g. something
+ * as 'test1/test2/a-file.pdf#thefragment) will be (hopefully) interpreted by the
+ * PDF reader (currently only Adobe Reader plug-in seems to be working that way) called
+ * from inside the Internet browser as: 'open the file test1/test2/a-file.pdf
+ * and go to named destination thefragment using default zoom'.
+ * The conversion is needed because in case of a fragment in the form: Slide%201
+ * (meaning Slide 1) as it is converted obeying the Inet rules, it will become Slide25201
+ * using this conversion, in both the generated named destinations, fragment and GoToR
+ * destination.
+ *
+ * The names for destinations are name objects and so they don't need to be encrypted
+ * even though they expose the content of PDF file (e.g. guessing the PDF content from the
+ * destination name).
+ *
+ * Fhurter limitation: it is advisable to use standard ASCII characters for
+ * OOo bookmarks.
+*/
+static void appendDestinationName( const rtl::OUString& rString, OStringBuffer& rBuffer )
+{
+ const sal_Unicode* pStr = rString.getStr();
+ sal_Int32 nLen = rString.getLength();
+ for( int i = 0; i < nLen; i++ )
+ {
+ sal_Unicode aChar = pStr[i];
+ if( (aChar >= '0' && aChar <= '9' ) ||
+ (aChar >= 'a' && aChar <= 'z' ) ||
+ (aChar >= 'A' && aChar <= 'Z' ) ||
+ aChar == '-' )
+ {
+ rBuffer.append((sal_Char)aChar);
+ }
+ else
+ {
+ sal_Int8 aValueHigh = sal_Int8(aChar >> 8);
+ if(aValueHigh > 0)
+ appendHex( aValueHigh, rBuffer );
+ appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
+ }
+ }
+}
+//<--- i56629
+
+static void appendUnicodeTextString( const rtl::OUString& rString, OStringBuffer& rBuffer )
+{
+ rBuffer.append( "FEFF" );
+ const sal_Unicode* pStr = rString.getStr();
+ sal_Int32 nLen = rString.getLength();
+ for( int i = 0; i < nLen; i++ )
+ {
+ sal_Unicode aChar = pStr[i];
+ appendHex( (sal_Int8)(aChar >> 8), rBuffer );
+ appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
+ }
+}
+
+void PDFWriterImpl::createWidgetFieldName( sal_Int32 i_nWidgetIndex, const PDFWriter::AnyWidget& i_rControl )
+{
+ /* #i80258# previously we use appendName here
+ however we need a slightly different coding scheme than the normal
+ name encoding for field names
+ */
+ const OUString& rName = (m_aContext.Version > PDFWriter::PDF_1_2) ? i_rControl.Name : i_rControl.Text;
+ OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ) );
+ const sal_Char* pStr = aStr.getStr();
+ int nLen = aStr.getLength();
+
+ OStringBuffer aBuffer( rName.getLength()+64 );
+ for( int i = 0; i < nLen; i++ )
+ {
+ /* #i16920# PDF recommendation: output UTF8, any byte
+ * outside the interval [32(=ASCII' ');126(=ASCII'~')]
+ * should be escaped hexadecimal
+ */
+ if( (pStr[i] >= 32 && pStr[i] <= 126 ) )
+ aBuffer.append( pStr[i] );
+ else
+ {
+ aBuffer.append( '#' );
+ appendHex( (sal_Int8)pStr[i], aBuffer );
+ }
+ }
+
+ OString aFullName( aBuffer.makeStringAndClear() );
+
+ /* #i82785# create hierarchical fields down to the for each dot in i_rName */
+ sal_Int32 nTokenIndex = 0, nLastTokenIndex = 0;
+ OString aPartialName;
+ OString aDomain;
+ do
+ {
+ nLastTokenIndex = nTokenIndex;
+ aPartialName = aFullName.getToken( 0, '.', nTokenIndex );
+ if( nTokenIndex != -1 )
+ {
+ // find or create a hierarchical field
+ // first find the fully qualified name up to this field
+ aDomain = aFullName.copy( 0, nTokenIndex-1 );
+ std::hash_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
+ if( it == m_aFieldNameMap.end() )
+ {
+ // create new hierarchy field
+ sal_Int32 nNewWidget = m_aWidgets.size();
+ m_aWidgets.push_back( PDFWidget() );
+ m_aWidgets[nNewWidget].m_nObject = createObject();
+ m_aWidgets[nNewWidget].m_eType = PDFWriter::Hierarchy;
+ m_aWidgets[nNewWidget].m_aName = aPartialName;
+ m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
+ m_aFieldNameMap[aDomain] = nNewWidget;
+ m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
+ if( nLastTokenIndex > 0 )
+ {
+ // this field is not a root field and
+ // needs to be inserted to its parent
+ OString aParentDomain( aDomain.copy( 0, nLastTokenIndex-1 ) );
+ it = m_aFieldNameMap.find( aParentDomain );
+ OSL_ENSURE( it != m_aFieldNameMap.end(), "field name not found" );
+ if( it != m_aFieldNameMap.end() )
+ {
+ OSL_ENSURE( it->second < sal_Int32(m_aWidgets.size()), "invalid field number entry" );
+ if( it->second < sal_Int32(m_aWidgets.size()) )
+ {
+ PDFWidget& rParentField( m_aWidgets[it->second] );
+ rParentField.m_aKids.push_back( m_aWidgets[nNewWidget].m_nObject );
+ rParentField.m_aKidsIndex.push_back( nNewWidget );
+ m_aWidgets[nNewWidget].m_nParent = rParentField.m_nObject;
+ }
+ }
+ }
+ }
+ else if( m_aWidgets[it->second].m_eType != PDFWriter::Hierarchy )
+ {
+ // this is invalid, someone tries to have a terminal field as parent
+ // example: a button with the name foo.bar exists and
+ // another button is named foo.bar.no
+ // workaround: put the second terminal field as much up in the hierarchy as
+ // necessary to have a non-terminal field as parent (or none at all)
+ // since it->second already is terminal, we just need to use its parent
+ aDomain = OString();
+ aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
+ if( nLastTokenIndex > 0 )
+ {
+ aDomain = aFullName.copy( 0, nLastTokenIndex-1 );
+ OStringBuffer aBuf( aDomain.getLength() + 1 + aPartialName.getLength() );
+ aBuf.append( aDomain );
+ aBuf.append( '.' );
+ aBuf.append( aPartialName );
+ aFullName = aBuf.makeStringAndClear();
+ }
+ else
+ aFullName = aPartialName;
+ break;
+ }
+ }
+ } while( nTokenIndex != -1 );
+
+ // insert widget into its hierarchy field
+ if( aDomain.getLength() )
+ {
+ std::hash_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
+ if( it != m_aFieldNameMap.end() )
+ {
+ OSL_ENSURE( it->second >= 0 && it->second < sal_Int32( m_aWidgets.size() ), "invalid field index" );
+ if( it->second >= 0 && it->second < sal_Int32(m_aWidgets.size()) )
+ {
+ m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[it->second].m_nObject;
+ m_aWidgets[it->second].m_aKids.push_back( m_aWidgets[i_nWidgetIndex].m_nObject);
+ m_aWidgets[it->second].m_aKidsIndex.push_back( i_nWidgetIndex );
+ }
+ }
+ }
+
+ if( aPartialName.getLength() == 0 )
+ {
+ // how funny, an empty field name
+ if( i_rControl.getType() == PDFWriter::RadioButton )
+ {
+ aPartialName = "RadioGroup";
+ aPartialName += OString::valueOf( static_cast<const PDFWriter::RadioButtonWidget&>(i_rControl).RadioGroup );
+ }
+ else
+ aPartialName = OString( "Widget" );
+ }
+
+ if( ! m_aContext.AllowDuplicateFieldNames )
+ {
+ std::hash_map<OString, sal_Int32, OStringHash>::iterator it = m_aFieldNameMap.find( aFullName );
+
+ if( it != m_aFieldNameMap.end() ) // not unique
+ {
+ std::hash_map< OString, sal_Int32, OStringHash >::const_iterator check_it;
+ OString aTry;
+ sal_Int32 nTry = 2;
+ do
+ {
+ OStringBuffer aUnique( aFullName.getLength() + 16 );
+ aUnique.append( aFullName );
+ aUnique.append( '_' );
+ aUnique.append( nTry++ );
+ aTry = aUnique.makeStringAndClear();
+ check_it = m_aFieldNameMap.find( aTry );
+ } while( check_it != m_aFieldNameMap.end() );
+ aFullName = aTry;
+ m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
+ aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
+ }
+ else
+ m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
+ }
+
+ // finally
+ m_aWidgets[i_nWidgetIndex].m_aName = aPartialName;
+}
+
+static void appendFixedInt( sal_Int32 nValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = nLog10Divisor )
+{
+ if( nValue < 0 )
+ {
+ rBuffer.append( '-' );
+ nValue = -nValue;
+ }
+ sal_Int32 nFactor = 1, nDiv = nPrecision;
+ while( nDiv-- )
+ nFactor *= 10;
+
+ sal_Int32 nInt = nValue / nFactor;
+ rBuffer.append( nInt );
+ if( nFactor > 1 )
+ {
+ sal_Int32 nDecimal = nValue % nFactor;
+ if( nDecimal )
+ {
+ rBuffer.append( '.' );
+ // omit trailing zeros
+ while( (nDecimal % 10) == 0 )
+ nDecimal /= 10;
+ rBuffer.append( nDecimal );
+ }
+ }
+}
+
+
+// appends a double. PDF does not accept exponential format, only fixed point
+static void appendDouble( double fValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = 5 )
+{
+ bool bNeg = false;
+ if( fValue < 0.0 )
+ {
+ bNeg = true;
+ fValue=-fValue;
+ }
+
+ sal_Int64 nInt = (sal_Int64)fValue;
+ fValue -= (double)nInt;
+ // optimizing hardware may lead to a value of 1.0 after the subtraction
+ if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision )
+ {
+ nInt++;
+ fValue = 0.0;
+ }
+ sal_Int64 nFrac = 0;
+ if( fValue )
+ {
+ fValue *= pow( 10.0, (double)nPrecision );
+ nFrac = (sal_Int64)fValue;
+ }
+ if( bNeg && ( nInt || nFrac ) )
+ rBuffer.append( '-' );
+ rBuffer.append( nInt );
+ if( nFrac )
+ {
+ int i;
+ rBuffer.append( '.' );
+ sal_Int64 nBound = (sal_Int64)(pow( 10.0, nPrecision - 1.0 )+0.5);
+ for ( i = 0; ( i < nPrecision ) && nFrac; i++ )
+ {
+ sal_Int64 nNumb = nFrac / nBound;
+ nFrac -= nNumb * nBound;
+ rBuffer.append( nNumb );
+ nBound /= 10;
+ }
+ }
+}
+
+
+static void appendColor( const Color& rColor, OStringBuffer& rBuffer )
+{
+
+ if( rColor != Color( COL_TRANSPARENT ) )
+ {
+ appendDouble( (double)rColor.GetRed() / 255.0, rBuffer );
+ rBuffer.append( ' ' );
+ appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer );
+ rBuffer.append( ' ' );
+ appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer );
+ }
+}
+
+static void appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
+{
+ if( rColor != Color( COL_TRANSPARENT ) )
+ {
+ appendColor( rColor, rBuffer );
+ rBuffer.append( " RG" );
+ }
+}
+
+static void appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
+{
+ if( rColor != Color( COL_TRANSPARENT ) )
+ {
+ appendColor( rColor, rBuffer );
+ rBuffer.append( " rg" );
+ }
+}
+
+// matrix helper class
+// TODO: use basegfx matrix class instead or derive from it
+namespace vcl // TODO: use anonymous namespace to keep this class local
+{
+/* for sparse matrices of the form (2D linear transformations)
+ * f[0] f[1] 0
+ * f[2] f[3] 0
+ * f[4] f[5] 1
+ */
+class Matrix3
+{
+ double f[6];
+
+ void set( double *pn ) { for( int i = 0 ; i < 6; i++ ) f[i] = pn[i]; }
+public:
+ Matrix3();
+ ~Matrix3() {}
+
+ void skew( double alpha, double beta );
+ void scale( double sx, double sy );
+ void rotate( double angle );
+ void translate( double tx, double ty );
+ bool invert();
+
+ void append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack = NULL );
+
+ Point transform( const Point& rPoint ) const;
+};
+}
+
+Matrix3::Matrix3()
+{
+ // initialize to unity
+ f[0] = 1.0;
+ f[1] = 0.0;
+ f[2] = 0.0;
+ f[3] = 1.0;
+ f[4] = 0.0;
+ f[5] = 0.0;
+}
+
+Point Matrix3::transform( const Point& rOrig ) const
+{
+ double x = (double)rOrig.X(), y = (double)rOrig.Y();
+ return Point( (int)(x*f[0] + y*f[2] + f[4]), (int)(x*f[1] + y*f[3] + f[5]) );
+}
+
+void Matrix3::skew( double alpha, double beta )
+{
+ double fn[6];
+ double tb = tan( beta );
+ fn[0] = f[0] + f[2]*tb;
+ fn[1] = f[1];
+ fn[2] = f[2] + f[3]*tb;
+ fn[3] = f[3];
+ fn[4] = f[4] + f[5]*tb;
+ fn[5] = f[5];
+ if( alpha != 0.0 )
+ {
+ double ta = tan( alpha );
+ fn[1] += f[0]*ta;
+ fn[3] += f[2]*ta;
+ fn[5] += f[4]*ta;
+ }
+ set( fn );
+}
+
+void Matrix3::scale( double sx, double sy )
+{
+ double fn[6];
+ fn[0] = sx*f[0];
+ fn[1] = sy*f[1];
+ fn[2] = sx*f[2];
+ fn[3] = sy*f[3];
+ fn[4] = sx*f[4];
+ fn[5] = sy*f[5];
+ set( fn );
+}
+
+void Matrix3::rotate( double angle )
+{
+ double fn[6];
+ double fSin = sin(angle);
+ double fCos = cos(angle);
+ fn[0] = f[0]*fCos - f[1]*fSin;
+ fn[1] = f[0]*fSin + f[1]*fCos;
+ fn[2] = f[2]*fCos - f[3]*fSin;
+ fn[3] = f[2]*fSin + f[3]*fCos;
+ fn[4] = f[4]*fCos - f[5]*fSin;
+ fn[5] = f[4]*fSin + f[5]*fCos;
+ set( fn );
+}
+
+void Matrix3::translate( double tx, double ty )
+{
+ f[4] += tx;
+ f[5] += ty;
+}
+
+bool Matrix3::invert()
+{
+ // short circuit trivial cases
+ if( f[1]==f[2] && f[1]==0.0 && f[0]==f[3] && f[0]==1.0 )
+ {
+ f[4] = -f[4];
+ f[5] = -f[5];
+ return true;
+ }
+
+ // check determinant
+ const double fDet = f[0]*f[3]-f[1]*f[2];
+ if( fDet == 0.0 )
+ return false;
+
+ // invert the matrix
+ double fn[6];
+ fn[0] = +f[3] / fDet;
+ fn[1] = -f[1] / fDet;
+ fn[2] = -f[2] / fDet;
+ fn[3] = +f[0] / fDet;
+
+ // apply inversion to translation
+ fn[4] = -(f[4]*fn[0] + f[5]*fn[2]);
+ fn[5] = -(f[4]*fn[1] + f[5]*fn[3]);
+
+ set( fn );
+ return true;
+}
+
+void Matrix3::append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack )
+{
+ appendDouble( f[0], rBuffer );
+ rBuffer.append( ' ' );
+ appendDouble( f[1], rBuffer );
+ rBuffer.append( ' ' );
+ appendDouble( f[2], rBuffer );
+ rBuffer.append( ' ' );
+ appendDouble( f[3], rBuffer );
+ rBuffer.append( ' ' );
+ rPage.appendPoint( Point( (long)f[4], (long)f[5] ), rBuffer, false, pBack );
+}
+
+static void appendResourceMap( OStringBuffer& rBuf, const char* pPrefix, const PDFWriterImpl::ResourceMap& rList )
+{
+ if( rList.empty() )
+ return;
+ rBuf.append( '/' );
+ rBuf.append( pPrefix );
+ rBuf.append( "<<" );
+ int ni = 0;
+ for( PDFWriterImpl::ResourceMap::const_iterator it = rList.begin(); it != rList.end(); ++it )
+ {
+ if( it->first.getLength() && it->second > 0 )
+ {
+ rBuf.append( '/' );
+ rBuf.append( it->first );
+ rBuf.append( ' ' );
+ rBuf.append( it->second );
+ rBuf.append( " 0 R" );
+ if( ((++ni) & 7) == 0 )
+ rBuf.append( '\n' );
+ }
+ }
+ rBuf.append( ">>\n" );
+}
+
+void PDFWriterImpl::ResourceDict::append( OStringBuffer& rBuf, sal_Int32 nFontDictObject )
+{
+ rBuf.append( "<</Font " );
+ rBuf.append( nFontDictObject );
+ rBuf.append( " 0 R\n" );
+ appendResourceMap( rBuf, "XObject", m_aXObjects );
+ appendResourceMap( rBuf, "ExtGState", m_aExtGStates );
+ appendResourceMap( rBuf, "Shading", m_aShadings );
+ appendResourceMap( rBuf, "Pattern", m_aPatterns );
+ rBuf.append( "/ProcSet[/PDF/Text" );
+ if( !m_aXObjects.empty() )
+ rBuf.append( "/ImageC/ImageI/ImageB" );
+ rBuf.append( "]\n>>\n" );
+};
+
+PDFWriterImpl::PDFPage::PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
+ :
+ m_pWriter( pWriter ),
+ m_nPageWidth( nPageWidth ),
+ m_nPageHeight( nPageHeight ),
+ m_eOrientation( eOrientation ),
+ m_nPageObject( 0 ), // invalid object number
+ m_nPageIndex( -1 ), // invalid index
+ m_nStreamLengthObject( 0 ),
+ m_nBeginStreamPos( 0 ),
+ m_eTransition( PDFWriter::Regular ),
+ m_nTransTime( 0 ),
+ m_nDuration( 0 ),
+ m_bHasWidgets( false )
+{
+ // object ref must be only ever updated in emit()
+ m_nPageObject = m_pWriter->createObject();
+}
+
+PDFWriterImpl::PDFPage::~PDFPage()
+{
+}
+
+void PDFWriterImpl::PDFPage::beginStream()
+{
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( "PDFWriterImpl::PDFPage::beginStream, +" );
+ m_pWriter->emitComment( aLine.getStr() );
+ }
+#endif
+ m_aStreamObjects.push_back(m_pWriter->createObject());
+ if( ! m_pWriter->updateObject( m_aStreamObjects.back() ) )
+ return;
+
+ m_nStreamLengthObject = m_pWriter->createObject();
+ // write content stream header
+ OStringBuffer aLine;
+ aLine.append( m_aStreamObjects.back() );
+ aLine.append( " 0 obj\n<</Length " );
+ aLine.append( m_nStreamLengthObject );
+ aLine.append( " 0 R" );
+#if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
+ aLine.append( "/Filter/FlateDecode" );
+#endif
+ aLine.append( ">>\nstream\n" );
+ if( ! m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ return;
+ if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &m_nBeginStreamPos ) )
+ {
+ osl_closeFile( m_pWriter->m_aFile );
+ m_pWriter->m_bOpen = false;
+ }
+#if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
+ m_pWriter->beginCompression();
+#endif
+ m_pWriter->checkAndEnableStreamEncryption( m_aStreamObjects.back() );
+}
+
+void PDFWriterImpl::PDFPage::endStream()
+{
+#if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
+ m_pWriter->endCompression();
+#endif
+ sal_uInt64 nEndStreamPos;
+ if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &nEndStreamPos ) )
+ {
+ osl_closeFile( m_pWriter->m_aFile );
+ m_pWriter->m_bOpen = false;
+ return;
+ }
+ m_pWriter->disableStreamEncryption();
+ if( ! m_pWriter->writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
+ return;
+ // emit stream length object
+ if( ! m_pWriter->updateObject( m_nStreamLengthObject ) )
+ return;
+ OStringBuffer aLine;
+ aLine.append( m_nStreamLengthObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( (sal_Int64)(nEndStreamPos-m_nBeginStreamPos) );
+ aLine.append( "\nendobj\n\n" );
+ m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+bool PDFWriterImpl::PDFPage::emit(sal_Int32 nParentObject )
+{
+ // emit page object
+ if( ! m_pWriter->updateObject( m_nPageObject ) )
+ return false;
+ OStringBuffer aLine;
+
+ aLine.append( m_nPageObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/Page/Parent " );
+ aLine.append( nParentObject );
+ aLine.append( " 0 R" );
+ aLine.append( "/Resources " );
+ aLine.append( m_pWriter->getResourceDictObj() );
+ aLine.append( " 0 R" );
+ if( m_nPageWidth && m_nPageHeight )
+ {
+ aLine.append( "/MediaBox[0 0 " );
+ aLine.append( m_nPageWidth );
+ aLine.append( ' ' );
+ aLine.append( m_nPageHeight );
+ aLine.append( "]" );
+ }
+ switch( m_eOrientation )
+ {
+ case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
+ case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break;
+ case PDFWriter::Portrait: aLine.append( "/Rotate 0\n" );break;
+
+ case PDFWriter::Inherit:
+ default:
+ break;
+ }
+ int nAnnots = m_aAnnotations.size();
+ if( nAnnots > 0 )
+ {
+ aLine.append( "/Annots[\n" );
+ for( int i = 0; i < nAnnots; i++ )
+ {
+ aLine.append( m_aAnnotations[i] );
+ aLine.append( " 0 R" );
+ aLine.append( ((i+1)%15) ? " " : "\n" );
+ }
+ aLine.append( "]\n" );
+ }
+ #if 0
+ // FIXME: implement tab order as Structure Tree
+ if( m_bHasWidgets && m_pWriter->getVersion() >= PDFWriter::PDF_1_5 )
+ aLine.append( " /Tabs /S\n" );
+ #endif
+ if( m_aMCIDParents.size() > 0 )
+ {
+ OStringBuffer aStructParents( 1024 );
+ aStructParents.append( "[ " );
+ int nParents = m_aMCIDParents.size();
+ for( int i = 0; i < nParents; i++ )
+ {
+ aStructParents.append( m_aMCIDParents[i] );
+ aStructParents.append( " 0 R" );
+ aStructParents.append( ((i%10) == 9) ? "\n" : " " );
+ }
+ aStructParents.append( "]" );
+ m_pWriter->m_aStructParentTree.push_back( aStructParents.makeStringAndClear() );
+
+ aLine.append( "/StructParents " );
+ aLine.append( sal_Int32(m_pWriter->m_aStructParentTree.size()-1) );
+ aLine.append( "\n" );
+ }
+ if( m_nDuration > 0 )
+ {
+ aLine.append( "/Dur " );
+ aLine.append( (sal_Int32)m_nDuration );
+ aLine.append( "\n" );
+ }
+ if( m_eTransition != PDFWriter::Regular && m_nTransTime > 0 )
+ {
+ // transition duration
+ aLine.append( "/Trans<</D " );
+ appendDouble( (double)m_nTransTime/1000.0, aLine, 3 );
+ aLine.append( "\n" );
+ const char *pStyle = NULL, *pDm = NULL, *pM = NULL, *pDi = NULL;
+ switch( m_eTransition )
+ {
+ case PDFWriter::SplitHorizontalInward:
+ pStyle = "Split"; pDm = "H"; pM = "I"; break;
+ case PDFWriter::SplitHorizontalOutward:
+ pStyle = "Split"; pDm = "H"; pM = "O"; break;
+ case PDFWriter::SplitVerticalInward:
+ pStyle = "Split"; pDm = "V"; pM = "I"; break;
+ case PDFWriter::SplitVerticalOutward:
+ pStyle = "Split"; pDm = "V"; pM = "O"; break;
+ case PDFWriter::BlindsHorizontal:
+ pStyle = "Blinds"; pDm = "H"; break;
+ case PDFWriter::BlindsVertical:
+ pStyle = "Blinds"; pDm = "V"; break;
+ case PDFWriter::BoxInward:
+ pStyle = "Box"; pM = "I"; break;
+ case PDFWriter::BoxOutward:
+ pStyle = "Box"; pM = "O"; break;
+ case PDFWriter::WipeLeftToRight:
+ pStyle = "Wipe"; pDi = "0"; break;
+ case PDFWriter::WipeBottomToTop:
+ pStyle = "Wipe"; pDi = "90"; break;
+ case PDFWriter::WipeRightToLeft:
+ pStyle = "Wipe"; pDi = "180"; break;
+ case PDFWriter::WipeTopToBottom:
+ pStyle = "Wipe"; pDi = "270"; break;
+ case PDFWriter::Dissolve:
+ pStyle = "Dissolve"; break;
+ case PDFWriter::GlitterLeftToRight:
+ pStyle = "Glitter"; pDi = "0"; break;
+ case PDFWriter::GlitterTopToBottom:
+ pStyle = "Glitter"; pDi = "270"; break;
+ case PDFWriter::GlitterTopLeftToBottomRight:
+ pStyle = "Glitter"; pDi = "315"; break;
+ case PDFWriter::Regular:
+ break;
+ }
+ // transition style
+ if( pStyle )
+ {
+ aLine.append( "/S/" );
+ aLine.append( pStyle );
+ aLine.append( "\n" );
+ }
+ if( pDm )
+ {
+ aLine.append( "/Dm/" );
+ aLine.append( pDm );
+ aLine.append( "\n" );
+ }
+ if( pM )
+ {
+ aLine.append( "/M/" );
+ aLine.append( pM );
+ aLine.append( "\n" );
+ }
+ if( pDi )
+ {
+ aLine.append( "/Di " );
+ aLine.append( pDi );
+ aLine.append( "\n" );
+ }
+ aLine.append( ">>\n" );
+ }
+ if( m_pWriter->getVersion() > PDFWriter::PDF_1_3 && ! m_pWriter->m_bIsPDF_A1 )
+ {
+ aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/I true>>" );
+ }
+ aLine.append( "/Contents" );
+ unsigned int nStreamObjects = m_aStreamObjects.size();
+ if( nStreamObjects > 1 )
+ aLine.append( '[' );
+ for( unsigned int i = 0; i < m_aStreamObjects.size(); i++ )
+ {
+ aLine.append( ' ' );
+ aLine.append( m_aStreamObjects[i] );
+ aLine.append( " 0 R" );
+ }
+ if( nStreamObjects > 1 )
+ aLine.append( ']' );
+ aLine.append( ">>\nendobj\n\n" );
+ return m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+namespace vcl
+{
+template < class GEOMETRY >
+GEOMETRY lcl_convert( const MapMode& _rSource, const MapMode& _rDest, OutputDevice* _pPixelConversion, const GEOMETRY& _rObject )
+{
+ GEOMETRY aPoint;
+ if ( MAP_PIXEL == _rSource.GetMapUnit() )
+ {
+ aPoint = _pPixelConversion->PixelToLogic( _rObject, _rDest );
+ }
+ else
+ {
+ aPoint = OutputDevice::LogicToLogic( _rObject, _rSource, _rDest );
+ }
+ return aPoint;
+}
+}
+
+void PDFWriterImpl::PDFPage::appendPoint( const Point& rPoint, OStringBuffer& rBuffer, bool bNeg, Point* pOutPoint ) const
+{
+ if( pOutPoint )
+ {
+ Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode,
+ m_pWriter->getReferenceDevice(),
+ rPoint ) );
+ *pOutPoint = aPoint;
+ }
+
+ Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode,
+ m_pWriter->getReferenceDevice(),
+ rPoint ) );
+
+ sal_Int32 nValue = aPoint.X();
+ if( bNeg )
+ nValue = -nValue;
+
+ appendFixedInt( nValue, rBuffer );
+
+ rBuffer.append( ' ' );
+
+ nValue = pointToPixel(getHeight()) - aPoint.Y();
+ if( bNeg )
+ nValue = -nValue;
+
+ appendFixedInt( nValue, rBuffer );
+}
+
+void PDFWriterImpl::PDFPage::appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const
+{
+ double fValue = pixelToPoint(rPoint.getX());
+
+ appendDouble( fValue, rBuffer, nLog10Divisor );
+
+ rBuffer.append( ' ' );
+
+ fValue = double(getHeight()) - pixelToPoint(rPoint.getY());
+
+ appendDouble( fValue, rBuffer, nLog10Divisor );
+}
+
+void PDFWriterImpl::PDFPage::appendRect( const Rectangle& rRect, OStringBuffer& rBuffer ) const
+{
+ appendPoint( rRect.BottomLeft() + Point( 0, 1 ), rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( (sal_Int32)rRect.GetWidth(), rBuffer, false );
+ rBuffer.append( ' ' );
+ appendMappedLength( (sal_Int32)rRect.GetHeight(), rBuffer, true );
+ rBuffer.append( " re" );
+}
+
+void PDFWriterImpl::PDFPage::convertRect( Rectangle& rRect ) const
+{
+ Point aLL = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode,
+ m_pWriter->getReferenceDevice(),
+ rRect.BottomLeft() + Point( 0, 1 )
+ );
+ Size aSize = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode,
+ m_pWriter->getReferenceDevice(),
+ rRect.GetSize() );
+ rRect.Left() = aLL.X();
+ rRect.Right() = aLL.X() + aSize.Width();
+ rRect.Top() = pointToPixel(getHeight()) - aLL.Y();
+ rRect.Bottom() = rRect.Top() + aSize.Height();
+}
+
+void PDFWriterImpl::PDFPage::appendPolygon( const Polygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
+{
+ USHORT nPoints = rPoly.GetSize();
+ /*
+ * #108582# applications do weird things
+ */
+ sal_uInt32 nBufLen = rBuffer.getLength();
+ if( nPoints > 0 )
+ {
+ const BYTE* pFlagArray = rPoly.GetConstFlagAry();
+ appendPoint( rPoly[0], rBuffer );
+ rBuffer.append( " m\n" );
+ for( USHORT i = 1; i < nPoints; i++ )
+ {
+ if( pFlagArray && pFlagArray[i] == POLY_CONTROL && nPoints-i > 2 )
+ {
+ // bezier
+ DBG_ASSERT( pFlagArray[i+1] == POLY_CONTROL && pFlagArray[i+2] != POLY_CONTROL, "unexpected sequence of control points" );
+ appendPoint( rPoly[i], rBuffer );
+ rBuffer.append( " " );
+ appendPoint( rPoly[i+1], rBuffer );
+ rBuffer.append( " " );
+ appendPoint( rPoly[i+2], rBuffer );
+ rBuffer.append( " c" );
+ i += 2; // add additionally consumed points
+ }
+ else
+ {
+ // line
+ appendPoint( rPoly[i], rBuffer );
+ rBuffer.append( " l" );
+ }
+ if( (rBuffer.getLength() - nBufLen) > 65 )
+ {
+ rBuffer.append( "\n" );
+ nBufLen = rBuffer.getLength();
+ }
+ else
+ rBuffer.append( " " );
+ }
+ if( bClose )
+ rBuffer.append( "h\n" );
+ }
+}
+
+void PDFWriterImpl::PDFPage::appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
+{
+ basegfx::B2DPolygon aPoly( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode,
+ m_pWriter->getReferenceDevice(),
+ rPoly ) );
+
+ if( basegfx::tools::isRectangle( aPoly ) )
+ {
+ basegfx::B2DRange aRange( aPoly.getB2DRange() );
+ basegfx::B2DPoint aBL( aRange.getMinX(), aRange.getMaxY() );
+ appendPixelPoint( aBL, rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( aRange.getWidth(), rBuffer, false, NULL, nLog10Divisor );
+ rBuffer.append( ' ' );
+ appendMappedLength( aRange.getHeight(), rBuffer, true, NULL, nLog10Divisor );
+ rBuffer.append( " re\n" );
+ return;
+ }
+ sal_uInt32 nPoints = aPoly.count();
+ if( nPoints > 0 )
+ {
+ sal_uInt32 nBufLen = rBuffer.getLength();
+ basegfx::B2DPoint aLastPoint( aPoly.getB2DPoint( 0 ) );
+ appendPixelPoint( aLastPoint, rBuffer );
+ rBuffer.append( " m\n" );
+ for( sal_uInt32 i = 1; i <= nPoints; i++ )
+ {
+ if( i != nPoints || aPoly.isClosed() )
+ {
+ sal_uInt32 nCurPoint = i % nPoints;
+ sal_uInt32 nLastPoint = i-1;
+ basegfx::B2DPoint aPoint( aPoly.getB2DPoint( nCurPoint ) );
+ if( aPoly.isNextControlPointUsed( nLastPoint ) &&
+ aPoly.isPrevControlPointUsed( nCurPoint ) )
+ {
+ appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
+ rBuffer.append( ' ' );
+ appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
+ rBuffer.append( ' ' );
+ appendPixelPoint( aPoint, rBuffer );
+ rBuffer.append( " c" );
+ }
+ else if( aPoly.isNextControlPointUsed( nLastPoint ) )
+ {
+ appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
+ rBuffer.append( ' ' );
+ appendPixelPoint( aPoint, rBuffer );
+ rBuffer.append( " y" );
+ }
+ else if( aPoly.isPrevControlPointUsed( nCurPoint ) )
+ {
+ appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
+ rBuffer.append( ' ' );
+ appendPixelPoint( aPoint, rBuffer );
+ rBuffer.append( " v" );
+ }
+ else
+ {
+ appendPixelPoint( aPoint, rBuffer );
+ rBuffer.append( " l" );
+ }
+ if( (rBuffer.getLength() - nBufLen) > 65 )
+ {
+ rBuffer.append( "\n" );
+ nBufLen = rBuffer.getLength();
+ }
+ else
+ rBuffer.append( " " );
+ }
+ }
+ if( bClose )
+ rBuffer.append( "h\n" );
+ }
+}
+
+void PDFWriterImpl::PDFPage::appendPolyPolygon( const PolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
+{
+ USHORT nPolygons = rPolyPoly.Count();
+ for( USHORT n = 0; n < nPolygons; n++ )
+ appendPolygon( rPolyPoly[n], rBuffer, bClose );
+}
+
+void PDFWriterImpl::PDFPage::appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
+{
+ sal_uInt32 nPolygons = rPolyPoly.count();
+ for( sal_uInt32 n = 0; n < nPolygons; n++ )
+ appendPolygon( rPolyPoly.getB2DPolygon( n ), rBuffer, bClose );
+}
+
+void PDFWriterImpl::PDFPage::appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength ) const
+{
+ sal_Int32 nValue = nLength;
+ if ( nLength < 0 )
+ {
+ rBuffer.append( '-' );
+ nValue = -nLength;
+ }
+ Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode,
+ m_pWriter->getReferenceDevice(),
+ Size( nValue, nValue ) ) );
+ nValue = bVertical ? aSize.Height() : aSize.Width();
+ if( pOutLength )
+ *pOutLength = ((nLength < 0 ) ? -nValue : nValue);
+
+ appendFixedInt( nValue, rBuffer, 1 );
+}
+
+void PDFWriterImpl::PDFPage::appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength, sal_Int32 nPrecision ) const
+{
+ Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode,
+ m_pWriter->getReferenceDevice(),
+ Size( 1000, 1000 ) ) );
+ if( pOutLength )
+ *pOutLength = (sal_Int32)(fLength*(double)(bVertical ? aSize.Height() : aSize.Width())/1000.0);
+ fLength *= pixelToPoint((double)(bVertical ? aSize.Height() : aSize.Width()) / 1000.0);
+ appendDouble( fLength, rBuffer, nPrecision );
+}
+
+bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const
+{
+ bool bRet = true;
+ if( rInfo.GetStyle() == LINE_DASH )
+ {
+ rBuffer.append( "[ " );
+ if( rInfo.GetDashLen() == rInfo.GetDotLen() ) // degraded case
+ {
+ appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
+ rBuffer.append( ' ' );
+ }
+ else
+ {
+ // check for implementation limits of dash array
+ // in PDF reader apps (e.g. acroread)
+ if( 2*(rInfo.GetDashCount() + rInfo.GetDotCount()) > 10 )
+ bRet = false;
+ for( int n = 0; n < rInfo.GetDashCount(); n++ )
+ {
+ appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
+ rBuffer.append( ' ' );
+ }
+ for( int m = 0; m < rInfo.GetDotCount(); m++ )
+ {
+ appendMappedLength( (sal_Int32)rInfo.GetDotLen(), rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
+ rBuffer.append( ' ' );
+ }
+ }
+ rBuffer.append( "] 0 d\n" );
+ }
+ if( rInfo.GetWidth() > 1 )
+ {
+ appendMappedLength( (sal_Int32)rInfo.GetWidth(), rBuffer );
+ rBuffer.append( " w\n" );
+ }
+ else if( rInfo.GetWidth() == 0 )
+ {
+ // "pixel" line
+ appendDouble( 72.0/double(m_pWriter->getReferenceDevice()->ImplGetDPIX()), rBuffer );
+ rBuffer.append( " w\n" );
+ }
+ return bRet;
+}
+
+void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal_Int32 nDelta, OStringBuffer& rBuffer ) const
+{
+ if( nWidth <= 0 )
+ return;
+ if( nDelta < 1 )
+ nDelta = 1;
+
+ rBuffer.append( "0 " );
+ appendMappedLength( nY, rBuffer, true );
+ rBuffer.append( " m\n" );
+ for( sal_Int32 n = 0; n < nWidth; )
+ {
+ n += nDelta;
+ appendMappedLength( n, rBuffer, false );
+ rBuffer.append( ' ' );
+ appendMappedLength( nDelta+nY, rBuffer, true );
+ rBuffer.append( ' ' );
+ n += nDelta;
+ appendMappedLength( n, rBuffer, false );
+ rBuffer.append( ' ' );
+ appendMappedLength( nY, rBuffer, true );
+ rBuffer.append( " v " );
+ if( n < nWidth )
+ {
+ n += nDelta;
+ appendMappedLength( n, rBuffer, false );
+ rBuffer.append( ' ' );
+ appendMappedLength( nY-nDelta, rBuffer, true );
+ rBuffer.append( ' ' );
+ n += nDelta;
+ appendMappedLength( n, rBuffer, false );
+ rBuffer.append( ' ' );
+ appendMappedLength( nY, rBuffer, true );
+ rBuffer.append( " v\n" );
+ }
+ }
+ rBuffer.append( "S\n" );
+}
+
+/*
+ * class PDFWriterImpl
+ */
+
+PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext )
+ :
+ m_pReferenceDevice( NULL ),
+ m_aMapMode( MAP_POINT, Point(), Fraction( 1L, pointToPixel(1) ), Fraction( 1L, pointToPixel(1) ) ),
+ m_nCurrentStructElement( 0 ),
+ m_bEmitStructure( true ),
+ m_bNewMCID( false ),
+ m_nCurrentControl( -1 ),
+ m_bEmbedStandardFonts( false ),
+ m_nNextFID( 1 ),
+ m_nInheritedPageWidth( 595 ), // default A4
+ m_nInheritedPageHeight( 842 ), // default A4
+ m_eInheritedOrientation( PDFWriter::Portrait ),
+ m_nCurrentPage( -1 ),
+ m_nResourceDict( -1 ),
+ m_nFontDictObject( -1 ),
+ m_pCodec( NULL ),
+ m_aDocDigest( rtl_digest_createMD5() ),
+ m_aCipher( (rtlCipher)NULL ),
+ m_aDigest( NULL ),
+ m_bEncryptThisStream( false ),
+ m_aDocID( 32 ),
+ m_aCreationDateString( 64 ),
+ m_aCreationMetaDateString( 64 ),
+ m_pEncryptionBuffer( NULL ),
+ m_nEncryptionBufferSize( 0 ),
+ m_bIsPDF_A1( false )
+{
+#ifdef DO_TEST_PDF
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ doTestCode();
+ }
+#endif
+ m_aContext = rContext;
+ m_aStructure.push_back( PDFStructureElement() );
+ m_aStructure[0].m_nOwnElement = 0;
+ m_aStructure[0].m_nParentElement = 0;
+
+ Font aFont;
+ aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
+ aFont.SetSize( Size( 0, 12 ) );
+
+ GraphicsState aState;
+ aState.m_aMapMode = m_aMapMode;
+ aState.m_aFont = aFont;
+ m_aGraphicsStack.push_front( aState );
+
+ oslFileError aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
+ if( aError != osl_File_E_None )
+ {
+ if( aError == osl_File_E_EXIST )
+ {
+ aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write );
+ if( aError == osl_File_E_None )
+ aError = osl_setFileSize( m_aFile, 0 );
+ }
+ }
+ if( aError != osl_File_E_None )
+ return;
+
+ m_bOpen = true;
+
+/* prepare the cypher engine, can be done in CTOR, free in DTOR */
+
+ m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
+ m_aDigest = rtl_digest_createMD5();
+
+/* the size of the Codec default maximum */
+ checkEncryptionBufferSize( 0x4000 );
+
+ // write header
+ OStringBuffer aBuffer( 20 );
+ aBuffer.append( "%PDF-" );
+ switch( m_aContext.Version )
+ {
+ case PDFWriter::PDF_1_2: aBuffer.append( "1.2" );break;
+ case PDFWriter::PDF_1_3: aBuffer.append( "1.3" );break;
+ case PDFWriter::PDF_A_1:
+ default:
+ case PDFWriter::PDF_1_4: aBuffer.append( "1.4" );break;
+ case PDFWriter::PDF_1_5: aBuffer.append( "1.5" );break;
+ }
+ // append something binary as comment (suggested in PDF Reference)
+ aBuffer.append( "\n%äüöß\n" );
+ if( !writeBuffer( aBuffer.getStr(), aBuffer.getLength() ) )
+ {
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+ return;
+ }
+
+ // insert outline root
+ m_aOutline.push_back( PDFOutlineEntry() );
+
+ m_bIsPDF_A1 = (m_aContext.Version == PDFWriter::PDF_A_1);
+ if( m_bIsPDF_A1 )
+ m_aContext.Version = PDFWriter::PDF_1_4; //meaning we need PDF 1.4, PDF/A flavour
+
+ m_bEmbedStandardFonts = m_aContext.EmbedStandardFonts;
+}
+
+PDFWriterImpl::~PDFWriterImpl()
+{
+ if( m_aDocDigest )
+ rtl_digest_destroyMD5( m_aDocDigest );
+ delete static_cast<VirtualDevice*>(m_pReferenceDevice);
+
+ if( m_aCipher )
+ rtl_cipher_destroyARCFOUR( m_aCipher );
+ if( m_aDigest )
+ rtl_digest_destroyMD5( m_aDigest );
+
+ rtl_freeMemory( m_pEncryptionBuffer );
+}
+
+void PDFWriterImpl::setDocInfo( const PDFDocInfo& rInfo )
+{
+ m_aDocInfo.Title = rInfo.Title;
+ m_aDocInfo.Author = rInfo.Author;
+ m_aDocInfo.Subject = rInfo.Subject;
+ m_aDocInfo.Keywords = rInfo.Keywords;
+ m_aDocInfo.Creator = rInfo.Creator;
+ m_aDocInfo.Producer = rInfo.Producer;
+
+//build the document id
+ rtl::OString aInfoValuesOut;
+ OStringBuffer aID( 1024 );
+ if( m_aDocInfo.Title.Len() )
+ appendUnicodeTextString( m_aDocInfo.Title, aID );
+ if( m_aDocInfo.Author.Len() )
+ appendUnicodeTextString( m_aDocInfo.Author, aID );
+ if( m_aDocInfo.Subject.Len() )
+ appendUnicodeTextString( m_aDocInfo.Subject, aID );
+ if( m_aDocInfo.Keywords.Len() )
+ appendUnicodeTextString( m_aDocInfo.Keywords, aID );
+ if( m_aDocInfo.Creator.Len() )
+ appendUnicodeTextString( m_aDocInfo.Creator, aID );
+ if( m_aDocInfo.Producer.Len() )
+ appendUnicodeTextString( m_aDocInfo.Producer, aID );
+
+ TimeValue aTVal, aGMT;
+ oslDateTime aDT;
+ osl_getSystemTime( &aGMT );
+ osl_getLocalTimeFromSystemTime( &aGMT, &aTVal );
+ osl_getDateTimeFromTimeValue( &aTVal, &aDT );
+ m_aCreationDateString.append( "D:" );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
+//--> i59651, we fill the Metadata date string as well, if PDF/A is requested
+ if( m_bIsPDF_A1 )
+ {
+// according to ISO 19005-1:2005 6.7.3 the date is corrected for
+// local time zone offset UTC only, whereas Acrobat 8 seems
+// to use the localtime notation only
+// according to a raccomandation in XMP Specification (Jan 2004, page 75)
+// the Acrobat way seems the right approach
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
+ m_aCreationMetaDateString.append( "-" );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
+ m_aCreationMetaDateString.append( "-" );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
+ m_aCreationMetaDateString.append( "T" );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
+ m_aCreationMetaDateString.append( ":" );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
+ m_aCreationMetaDateString.append( ":" );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
+ }
+ sal_uInt32 nDelta = 0;
+ if( aGMT.Seconds > aTVal.Seconds )
+ {
+ m_aCreationDateString.append( "-" );
+ nDelta = aGMT.Seconds-aTVal.Seconds;
+ if( m_bIsPDF_A1 )
+ m_aCreationMetaDateString.append( "-" );
+ }
+ else if( aGMT.Seconds < aTVal.Seconds )
+ {
+ m_aCreationDateString.append( "+" );
+ nDelta = aTVal.Seconds-aGMT.Seconds;
+ if( m_bIsPDF_A1 )
+ m_aCreationMetaDateString.append( "+" );
+ }
+ else
+ {
+ m_aCreationDateString.append( "Z" );
+ if( m_bIsPDF_A1 )
+ m_aCreationMetaDateString.append( "Z" );
+
+ }
+ if( nDelta )
+ {
+ m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
+ m_aCreationDateString.append( "'" );
+ m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
+ m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
+ if( m_bIsPDF_A1 )
+ {
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
+ m_aCreationMetaDateString.append( ":" );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
+ m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
+ }
+ }
+ m_aCreationDateString.append( "'" );
+ aID.append( m_aCreationDateString.getStr(), m_aCreationDateString.getLength() );
+
+ aInfoValuesOut = aID.makeStringAndClear();
+
+ DBG_ASSERT( m_aDigest != NULL, "PDFWrite_Impl::setDocInfo: cannot obtain a digest object !" );
+
+ m_aDocID.setLength( 0 );
+ if( m_aDigest )
+ {
+ osl_getSystemTime( &aGMT );
+ rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, &aGMT, sizeof( aGMT ) );
+ if( nError == rtl_Digest_E_None )
+ nError = rtl_digest_updateMD5( m_aDigest, m_aContext.URL.getStr(), m_aContext.URL.getLength()*sizeof(sal_Unicode) );
+ if( nError == rtl_Digest_E_None )
+ nError = rtl_digest_updateMD5( m_aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() );
+ if( nError == rtl_Digest_E_None )
+ {
+//the binary form of the doc id is needed for encryption stuff
+ rtl_digest_getMD5( m_aDigest, m_nDocID, 16 );
+ for( unsigned int i = 0; i < 16; i++ )
+ appendHex( m_nDocID[i], m_aDocID );
+ }
+ }
+}
+
+/* i12626 methods */
+/*
+check if the Unicode string must be encrypted or not, perform the requested task,
+append the string as unicode hex, encrypted if needed
+ */
+inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer )
+{
+ rOutBuffer.append( "<" );
+ if( m_aContext.Encrypt )
+ {
+ const sal_Unicode* pStr = rInString.getStr();
+ sal_Int32 nLen = rInString.getLength();
+//prepare a unicode string, encrypt it
+ if( checkEncryptionBufferSize( nLen*2 ) )
+ {
+ enableStringEncryption( nInObjectNumber );
+ register sal_uInt8 *pCopy = m_pEncryptionBuffer;
+ sal_Int32 nChars = 2;
+ *pCopy++ = 0xFE;
+ *pCopy++ = 0xFF;
+// we need to prepare a byte stream from the unicode string buffer
+ for( register int i = 0; i < nLen; i++ )
+ {
+ register sal_Unicode aUnChar = pStr[i];
+ *pCopy++ = (sal_uInt8)( aUnChar >> 8 );
+ *pCopy++ = (sal_uInt8)( aUnChar & 255 );
+ nChars += 2;
+ }
+//encrypt in place
+ rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChars, m_pEncryptionBuffer, nChars );
+//now append, hexadecimal (appendHex), the encrypted result
+ for(register int i = 0; i < nChars; i++)
+ appendHex( m_pEncryptionBuffer[i], rOutBuffer );
+ }
+ }
+ else
+ appendUnicodeTextString( rInString, rOutBuffer );
+ rOutBuffer.append( ">" );
+}
+
+inline void PDFWriterImpl::appendLiteralStringEncrypt( rtl::OStringBuffer& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer )
+{
+ rOutBuffer.append( "(" );
+ sal_Int32 nChars = rInString.getLength();
+//check for encryption, if ok, encrypt the string, then convert with appndLiteralString
+ if( m_aContext.Encrypt && checkEncryptionBufferSize( nChars ) )
+ {
+//encrypt the string in a buffer, then append it
+ enableStringEncryption( nInObjectNumber );
+ rtl_cipher_encodeARCFOUR( m_aCipher, rInString.getStr(), nChars, m_pEncryptionBuffer, nChars );
+ appendLiteralString( (const sal_Char*)m_pEncryptionBuffer, nChars, rOutBuffer );
+ }
+ else
+ appendLiteralString( rInString.getStr(), nChars , rOutBuffer );
+ rOutBuffer.append( ")" );
+}
+
+inline void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer )
+{
+ rtl::OStringBuffer aBufferString( rInString );
+ appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
+}
+
+inline void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer )
+{
+ rtl::OString aBufferString( rtl::OUStringToOString( rInString, RTL_TEXTENCODING_ASCII_US ) );
+ appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
+}
+
+/* end i12626 methods */
+
+void PDFWriterImpl::emitComment( const char* pComment )
+{
+ OStringBuffer aLine( 64 );
+ aLine.append( "% " );
+ aLine.append( (const sal_Char*)pComment );
+ aLine.append( "\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+bool PDFWriterImpl::compressStream( SvMemoryStream* pStream )
+{
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ pStream->Seek( STREAM_SEEK_TO_END );
+ ULONG nEndPos = pStream->Tell();
+ pStream->Seek( STREAM_SEEK_TO_BEGIN );
+ ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 );
+ SvMemoryStream aStream;
+ pCodec->BeginCompression();
+ pCodec->Write( aStream, (const BYTE*)pStream->GetData(), nEndPos );
+ pCodec->EndCompression();
+ delete pCodec;
+ nEndPos = aStream.Tell();
+ pStream->Seek( STREAM_SEEK_TO_BEGIN );
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ pStream->SetStreamSize( nEndPos );
+ pStream->Write( aStream.GetData(), nEndPos );
+ return true;
+#else
+ (void)pStream;
+ return false;
+#endif
+}
+
+void PDFWriterImpl::beginCompression()
+{
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ m_pCodec = new ZCodec( 0x4000, 0x4000 );
+ m_pMemStream = new SvMemoryStream();
+ m_pCodec->BeginCompression();
+#endif
+}
+
+void PDFWriterImpl::endCompression()
+{
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ if( m_pCodec )
+ {
+ m_pCodec->EndCompression();
+ delete m_pCodec;
+ m_pCodec = NULL;
+ sal_uInt64 nLen = m_pMemStream->Tell();
+ m_pMemStream->Seek( 0 );
+ writeBuffer( m_pMemStream->GetData(), nLen );
+ delete m_pMemStream;
+ m_pMemStream = NULL;
+ }
+#endif
+}
+
+bool PDFWriterImpl::writeBuffer( const void* pBuffer, sal_uInt64 nBytes )
+{
+ if( ! m_bOpen ) // we are already down the drain
+ return false;
+
+ if( ! nBytes ) // huh ?
+ return true;
+
+ if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
+ {
+ m_aOutputStreams.front().m_pStream->Seek( STREAM_SEEK_TO_END );
+ m_aOutputStreams.front().m_pStream->Write( pBuffer, sal::static_int_cast<sal_Size>(nBytes) );
+ return true;
+ }
+
+ sal_uInt64 nWritten;
+ if( m_pCodec )
+ {
+ m_pCodec->Write( *m_pMemStream, static_cast<const BYTE*>(pBuffer), (ULONG)nBytes );
+ nWritten = nBytes;
+ }
+ else
+ {
+ sal_Bool buffOK = sal_True;
+ if( m_bEncryptThisStream )
+ {
+/* implement the encryption part of the PDF spec encryption algorithm 3.1 */
+ if( ( buffOK = checkEncryptionBufferSize( static_cast<sal_Int32>(nBytes) ) ) != sal_False )
+ rtl_cipher_encodeARCFOUR( m_aCipher,
+ (sal_uInt8*)pBuffer, static_cast<sal_Size>(nBytes),
+ m_pEncryptionBuffer, static_cast<sal_Size>(nBytes) );
+ }
+
+ const void* pWriteBuffer = ( m_bEncryptThisStream && buffOK ) ? m_pEncryptionBuffer : pBuffer;
+ if( m_aDocDigest )
+ rtl_digest_updateMD5( m_aDocDigest, pWriteBuffer, static_cast<sal_uInt32>(nBytes) );
+
+ if( osl_writeFile( m_aFile,
+ pWriteBuffer,
+ nBytes, &nWritten ) != osl_File_E_None )
+ nWritten = 0;
+
+ if( nWritten != nBytes )
+ {
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+ }
+ }
+
+ return nWritten == nBytes;
+}
+
+OutputDevice* PDFWriterImpl::getReferenceDevice()
+{
+ if( ! m_pReferenceDevice )
+ {
+ VirtualDevice* pVDev = new VirtualDevice( 0 );
+
+ m_pReferenceDevice = pVDev;
+
+ pVDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_PDF1 );
+
+ pVDev->SetOutputSizePixel( Size( 640, 480 ) );
+ pVDev->SetMapMode( MAP_MM );
+
+ m_pReferenceDevice->mpPDFWriter = this;
+ m_pReferenceDevice->ImplUpdateFontData( TRUE );
+ }
+ return m_pReferenceDevice;
+}
+
+class ImplPdfBuiltinFontData : public ImplFontData
+{
+private:
+ const PDFWriterImpl::BuiltinFont& mrBuiltin;
+
+public:
+ enum {PDF_FONT_MAGIC = 0xBDFF0A1C };
+ ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& );
+ const PDFWriterImpl::BuiltinFont* GetBuiltinFont() const { return &mrBuiltin; }
+
+ virtual ImplFontData* Clone() const { return new ImplPdfBuiltinFontData(*this); }
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ virtual sal_IntPtr GetFontId() const { return reinterpret_cast<sal_IntPtr>(&mrBuiltin); }
+};
+
+inline const ImplPdfBuiltinFontData* GetPdfFontData( const ImplFontData* pFontData )
+{
+ const ImplPdfBuiltinFontData* pFD = NULL;
+ if( pFontData && pFontData->CheckMagic( ImplPdfBuiltinFontData::PDF_FONT_MAGIC ) )
+ pFD = static_cast<const ImplPdfBuiltinFontData*>( pFontData );
+ return pFD;
+}
+
+static ImplDevFontAttributes GetDevFontAttributes( const PDFWriterImpl::BuiltinFont& rBuiltin )
+{
+ ImplDevFontAttributes aDFA;
+ aDFA.maName = String::CreateFromAscii( rBuiltin.m_pName );
+ aDFA.maStyleName = String::CreateFromAscii( rBuiltin.m_pStyleName );
+ aDFA.meFamily = rBuiltin.m_eFamily;
+ aDFA.mbSymbolFlag = (rBuiltin.m_eCharSet != RTL_TEXTENCODING_MS_1252 );
+ aDFA.mePitch = rBuiltin.m_ePitch;
+ aDFA.meWeight = rBuiltin.m_eWeight;
+ aDFA.meItalic = rBuiltin.m_eItalic;
+ aDFA.meWidthType = rBuiltin.m_eWidthType;
+
+ aDFA.mbOrientation = true;
+ aDFA.mbDevice = true;
+ aDFA.mnQuality = 50000;
+ aDFA.mbSubsettable = false;
+ aDFA.mbEmbeddable = false;
+ return aDFA;
+}
+
+ImplPdfBuiltinFontData::ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& rBuiltin )
+: ImplFontData( GetDevFontAttributes(rBuiltin), PDF_FONT_MAGIC ),
+ mrBuiltin( rBuiltin )
+{}
+
+ImplFontEntry* ImplPdfBuiltinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplFontEntry* pEntry = new ImplFontEntry( rFSD );
+ return pEntry;
+}
+
+ImplDevFontList* PDFWriterImpl::filterDevFontList( ImplDevFontList* pFontList )
+{
+ DBG_ASSERT( m_aSubsets.size() == 0, "Fonts changing during PDF generation, document will be invalid" );
+ ImplDevFontList* pFiltered = pFontList->Clone( true, true );
+
+ // append the PDF builtin fonts
+ if( !m_bIsPDF_A1 && !m_bEmbedStandardFonts)
+ for( unsigned int i = 0; i < sizeof(m_aBuiltinFonts)/sizeof(m_aBuiltinFonts[0]); i++ )
+ {
+ ImplFontData* pNewData = new ImplPdfBuiltinFontData( m_aBuiltinFonts[i] );
+ pFiltered->Add( pNewData );
+ }
+ return pFiltered;
+}
+
+bool PDFWriterImpl::isBuiltinFont( const ImplFontData* pFont ) const
+{
+ const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
+ return (pFD != NULL);
+}
+
+void PDFWriterImpl::getFontMetric( ImplFontSelectData* pSelect, ImplFontMetricData* pMetric ) const
+{
+ const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData );
+ if( !pFD )
+ return;
+ const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
+
+ pMetric->mnOrientation = sal::static_int_cast<short>(pSelect->mnOrientation);
+ pMetric->meFamily = pBuiltinFont->m_eFamily;
+ pMetric->mePitch = pBuiltinFont->m_ePitch;
+ pMetric->meWeight = pBuiltinFont->m_eWeight;
+ pMetric->meItalic = pBuiltinFont->m_eItalic;
+ pMetric->mbSymbolFlag = pFD->IsSymbolFont();
+ pMetric->mnWidth = pSelect->mnHeight;
+ pMetric->mnAscent = ( pSelect->mnHeight * +pBuiltinFont->m_nAscent + 500 ) / 1000;
+ pMetric->mnDescent = ( pSelect->mnHeight * -pBuiltinFont->m_nDescent + 500 ) / 1000;
+ pMetric->mnIntLeading = 0;
+ pMetric->mnExtLeading = 0;
+ pMetric->mnSlant = 0;
+ pMetric->mbScalableFont = true;
+ pMetric->mbDevice = true;
+}
+
+// -----------------------------------------------------------------------
+
+namespace vcl {
+
+class PDFSalLayout : public GenericSalLayout
+{
+ PDFWriterImpl& mrPDFWriterImpl;
+ const PDFWriterImpl::BuiltinFont& mrBuiltinFont;
+ bool mbIsSymbolFont;
+ long mnPixelPerEM;
+ String maOrigText;
+
+public:
+ PDFSalLayout( PDFWriterImpl&,
+ const PDFWriterImpl::BuiltinFont&,
+ long nPixelPerEM, int nOrientation );
+
+ void SetText( const String& rText ) { maOrigText = rText; }
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+};
+
+}
+
+// -----------------------------------------------------------------------
+
+PDFSalLayout::PDFSalLayout( PDFWriterImpl& rPDFWriterImpl,
+ const PDFWriterImpl::BuiltinFont& rBuiltinFont,
+ long nPixelPerEM, int nOrientation )
+: mrPDFWriterImpl( rPDFWriterImpl ),
+ mrBuiltinFont( rBuiltinFont ),
+ mnPixelPerEM( nPixelPerEM )
+{
+ mbIsSymbolFont = (rBuiltinFont.m_eCharSet != RTL_TEXTENCODING_MS_1252);
+ SetOrientation( nOrientation );
+}
+
+// -----------------------------------------------------------------------
+
+bool PDFSalLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ const String aText( rArgs.mpStr+rArgs.mnMinCharPos, sal::static_int_cast<xub_StrLen>(rArgs.mnEndCharPos-rArgs.mnMinCharPos) );
+ SetText( aText );
+ SetUnitsPerPixel( 1000 );
+
+ rtl_UnicodeToTextConverter aConv = rtl_createTextToUnicodeConverter( mrBuiltinFont.m_eCharSet );
+
+ Point aNewPos( 0, 0 );
+ bool bRightToLeft;
+ for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); )
+ {
+ // TODO: handle unicode surrogates
+ // on the other hand the PDF builtin fonts don't support them anyway
+ sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
+ if( bRightToLeft )
+ cChar = static_cast<sal_Unicode>(GetMirroredChar( cChar ));
+
+ if( 1 ) // TODO: shortcut for ASCII?
+ {
+ sal_Char aBuf[4];
+ sal_uInt32 nInfo;
+ sal_Size nSrcCvtChars;
+
+ sal_Size nConv = rtl_convertUnicodeToText( aConv,
+ NULL,
+ &cChar, 1,
+ aBuf, sizeof(aBuf)/sizeof(*aBuf),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR,
+ &nInfo, &nSrcCvtChars );
+ // check whether conversion was possible
+ // else fallback font is needed as the standard fonts
+ // are handled via WinAnsi encoding
+ if( nConv > 0 )
+ cChar = ((sal_Unicode)aBuf[0]) & 0x00ff;
+ }
+ if( cChar & 0xff00 )
+ {
+ cChar = 0; // NotDef glyph
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+ }
+
+ long nGlyphWidth = (long)mrBuiltinFont.m_aWidths[cChar] * mnPixelPerEM;
+ long nGlyphFlags = 0; // builtin fonts don't have diacritic glyphs
+ if( bRightToLeft )
+ nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
+ // TODO: get kerning from builtin fonts
+ GlyphItem aGI( nCharPos, cChar, aNewPos, nGlyphFlags, nGlyphWidth );
+ AppendGlyph( aGI );
+
+ aNewPos.X() += nGlyphWidth;
+ }
+
+ rtl_destroyUnicodeToTextConverter( aConv );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void PDFSalLayout::InitFont() const
+{
+ // TODO: recreate font with all its attributes
+}
+
+// -----------------------------------------------------------------------
+
+void PDFSalLayout::DrawText( SalGraphics& ) const
+{
+ mrPDFWriterImpl.drawLayout( *const_cast<PDFSalLayout*>(this), maOrigText, true );
+}
+
+// -----------------------------------------------------------------------
+
+SalLayout* PDFWriterImpl::GetTextLayout( ImplLayoutArgs& rArgs, ImplFontSelectData* pSelect )
+{
+ DBG_ASSERT( (pSelect->mpFontData != NULL),
+ "PDFWriterImpl::GetTextLayout mpFontData is NULL" );
+
+ const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData );
+ if( !pFD )
+ return NULL;
+ const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
+
+ long nPixelPerEM = pSelect->mnWidth ? pSelect->mnWidth : pSelect->mnHeight;
+ int nOrientation = pSelect->mnOrientation;
+ PDFSalLayout* pLayout = new PDFSalLayout( *this, *pBuiltinFont, nPixelPerEM, nOrientation );
+ pLayout->SetText( rArgs.mpStr );
+ return pLayout;
+}
+
+sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
+{
+ if( m_aContext.Encrypt && m_aPages.empty() )
+ initEncryption();
+
+ endPage();
+ m_nCurrentPage = m_aPages.size();
+ m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) );
+ m_aPages.back().m_nPageIndex = m_nCurrentPage;
+ m_aPages.back().beginStream();
+
+ // setup global graphics state
+ // linewidth is "1 pixel" by default
+ OStringBuffer aBuf( 16 );
+ appendDouble( 72.0/double(getReferenceDevice()->ImplGetDPIX()), aBuf );
+ aBuf.append( " w\n" );
+ writeBuffer( aBuf.getStr(), aBuf.getLength() );
+
+ return m_nCurrentPage;
+}
+
+void PDFWriterImpl::endPage()
+{
+ if( m_aPages.begin() != m_aPages.end() )
+ {
+ // close eventual MC sequence
+ endStructureElementMCSeq();
+
+ // sanity check
+ if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
+ {
+ DBG_ERROR( "redirection across pages !!!" );
+ m_aOutputStreams.clear(); // leak !
+ m_aMapMode.SetOrigin( Point() );
+ }
+
+ m_aGraphicsStack.clear();
+ m_aGraphicsStack.push_back( GraphicsState() );
+
+ // this should pop the PDF graphics stack if necessary
+ updateGraphicsState();
+
+ m_aPages.back().endStream();
+
+ // reset the default font
+ Font aFont;
+ aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
+ aFont.SetSize( Size( 0, 12 ) );
+
+ m_aCurrentPDFState = m_aGraphicsStack.front();
+ m_aGraphicsStack.front().m_aFont = aFont;
+
+ for( std::list<BitmapEmit>::iterator it = m_aBitmaps.begin();
+ it != m_aBitmaps.end(); ++it )
+ {
+ if( ! it->m_aBitmap.IsEmpty() )
+ {
+ writeBitmapObject( *it );
+ it->m_aBitmap = BitmapEx();
+ }
+ }
+ for( std::list<JPGEmit>::iterator jpeg = m_aJPGs.begin(); jpeg != m_aJPGs.end(); ++jpeg )
+ {
+ if( jpeg->m_pStream )
+ {
+ writeJPG( *jpeg );
+ delete jpeg->m_pStream;
+ jpeg->m_pStream = NULL;
+ jpeg->m_aMask = Bitmap();
+ }
+ }
+ for( std::list<TransparencyEmit>::iterator t = m_aTransparentObjects.begin();
+ t != m_aTransparentObjects.end(); ++t )
+ {
+ if( t->m_pContentStream )
+ {
+ writeTransparentObject( *t );
+ delete t->m_pContentStream;
+ t->m_pContentStream = NULL;
+ }
+ }
+ }
+}
+
+sal_Int32 PDFWriterImpl::createObject()
+{
+ m_aObjects.push_back( ~0U );
+ return m_aObjects.size();
+}
+
+bool PDFWriterImpl::updateObject( sal_Int32 n )
+{
+ if( ! m_bOpen )
+ return false;
+
+ sal_uInt64 nOffset = ~0U;
+ oslFileError aError = osl_getFilePos( m_aFile, &nOffset );
+ DBG_ASSERT( aError == osl_File_E_None, "could not register object" );
+ if( aError != osl_File_E_None )
+ {
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+ }
+ m_aObjects[ n-1 ] = nOffset;
+ return aError == osl_File_E_None;
+}
+
+#define CHECK_RETURN( x ) if( !(x) ) return 0
+
+sal_Int32 PDFWriterImpl::emitStructParentTree( sal_Int32 nObject )
+{
+ if( nObject > 0 )
+ {
+ OStringBuffer aLine( 1024 );
+
+ aLine.append( nObject );
+ aLine.append( " 0 obj\n"
+ "<</Nums[\n" );
+ sal_Int32 nTreeItems = m_aStructParentTree.size();
+ for( sal_Int32 n = 0; n < nTreeItems; n++ )
+ {
+ aLine.append( n );
+ aLine.append( ' ' );
+ aLine.append( m_aStructParentTree[n] );
+ aLine.append( "\n" );
+ }
+ aLine.append( "]>>\nendobj\n\n" );
+ CHECK_RETURN( updateObject( nObject ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+ return nObject;
+}
+
+const sal_Char* PDFWriterImpl::getAttributeTag( PDFWriter::StructAttribute eAttr )
+{
+ static std::map< PDFWriter::StructAttribute, const char* > aAttributeStrings;
+ // fill maps once
+ if( aAttributeStrings.empty() )
+ {
+ aAttributeStrings[ PDFWriter::Placement ] = "Placement";
+ aAttributeStrings[ PDFWriter::WritingMode ] = "WritingMode";
+ aAttributeStrings[ PDFWriter::SpaceBefore ] = "SpaceBefore";
+ aAttributeStrings[ PDFWriter::SpaceAfter ] = "SpaceAfter";
+ aAttributeStrings[ PDFWriter::StartIndent ] = "StartIndent";
+ aAttributeStrings[ PDFWriter::EndIndent ] = "EndIndent";
+ aAttributeStrings[ PDFWriter::TextIndent ] = "TextIndent";
+ aAttributeStrings[ PDFWriter::TextAlign ] = "TextAlign";
+ aAttributeStrings[ PDFWriter::Width ] = "Width";
+ aAttributeStrings[ PDFWriter::Height ] = "Height";
+ aAttributeStrings[ PDFWriter::BlockAlign ] = "BlockAlign";
+ aAttributeStrings[ PDFWriter::InlineAlign ] = "InlineAlign";
+ aAttributeStrings[ PDFWriter::LineHeight ] = "LineHeight";
+ aAttributeStrings[ PDFWriter::BaselineShift ] = "BaselineShift";
+ aAttributeStrings[ PDFWriter::TextDecorationType ] = "TextDecorationType";
+ aAttributeStrings[ PDFWriter::ListNumbering ] = "ListNumbering";
+ aAttributeStrings[ PDFWriter::RowSpan ] = "RowSpan";
+ aAttributeStrings[ PDFWriter::ColSpan ] = "ColSpan";
+ aAttributeStrings[ PDFWriter::LinkAnnotation ] = "LinkAnnotation";
+ }
+
+ std::map< PDFWriter::StructAttribute, const char* >::const_iterator it =
+ aAttributeStrings.find( eAttr );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( it == aAttributeStrings.end() )
+ fprintf( stderr, "invalid PDFWriter::StructAttribute %d\n", eAttr );
+#endif
+
+ return it != aAttributeStrings.end() ? it->second : "";
+}
+
+const sal_Char* PDFWriterImpl::getAttributeValueTag( PDFWriter::StructAttributeValue eVal )
+{
+ static std::map< PDFWriter::StructAttributeValue, const char* > aValueStrings;
+
+ if( aValueStrings.empty() )
+ {
+ aValueStrings[ PDFWriter::NONE ] = "None";
+ aValueStrings[ PDFWriter::Block ] = "Block";
+ aValueStrings[ PDFWriter::Inline ] = "Inline";
+ aValueStrings[ PDFWriter::Before ] = "Before";
+ aValueStrings[ PDFWriter::After ] = "After";
+ aValueStrings[ PDFWriter::Start ] = "Start";
+ aValueStrings[ PDFWriter::End ] = "End";
+ aValueStrings[ PDFWriter::LrTb ] = "LrTb";
+ aValueStrings[ PDFWriter::RlTb ] = "RlTb";
+ aValueStrings[ PDFWriter::TbRl ] = "TbRl";
+ aValueStrings[ PDFWriter::Center ] = "Center";
+ aValueStrings[ PDFWriter::Justify ] = "Justify";
+ aValueStrings[ PDFWriter::Auto ] = "Auto";
+ aValueStrings[ PDFWriter::Middle ] = "Middle";
+ aValueStrings[ PDFWriter::Normal ] = "Normal";
+ aValueStrings[ PDFWriter::Underline ] = "Underline";
+ aValueStrings[ PDFWriter::Overline ] = "Overline";
+ aValueStrings[ PDFWriter::LineThrough ] = "LineThrough";
+ aValueStrings[ PDFWriter::Disc ] = "Disc";
+ aValueStrings[ PDFWriter::Circle ] = "Circle";
+ aValueStrings[ PDFWriter::Square ] = "Square";
+ aValueStrings[ PDFWriter::Decimal ] = "Decimal";
+ aValueStrings[ PDFWriter::UpperRoman ] = "UpperRoman";
+ aValueStrings[ PDFWriter::LowerRoman ] = "LowerRoman";
+ aValueStrings[ PDFWriter::UpperAlpha ] = "UpperAlpha";
+ aValueStrings[ PDFWriter::LowerAlpha ] = "LowerAlpha";
+ }
+
+ std::map< PDFWriter::StructAttributeValue, const char* >::const_iterator it =
+ aValueStrings.find( eVal );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( it == aValueStrings.end() )
+ fprintf( stderr, "invalid PDFWriter::StructAttributeValue %d\n", eVal );
+#endif
+
+ return it != aValueStrings.end() ? it->second : "";
+}
+
+static void appendStructureAttributeLine( PDFWriter::StructAttribute i_eAttr, const PDFWriterImpl::PDFStructureAttribute& i_rVal, OStringBuffer& o_rLine, bool i_bIsFixedInt )
+{
+ o_rLine.append( "/" );
+ o_rLine.append( PDFWriterImpl::getAttributeTag( i_eAttr ) );
+
+ if( i_rVal.eValue != PDFWriter::Invalid )
+ {
+ o_rLine.append( "/" );
+ o_rLine.append( PDFWriterImpl::getAttributeValueTag( i_rVal.eValue ) );
+ }
+ else
+ {
+ // numerical value
+ o_rLine.append( " " );
+ if( i_bIsFixedInt )
+ appendFixedInt( i_rVal.nValue, o_rLine );
+ else
+ o_rLine.append( i_rVal.nValue );
+ }
+ o_rLine.append( "\n" );
+}
+
+OString PDFWriterImpl::emitStructureAttributes( PDFStructureElement& i_rEle )
+{
+ // create layout, list and table attribute sets
+ OStringBuffer aLayout(256), aList(64), aTable(64);
+ for( PDFStructAttributes::const_iterator it = i_rEle.m_aAttributes.begin();
+ it != i_rEle.m_aAttributes.end(); ++it )
+ {
+ if( it->first == PDFWriter::ListNumbering )
+ appendStructureAttributeLine( it->first, it->second, aList, true );
+ else if( it->first == PDFWriter::RowSpan ||
+ it->first == PDFWriter::ColSpan )
+ appendStructureAttributeLine( it->first, it->second, aTable, false );
+ else if( it->first == PDFWriter::LinkAnnotation )
+ {
+ sal_Int32 nLink = it->second.nValue;
+ std::map< sal_Int32, sal_Int32 >::const_iterator link_it =
+ m_aLinkPropertyMap.find( nLink );
+ if( link_it != m_aLinkPropertyMap.end() )
+ nLink = link_it->second;
+ if( nLink >= 0 && nLink < (sal_Int32)m_aLinks.size() )
+ {
+ // update struct parent of link
+ OStringBuffer aStructParentEntry( 32 );
+ aStructParentEntry.append( i_rEle.m_nObject );
+ aStructParentEntry.append( " 0 R" );
+ m_aStructParentTree.push_back( aStructParentEntry.makeStringAndClear() );
+ m_aLinks[ nLink ].m_nStructParent = m_aStructParentTree.size()-1;
+
+ sal_Int32 nRefObject = createObject();
+ OStringBuffer aRef( 256 );
+ aRef.append( nRefObject );
+ aRef.append( " 0 obj\n"
+ "<</Type/OBJR/Obj " );
+ aRef.append( m_aLinks[ nLink ].m_nObject );
+ aRef.append( " 0 R>>\n"
+ "endobj\n\n"
+ );
+ updateObject( nRefObject );
+ writeBuffer( aRef.getStr(), aRef.getLength() );
+
+ i_rEle.m_aKids.push_back( PDFStructureElementKid( nRefObject ) );
+ }
+ else
+ {
+ DBG_ERROR( "unresolved link id for Link structure" );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "unresolved link id %" SAL_PRIdINT32 " for Link structure\n", nLink );
+ {
+ OStringBuffer aLine( "unresolved link id " );
+ aLine.append( nLink );
+ aLine.append( " for Link structure" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+ }
+ }
+ else
+ appendStructureAttributeLine( it->first, it->second, aLayout, true );
+ }
+ if( ! i_rEle.m_aBBox.IsEmpty() )
+ {
+ aLayout.append( "/BBox[" );
+ appendFixedInt( i_rEle.m_aBBox.Left(), aLayout );
+ aLayout.append( " " );
+ appendFixedInt( i_rEle.m_aBBox.Top(), aLayout );
+ aLayout.append( " " );
+ appendFixedInt( i_rEle.m_aBBox.Right(), aLayout );
+ aLayout.append( " " );
+ appendFixedInt( i_rEle.m_aBBox.Bottom(), aLayout );
+ aLayout.append( "]\n" );
+ }
+
+ std::vector< sal_Int32 > aAttribObjects;
+ if( aLayout.getLength() )
+ {
+ aAttribObjects.push_back( createObject() );
+ updateObject( aAttribObjects.back() );
+ OStringBuffer aObj( 64 );
+ aObj.append( aAttribObjects.back() );
+ aObj.append( " 0 obj\n"
+ "<</O/Layout\n" );
+ aLayout.append( ">>\nendobj\n\n" );
+ writeBuffer( aObj.getStr(), aObj.getLength() );
+ writeBuffer( aLayout.getStr(), aLayout.getLength() );
+ }
+ if( aList.getLength() )
+ {
+ aAttribObjects.push_back( createObject() );
+ updateObject( aAttribObjects.back() );
+ OStringBuffer aObj( 64 );
+ aObj.append( aAttribObjects.back() );
+ aObj.append( " 0 obj\n"
+ "<</O/List\n" );
+ aList.append( ">>\nendobj\n\n" );
+ writeBuffer( aObj.getStr(), aObj.getLength() );
+ writeBuffer( aList.getStr(), aList.getLength() );
+ }
+ if( aTable.getLength() )
+ {
+ aAttribObjects.push_back( createObject() );
+ updateObject( aAttribObjects.back() );
+ OStringBuffer aObj( 64 );
+ aObj.append( aAttribObjects.back() );
+ aObj.append( " 0 obj\n"
+ "<</O/Table\n" );
+ aTable.append( ">>\nendobj\n\n" );
+ writeBuffer( aObj.getStr(), aObj.getLength() );
+ writeBuffer( aTable.getStr(), aTable.getLength() );
+ }
+
+ OStringBuffer aRet( 64 );
+ if( aAttribObjects.size() > 1 )
+ aRet.append( " [" );
+ for( std::vector< sal_Int32 >::const_iterator at_it = aAttribObjects.begin();
+ at_it != aAttribObjects.end(); ++at_it )
+ {
+ aRet.append( " " );
+ aRet.append( *at_it );
+ aRet.append( " 0 R" );
+ }
+ if( aAttribObjects.size() > 1 )
+ aRet.append( " ]" );
+ return aRet.makeStringAndClear();
+}
+
+sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
+{
+ if(
+ // do not emit NonStruct and its children
+ rEle.m_eType == PDFWriter::NonStructElement &&
+ rEle.m_nOwnElement != rEle.m_nParentElement // but of course emit the struct tree root
+ )
+ return 0;
+
+ for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
+ {
+ if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
+ {
+ PDFStructureElement& rChild = m_aStructure[ *it ];
+ if( rChild.m_eType != PDFWriter::NonStructElement )
+ {
+ if( rChild.m_nParentElement == rEle.m_nOwnElement )
+ emitStructure( rChild );
+ else
+ {
+ DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure element" );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
+#endif
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure id" );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
+#endif
+ }
+ }
+
+ OStringBuffer aLine( 512 );
+ aLine.append( rEle.m_nObject );
+ aLine.append( " 0 obj\n"
+ "<</Type" );
+ sal_Int32 nParentTree = -1;
+ if( rEle.m_nOwnElement == rEle.m_nParentElement )
+ {
+ nParentTree = createObject();
+ CHECK_RETURN( nParentTree );
+ aLine.append( "/StructTreeRoot\n" );
+ aLine.append( "/ParentTree " );
+ aLine.append( nParentTree );
+ aLine.append( " 0 R\n" );
+ if( ! m_aRoleMap.empty() )
+ {
+ aLine.append( "/RoleMap<<" );
+ for( std::hash_map<OString,OString,OStringHash>::const_iterator
+ it = m_aRoleMap.begin(); it != m_aRoleMap.end(); ++it )
+ {
+ aLine.append( '/' );
+ aLine.append(it->first);
+ aLine.append( '/' );
+ aLine.append( it->second );
+ aLine.append( '\n' );
+ }
+ aLine.append( ">>\n" );
+ }
+ }
+ else
+ {
+ aLine.append( "/StructElem\n"
+ "/S/" );
+ if( rEle.m_aAlias.getLength() > 0 )
+ aLine.append( rEle.m_aAlias );
+ else
+ aLine.append( getStructureTag( rEle.m_eType ) );
+ aLine.append( "\n"
+ "/P " );
+ aLine.append( m_aStructure[ rEle.m_nParentElement ].m_nObject );
+ aLine.append( " 0 R\n"
+ "/Pg " );
+ aLine.append( rEle.m_nFirstPageObject );
+ aLine.append( " 0 R\n" );
+ if( rEle.m_aActualText.getLength() )
+ {
+ aLine.append( "/ActualText" );
+ appendUnicodeTextStringEncrypt( rEle.m_aActualText, rEle.m_nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( rEle.m_aAltText.getLength() )
+ {
+ aLine.append( "/Alt" );
+ appendUnicodeTextStringEncrypt( rEle.m_aAltText, rEle.m_nObject, aLine );
+ aLine.append( "\n" );
+ }
+ }
+ if( ! rEle.m_aBBox.IsEmpty() || rEle.m_aAttributes.size() )
+ {
+ OString aAttribs = emitStructureAttributes( rEle );
+ if( aAttribs.getLength() )
+ {
+ aLine.append( "/A" );
+ aLine.append( aAttribs );
+ aLine.append( "\n" );
+ }
+ }
+ if( rEle.m_aLocale.Language.getLength() > 0 )
+ {
+ OUStringBuffer aLocBuf( 16 );
+ aLocBuf.append( rEle.m_aLocale.Language.toAsciiLowerCase() );
+ if( rEle.m_aLocale.Country.getLength() > 0 )
+ {
+ aLocBuf.append( sal_Unicode('-') );
+ aLocBuf.append( rEle.m_aLocale.Country );
+ }
+ aLine.append( "/Lang" );
+ appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), rEle.m_nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( ! rEle.m_aKids.empty() )
+ {
+ unsigned int i = 0;
+ aLine.append( "/K[" );
+ for( std::list< PDFStructureElementKid >::const_iterator it =
+ rEle.m_aKids.begin(); it != rEle.m_aKids.end(); ++it, i++ )
+ {
+ if( it->nMCID == -1 )
+ {
+ aLine.append( it->nObject );
+ aLine.append( " 0 R" );
+ aLine.append( ( (i & 15) == 15 ) ? "\n" : " " );
+ }
+ else
+ {
+ if( it->nObject == rEle.m_nFirstPageObject )
+ {
+ aLine.append( it->nMCID );
+ aLine.append( " " );
+ }
+ else
+ {
+ aLine.append( "<</Type/MCR/Pg " );
+ aLine.append( it->nObject );
+ aLine.append( " 0 R /MCID " );
+ aLine.append( it->nMCID );
+ aLine.append( ">>\n" );
+ }
+ }
+ }
+ aLine.append( "]\n" );
+ }
+ aLine.append( ">>\nendobj\n\n" );
+
+ CHECK_RETURN( updateObject( rEle.m_nObject ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ CHECK_RETURN( emitStructParentTree( nParentTree ) );
+
+ return rEle.m_nObject;
+}
+
+bool PDFWriterImpl::emitGradients()
+{
+ for( std::list<GradientEmit>::iterator it = m_aGradients.begin();
+ it != m_aGradients.end(); ++it )
+ {
+ CHECK_RETURN( writeGradientFunction( *it ) );
+ }
+ return true;
+}
+
+bool PDFWriterImpl::emitTilings()
+{
+ OStringBuffer aTilingObj( 1024 );
+
+ for( std::vector<TilingEmit>::iterator it = m_aTilings.begin(); it != m_aTilings.end(); ++it )
+ {
+ DBG_ASSERT( it->m_pTilingStream, "tiling without stream" );
+ if( ! it->m_pTilingStream )
+ continue;
+
+ aTilingObj.setLength( 0 );
+
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( "PDFWriterImpl::emitTilings" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+
+ sal_Int32 nX = (sal_Int32)it->m_aRectangle.Left();
+ sal_Int32 nY = (sal_Int32)it->m_aRectangle.Top();
+ sal_Int32 nW = (sal_Int32)it->m_aRectangle.GetWidth();
+ sal_Int32 nH = (sal_Int32)it->m_aRectangle.GetHeight();
+ if( it->m_aCellSize.Width() == 0 )
+ it->m_aCellSize.Width() = nW;
+ if( it->m_aCellSize.Height() == 0 )
+ it->m_aCellSize.Height() = nH;
+
+ bool bDeflate = compressStream( it->m_pTilingStream );
+ it->m_pTilingStream->Seek( STREAM_SEEK_TO_END );
+ sal_Size nTilingStreamSize = it->m_pTilingStream->Tell();
+ it->m_pTilingStream->Seek( STREAM_SEEK_TO_BEGIN );
+
+ // write pattern object
+ aTilingObj.append( it->m_nObject );
+ aTilingObj.append( " 0 obj\n" );
+ aTilingObj.append( "<</Type/Pattern/PatternType 1\n"
+ "/PaintType 1\n"
+ "/TilingType 2\n"
+ "/BBox[" );
+ appendFixedInt( nX, aTilingObj );
+ aTilingObj.append( ' ' );
+ appendFixedInt( nY, aTilingObj );
+ aTilingObj.append( ' ' );
+ appendFixedInt( nX+nW, aTilingObj );
+ aTilingObj.append( ' ' );
+ appendFixedInt( nY+nH, aTilingObj );
+ aTilingObj.append( "]\n"
+ "/XStep " );
+ appendFixedInt( it->m_aCellSize.Width(), aTilingObj );
+ aTilingObj.append( "\n"
+ "/YStep " );
+ appendFixedInt( it->m_aCellSize.Height(), aTilingObj );
+ aTilingObj.append( "\n" );
+ if( it->m_aTransform.matrix[0] != 1.0 ||
+ it->m_aTransform.matrix[1] != 0.0 ||
+ it->m_aTransform.matrix[3] != 0.0 ||
+ it->m_aTransform.matrix[4] != 1.0 ||
+ it->m_aTransform.matrix[2] != 0.0 ||
+ it->m_aTransform.matrix[5] != 0.0 )
+ {
+ aTilingObj.append( "/Matrix [" );
+ // TODO: scaling, mirroring on y, etc
+ appendDouble( it->m_aTransform.matrix[0], aTilingObj );
+ aTilingObj.append( ' ' );
+ appendDouble( it->m_aTransform.matrix[1], aTilingObj );
+ aTilingObj.append( ' ' );
+ appendDouble( it->m_aTransform.matrix[3], aTilingObj );
+ aTilingObj.append( ' ' );
+ appendDouble( it->m_aTransform.matrix[4], aTilingObj );
+ aTilingObj.append( ' ' );
+ appendDouble( it->m_aTransform.matrix[2], aTilingObj );
+ aTilingObj.append( ' ' );
+ appendDouble( it->m_aTransform.matrix[5], aTilingObj );
+ aTilingObj.append( "]\n" );
+ }
+ aTilingObj.append( "/Resources" );
+ it->m_aResources.append( aTilingObj, getFontDictObject() );
+ if( bDeflate )
+ aTilingObj.append( "/Filter/FlateDecode" );
+ aTilingObj.append( "/Length " );
+ aTilingObj.append( (sal_Int32)nTilingStreamSize );
+ aTilingObj.append( ">>\nstream\n" );
+ CHECK_RETURN( updateObject( it->m_nObject ) );
+ CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
+ checkAndEnableStreamEncryption( it->m_nObject );
+ nTilingStreamSize = writeBuffer( it->m_pTilingStream->GetData(), nTilingStreamSize );
+ delete it->m_pTilingStream;
+ it->m_pTilingStream = NULL;
+ if( nTilingStreamSize == 0 )
+ return false;
+ disableStreamEncryption();
+ aTilingObj.setLength( 0 );
+ aTilingObj.append( "\nendstream\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
+ }
+ return true;
+}
+
+sal_Int32 PDFWriterImpl::emitBuiltinFont( const ImplFontData* pFont, sal_Int32 nFontObject )
+{
+ const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
+ if( !pFD )
+ return 0;
+ const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
+
+ OStringBuffer aLine( 1024 );
+
+ if( nFontObject <= 0 )
+ nFontObject = createObject();
+ CHECK_RETURN( updateObject( nFontObject ) );
+ aLine.append( nFontObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/Font/Subtype/Type1/BaseFont/" );
+ appendName( pBuiltinFont->m_pPSName, aLine );
+ aLine.append( "\n" );
+ if( pBuiltinFont->m_eCharSet == RTL_TEXTENCODING_MS_1252 )
+ aLine.append( "/Encoding/WinAnsiEncoding\n" );
+ aLine.append( ">>\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ return nFontObject;
+}
+
+std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const ImplFontData* pFont, EmbedFont& rEmbed )
+{
+ std::map< sal_Int32, sal_Int32 > aRet;
+ if( isBuiltinFont( pFont ) )
+ {
+ aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont );
+ return aRet;
+ }
+
+ sal_Int32 nFontObject = 0;
+ sal_Int32 nFontDescriptor = 0;
+ rtl::OString aSubType( "/Type1" );
+ FontSubsetInfo aInfo;
+ // fill in dummy values
+ aInfo.m_nAscent = 1000;
+ aInfo.m_nDescent = 200;
+ aInfo.m_nCapHeight = 1000;
+ aInfo.m_aFontBBox = Rectangle( Point( -200, -200 ), Size( 1700, 1700 ) );
+ aInfo.m_aPSName = pFont->maName;
+ sal_Int32 pWidths[256];
+ rtl_zeroMemory( pWidths, sizeof(pWidths) );
+ if( pFont->IsEmbeddable() )
+ {
+ const unsigned char* pFontData = NULL;
+ long nFontLen = 0;
+ sal_Ucs nEncodedCodes[256];
+ sal_Int32 pEncWidths[256];
+ if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pEncWidths, aInfo, &nFontLen )) != NULL )
+ {
+ m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen );
+ for( int i = 0; i < 256; i++ )
+ {
+ if( nEncodedCodes[i] >= 32 && nEncodedCodes[i] < 256 )
+ {
+ pWidths[i] = pEncWidths[ i ];
+ }
+ }
+ }
+ }
+ else if( pFont->mbSubsettable )
+ {
+ aSubType = rtl::OString( "/TrueType" );
+ Int32Vector aGlyphWidths;
+ Ucs2UIntMap aUnicodeMap;
+ m_pReferenceDevice->mpGraphics->GetGlyphWidths( pFont, false, aGlyphWidths, aUnicodeMap );
+
+ OUString aTmpName;
+ osl_createTempFile( NULL, NULL, &aTmpName.pData );
+ sal_Int32 pGlyphIDs[ 256 ];
+ sal_uInt8 pEncoding[ 256 ];
+ sal_Ucs pUnicodes[ 256 ];
+ sal_Int32 pDuWidths[ 256 ];
+
+ memset( pGlyphIDs, 0, sizeof( pGlyphIDs ) );
+ memset( pEncoding, 0, sizeof( pEncoding ) );
+ memset( pUnicodes, 0, sizeof( pUnicodes ) );
+ memset( pDuWidths, 0, sizeof( pDuWidths ) );
+
+ for( sal_Ucs c = 32; c < 256; c++ )
+ {
+ pUnicodes[c] = c;
+ pEncoding[c] = c;
+ pGlyphIDs[c] = 0;
+ if( aUnicodeMap.find( c ) != aUnicodeMap.end() )
+ pWidths[ c ] = aGlyphWidths[ aUnicodeMap[ c ] ];
+ }
+
+ m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, pFont, pGlyphIDs, pEncoding, pDuWidths, 256, aInfo );
+ osl_removeFile( aTmpName.pData );
+ }
+ else
+ {
+ DBG_ERROR( "system font neither embeddable nor subsettable" );
+ }
+
+ // write font descriptor
+ nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, 0 );
+ if( nFontDescriptor )
+ {
+ // write font object
+ sal_Int32 nObject = createObject();
+ if( updateObject( nObject ) )
+ {
+ OStringBuffer aLine( 1024 );
+ aLine.append( nObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/Font/Subtype" );
+ aLine.append( aSubType );
+ aLine.append( "/BaseFont/" );
+ appendName( aInfo.m_aPSName, aLine );
+ aLine.append( "\n" );
+ if( !pFont->mbSymbolFlag )
+ aLine.append( "/Encoding/WinAnsiEncoding\n" );
+ aLine.append( "/FirstChar 32 /LastChar 255\n"
+ "/Widths[" );
+ for( int i = 32; i < 256; i++ )
+ {
+ aLine.append( pWidths[i] );
+ aLine.append( ((i&15) == 15) ? "\n" : " " );
+ }
+ aLine.append( "]\n"
+ "/FontDescriptor " );
+ aLine.append( nFontDescriptor );
+ aLine.append( " 0 R>>\n"
+ "endobj\n\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ nFontObject = nObject;
+ aRet[ rEmbed.m_nNormalFontID ] = nObject;
+ }
+ }
+
+ return aRet;
+}
+
+typedef int ThreeInts[3];
+static bool getPfbSegmentLengths( const unsigned char* pFontBytes, int nByteLen,
+ ThreeInts& rSegmentLengths )
+{
+ if( !pFontBytes || (nByteLen < 0) )
+ return false;
+ const unsigned char* pPtr = pFontBytes;
+ const unsigned char* pEnd = pFontBytes + nByteLen;
+
+ for( int i = 0; i < 3; ++i) {
+ // read segment1 header
+ if( pPtr+6 >= pEnd )
+ return false;
+ if( (pPtr[0] != 0x80) || (pPtr[1] >= 0x03) )
+ return false;
+ const int nLen = (pPtr[5]<<24) + (pPtr[4]<<16) + (pPtr[3]<<8) + pPtr[2];
+ if( nLen <= 0)
+ return false;
+ rSegmentLengths[i] = nLen;
+ pPtr += nLen + 6;
+ }
+
+ // read segment-end header
+ if( pPtr+2 >= pEnd )
+ return false;
+ if( (pPtr[0] != 0x80) || (pPtr[1] != 0x03) )
+ return false;
+
+ return true;
+}
+
+struct FontException : public std::exception
+{
+};
+
+// TODO: always subset instead of embedding the full font => this method becomes obsolete then
+std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFontData* pFont, EmbedFont& rEmbed )
+{
+ std::map< sal_Int32, sal_Int32 > aRet;
+ if( isBuiltinFont( pFont ) )
+ {
+ aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont );
+ return aRet;
+ }
+
+ sal_Int32 nFontObject = 0;
+ sal_Int32 nStreamObject = 0;
+ sal_Int32 nFontDescriptor = 0;
+
+ // prepare font encoding
+ const Ucs2SIntMap* pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pFont, NULL );
+ sal_Int32 nToUnicodeStream = 0;
+ sal_uInt8 nEncoding[256];
+ sal_Ucs nEncodedCodes[256];
+ std::vector<sal_Ucs> aUnicodes;
+ aUnicodes.reserve( 256 );
+ sal_Int32 pUnicodesPerGlyph[256];
+ sal_Int32 pEncToUnicodeIndex[256];
+ if( pEncoding )
+ {
+ rtl_zeroMemory( nEncoding, sizeof(nEncoding) );
+ rtl_zeroMemory( nEncodedCodes, sizeof(nEncodedCodes) );
+ rtl_zeroMemory( pUnicodesPerGlyph, sizeof(pUnicodesPerGlyph) );
+ rtl_zeroMemory( pEncToUnicodeIndex, sizeof(pEncToUnicodeIndex) );
+ for( Ucs2SIntMap::const_iterator it = pEncoding->begin(); it != pEncoding->end(); ++it )
+ {
+ if( it->second != -1 )
+ {
+ sal_Int32 nCode = (sal_Int32)(it->second & 0x000000ff);
+ nEncoding[ nCode ] = static_cast<sal_uInt8>( nCode );
+ nEncodedCodes[ nCode ] = it->first;
+ pEncToUnicodeIndex[ nCode ] = static_cast<sal_Int32>(aUnicodes.size());
+ aUnicodes.push_back( it->first );
+ pUnicodesPerGlyph[ nCode ] = 1;
+ }
+ }
+ }
+
+ FontSubsetInfo aInfo;
+ sal_Int32 pWidths[256];
+ const unsigned char* pFontData = NULL;
+ long nFontLen = 0;
+ sal_Int32 nLength1, nLength2;
+ try
+ {
+ if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pWidths, aInfo, &nFontLen )) != NULL )
+ {
+ if( (aInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) == 0 )
+ throw FontException();
+ // see whether it is pfb or pfa; if it is a pfb, fill ranges
+ // of 6 bytes that are not part of the font program
+ std::list< int > aSections;
+ std::list< int >::const_iterator it;
+ int nIndex = 0;
+ while( pFontData[nIndex] == 0x80 && nIndex < nFontLen-1 )
+ {
+ aSections.push_back( nIndex );
+ if( pFontData[nIndex+1] == 0x03 )
+ break;
+ sal_Int32 nBytes =
+ ((sal_Int32)pFontData[nIndex+2]) |
+ ((sal_Int32)pFontData[nIndex+3]) << 8 |
+ ((sal_Int32)pFontData[nIndex+4]) << 16 |
+ ((sal_Int32)pFontData[nIndex+5]) << 24;
+ nIndex += nBytes+6;
+ }
+
+ // search for eexec
+ // TODO: use getPfbSegmentLengths() if possible to skip the search thingies below
+ nIndex = 0;
+ int nEndAsciiIndex;
+ int nBeginBinaryIndex;
+ int nEndBinaryIndex;
+ do
+ {
+ while( nIndex < nFontLen-4 &&
+ ( pFontData[nIndex] != 'e' ||
+ pFontData[nIndex+1] != 'e' ||
+ pFontData[nIndex+2] != 'x' ||
+ pFontData[nIndex+3] != 'e' ||
+ pFontData[nIndex+4] != 'c'
+ )
+ )
+ nIndex++;
+ // check whether we are in a excluded section
+ for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
+ ;
+ } while( it != aSections.end() && nIndex < nFontLen-4 );
+ // this should end the ascii part
+ if( nIndex > nFontLen-5 )
+ throw FontException();
+
+ nEndAsciiIndex = nIndex+4;
+ // now count backwards until we can account for 512 '0'
+ // which is the endmarker of the (hopefully) binary data
+ // do not count the pfb header sections
+ int nFound = 0;
+ nIndex = nFontLen-1;
+ while( nIndex > 0 && nFound < 512 )
+ {
+ for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
+ ;
+ if( it == aSections.end() )
+ {
+ // inside the 512 '0' block there may only be whitespace
+ // according to T1 spec; probably it would be to simple
+ // if all fonts complied
+ if( pFontData[nIndex] == '0' )
+ nFound++;
+ else if( nFound > 0 &&
+ pFontData[nIndex] != '\r' &&
+ pFontData[nIndex] != '\t' &&
+ pFontData[nIndex] != '\n' &&
+ pFontData[nIndex] != ' ' )
+ break;
+ }
+ nIndex--;
+ }
+
+ if( nIndex < 1 || nIndex <= nEndAsciiIndex )
+ throw FontException();
+
+ // nLength3 is the rest of the file - excluding any section headers
+ // nIndex now points to the first of the 512 '0' characters marking the
+ // fixed content portion
+ sal_Int32 nLength3 = nFontLen - nIndex;
+ for( it = aSections.begin(); it != aSections.end(); ++it )
+ {
+ if( *it >= nIndex )
+ {
+ // special case: nIndex inside a section marker
+ if( nIndex >= (*it) && (*it)+5 > nIndex )
+ nLength3 -= (*it)+5 - nIndex;
+ else
+ {
+ if( *it < nFontLen - 6 )
+ nLength3 -= 6;
+ else // the last section 0x8003 is only 2 bytes after all
+ nLength3 -= (nFontLen - *it);
+ }
+ }
+ }
+
+ // there may be whitespace to ignore before the 512 '0'
+ while( pFontData[nIndex] == '\r' || pFontData[nIndex] == '\n' )
+ {
+ nIndex--;
+ for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
+ ;
+ if( it != aSections.end() )
+ {
+ nIndex = (*it)-1;
+ break; // this is surely a binary boundary, in ascii case it wouldn't matter
+ }
+ }
+ nEndBinaryIndex = nIndex;
+
+ // search for beginning of binary section
+ nBeginBinaryIndex = nEndAsciiIndex;
+ do
+ {
+ nBeginBinaryIndex++;
+ for( it = aSections.begin(); it != aSections.end() && (nBeginBinaryIndex < *it || nBeginBinaryIndex > ((*it) + 5) ); ++it )
+ ;
+ } while( nBeginBinaryIndex < nEndBinaryIndex &&
+ ( pFontData[nBeginBinaryIndex] == '\r' ||
+ pFontData[nBeginBinaryIndex] == '\n' ||
+ it != aSections.end() ) );
+
+ // it seems to be vital to copy the exact whitespace between binary data
+ // and eexec, else a invalid font results. so make nEndAsciiIndex
+ // always immediate in front of nBeginBinaryIndex
+ nEndAsciiIndex = nBeginBinaryIndex-1;
+ for( it = aSections.begin(); it != aSections.end() && (nEndAsciiIndex < *it || nEndAsciiIndex > ((*it)+5)); ++it )
+ ;
+ if( it != aSections.end() )
+ nEndAsciiIndex = (*it)-1;
+
+ nLength1 = nEndAsciiIndex+1; // including the last character
+ for( it = aSections.begin(); it != aSections.end() && *it < nEndAsciiIndex; ++it )
+ nLength1 -= 6; // decrease by pfb section size
+
+ // if the first four bytes are all ascii hex characters, then binary data
+ // has to be converted to real binary data
+ for( nIndex = 0; nIndex < 4 &&
+ ( ( pFontData[ nBeginBinaryIndex+nIndex ] >= '0' && pFontData[ nBeginBinaryIndex+nIndex ] <= '9' ) ||
+ ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'a' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'f' ) ||
+ ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'A' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'F' )
+ ); ++nIndex )
+ ;
+ bool bConvertHexData = true;
+ if( nIndex < 4 )
+ {
+ bConvertHexData = false;
+ nLength2 = nEndBinaryIndex - nBeginBinaryIndex + 1; // include the last byte
+ for( it = aSections.begin(); it != aSections.end(); ++it )
+ if( *it > nBeginBinaryIndex && *it < nEndBinaryIndex )
+ nLength2 -= 6;
+ }
+ else
+ {
+ // count the hex ascii characters to get nLength2
+ nLength2 = 0;
+ int nNextSectionIndex = 0;
+ for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
+ ;
+ if( it != aSections.end() )
+ nNextSectionIndex = *it;
+ for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
+ {
+ if( nIndex == nNextSectionIndex )
+ {
+ nIndex += 6;
+ ++it;
+ nNextSectionIndex = (it == aSections.end() ? 0 : *it );
+ }
+ if( ( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) ||
+ ( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) ||
+ ( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) )
+ nLength2++;
+ }
+ DBG_ASSERT( !(nLength2 & 1), "uneven number of hex chars in binary pfa section" );
+ nLength2 /= 2;
+ }
+
+ // now we can actually write the font stream !
+ #if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( " PDFWriterImpl::emitEmbeddedFont" );
+ emitComment( aLine.getStr() );
+ }
+ #endif
+ OStringBuffer aLine( 512 );
+ nStreamObject = createObject();
+ if( !updateObject(nStreamObject))
+ throw FontException();
+ sal_Int32 nStreamLengthObject = createObject();
+ aLine.append( nStreamObject );
+ aLine.append( " 0 obj\n"
+ "<</Length " );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 R"
+ #ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ "/Filter/FlateDecode"
+ #endif
+ "/Length1 " );
+ aLine.append( nLength1 );
+ aLine.append( " /Length2 " );
+ aLine.append( nLength2 );
+ aLine.append( " /Length3 ");
+ aLine.append( nLength3 );
+ aLine.append( ">>\n"
+ "stream\n" );
+ if( !writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ throw FontException();
+
+ sal_uInt64 nBeginStreamPos = 0;
+ osl_getFilePos( m_aFile, &nBeginStreamPos );
+
+ beginCompression();
+ checkAndEnableStreamEncryption( nStreamObject );
+
+ // write ascii section
+ if( aSections.begin() == aSections.end() )
+ {
+ if( ! writeBuffer( pFontData, nEndAsciiIndex+1 ) )
+ throw FontException();
+ }
+ else
+ {
+ // first section always starts at 0
+ it = aSections.begin();
+ nIndex = (*it)+6;
+ ++it;
+ while( *it < nEndAsciiIndex )
+ {
+ if( ! writeBuffer( pFontData+nIndex, (*it)-nIndex ) )
+ throw FontException();
+ nIndex = (*it)+6;
+ ++it;
+ }
+ // write partial last section
+ if( ! writeBuffer( pFontData+nIndex, nEndAsciiIndex-nIndex+1 ) )
+ throw FontException();
+ }
+
+ // write binary section
+ if( ! bConvertHexData )
+ {
+ if( aSections.begin() == aSections.end() )
+ {
+ if( ! writeBuffer( pFontData+nBeginBinaryIndex, nFontLen-nBeginBinaryIndex ) )
+ throw FontException();
+ }
+ else
+ {
+ for( it = aSections.begin(); *it < nBeginBinaryIndex; ++it )
+ ;
+ // write first partial section
+ if( ! writeBuffer( pFontData+nBeginBinaryIndex, (*it) - nBeginBinaryIndex ) )
+ throw FontException();
+ // write following sections
+ while( it != aSections.end() )
+ {
+ nIndex = (*it)+6;
+ ++it;
+ if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
+ {
+ sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
+ if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
+ throw FontException();
+ }
+ }
+ }
+ }
+ else
+ {
+ boost::shared_array<unsigned char> pWriteBuffer( new unsigned char[ nLength2 ] );
+ rtl_zeroMemory( pWriteBuffer.get(), nLength2 );
+ int nWriteIndex = 0;
+
+ int nNextSectionIndex = 0;
+ for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
+ ;
+ if( it != aSections.end() )
+ nNextSectionIndex = *it;
+ for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
+ {
+ if( nIndex == nNextSectionIndex )
+ {
+ nIndex += 6;
+ ++it;
+ nNextSectionIndex = (it == aSections.end() ? nFontLen : *it );
+ }
+ unsigned char cNibble = 0x80;
+ if( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' )
+ cNibble = pFontData[nIndex] - '0';
+ else if( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' )
+ cNibble = pFontData[nIndex] - 'a' + 10;
+ else if( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' )
+ cNibble = pFontData[nIndex] - 'A' + 10;
+ if( cNibble != 0x80 )
+ {
+ if( !(nWriteIndex & 1 ) )
+ cNibble <<= 4;
+ pWriteBuffer.get()[ nWriteIndex/2 ] |= cNibble;
+ nWriteIndex++;
+ }
+ }
+ if( ! writeBuffer( pWriteBuffer.get(), nLength2 ) )
+ throw FontException();
+ if( aSections.empty() )
+ {
+ if( ! writeBuffer( pFontData+nIndex, nFontLen-nIndex ) )
+ throw FontException();
+ }
+ else
+ {
+ // write rest of this section
+ if( nIndex < nNextSectionIndex )
+ {
+ if( ! writeBuffer( pFontData+nIndex, nNextSectionIndex - nIndex ) )
+ throw FontException();
+ }
+ // write following sections
+ while( it != aSections.end() )
+ {
+ nIndex = (*it)+6;
+ ++it;
+ if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
+ {
+ sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
+ if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
+ throw FontException();
+ }
+ }
+ }
+ }
+ endCompression();
+ disableStreamEncryption();
+
+
+ sal_uInt64 nEndStreamPos = 0;
+ osl_getFilePos( m_aFile, &nEndStreamPos );
+
+ // and finally close the stream
+ aLine.setLength( 0 );
+ aLine.append( "\nendstream\nendobj\n\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ throw FontException();
+
+ // write stream length object
+ aLine.setLength( 0 );
+ if( ! updateObject( nStreamLengthObject ) )
+ throw FontException();
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos ) );
+ aLine.append( "\nendobj\n\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ throw FontException();
+ }
+ else
+ {
+ rtl::OStringBuffer aErrorComment( 256 );
+ aErrorComment.append( "GetEmbedFontData failed for font \"" );
+ aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
+ aErrorComment.append( '\"' );
+ if( pFont->GetSlant() == ITALIC_NORMAL )
+ aErrorComment.append( " italic" );
+ else if( pFont->GetSlant() == ITALIC_OBLIQUE )
+ aErrorComment.append( " oblique" );
+ aErrorComment.append( " weight=" );
+ aErrorComment.append( sal_Int32(pFont->GetWeight()) );
+ emitComment( aErrorComment.getStr() );
+ }
+
+ if( nStreamObject )
+ // write font descriptor
+ nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, nStreamObject );
+
+ if( nFontDescriptor )
+ {
+ if( pEncoding )
+ nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, sizeof(nEncoding)/sizeof(nEncoding[0]) );
+
+ // write font object
+ sal_Int32 nObject = createObject();
+ if( ! updateObject( nObject ) )
+ throw FontException();
+
+ OStringBuffer aLine( 1024 );
+ aLine.append( nObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/Font/Subtype/Type1/BaseFont/" );
+ appendName( aInfo.m_aPSName, aLine );
+ aLine.append( "\n" );
+ if( !pFont->mbSymbolFlag && pEncoding == 0 )
+ aLine.append( "/Encoding/WinAnsiEncoding\n" );
+ if( nToUnicodeStream )
+ {
+ aLine.append( "/ToUnicode " );
+ aLine.append( nToUnicodeStream );
+ aLine.append( " 0 R\n" );
+ }
+ aLine.append( "/FirstChar 0 /LastChar 255\n"
+ "/Widths[" );
+ for( int i = 0; i < 256; i++ )
+ {
+ aLine.append( pWidths[i] );
+ aLine.append( ((i&15) == 15) ? "\n" : " " );
+ }
+ aLine.append( "]\n"
+ "/FontDescriptor " );
+ aLine.append( nFontDescriptor );
+ aLine.append( " 0 R>>\n"
+ "endobj\n\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ throw FontException();
+
+ nFontObject = nObject;
+
+ aRet[ rEmbed.m_nNormalFontID ] = nObject;
+
+ // write additional encodings
+ for( std::list< EmbedEncoding >::iterator enc_it = rEmbed.m_aExtendedEncodings.begin(); enc_it != rEmbed.m_aExtendedEncodings.end(); ++enc_it )
+ {
+ sal_Int32 aEncWidths[ 256 ];
+ // emit encoding dict
+ sal_Int32 nEncObject = createObject();
+ if( ! updateObject( nEncObject ) )
+ throw FontException();
+
+ OutputDevice* pRef = getReferenceDevice();
+ pRef->Push( PUSH_FONT | PUSH_MAPMODE );
+ pRef->SetMapMode( MapMode( MAP_PIXEL ) );
+ Font aFont( pFont->GetFamilyName(), pFont->GetStyleName(), Size( 0, 1000 ) );
+ aFont.SetWeight( pFont->GetWeight() );
+ aFont.SetItalic( pFont->GetSlant() );
+ aFont.SetPitch( pFont->GetPitch() );
+ pRef->SetFont( aFont );
+ pRef->ImplNewFont();
+
+ aLine.setLength( 0 );
+ aLine.append( nEncObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/Encoding/Differences[ 0\n" );
+ int nEncoded = 0;
+ aUnicodes.clear();
+ for( std::vector< EmbedCode >::iterator str_it = enc_it->m_aEncVector.begin(); str_it != enc_it->m_aEncVector.end(); ++str_it )
+ {
+ String aStr( str_it->m_aUnicode );
+ aEncWidths[nEncoded] = pRef->GetTextWidth( aStr );
+ nEncodedCodes[nEncoded] = str_it->m_aUnicode;
+ nEncoding[nEncoded] = sal::static_int_cast<sal_uInt8>(nEncoded);
+ pEncToUnicodeIndex[nEncoded] = static_cast<sal_Int32>(aUnicodes.size());
+ aUnicodes.push_back( nEncodedCodes[nEncoded] );
+ pUnicodesPerGlyph[nEncoded] = 1;
+
+ aLine.append( " /" );
+ aLine.append( str_it->m_aName );
+ if( !((++nEncoded) & 15) )
+ aLine.append( "\n" );
+ }
+ aLine.append( "]>>\n"
+ "endobj\n\n" );
+
+ pRef->Pop();
+
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ throw FontException();
+
+ nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nEncoded );
+
+ nObject = createObject();
+ if( ! updateObject( nObject ) )
+ throw FontException();
+
+ aLine.setLength( 0 );
+ aLine.append( nObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/Font/Subtype/Type1/BaseFont/" );
+ appendName( aInfo.m_aPSName, aLine );
+ aLine.append( "\n" );
+ aLine.append( "/Encoding " );
+ aLine.append( nEncObject );
+ aLine.append( " 0 R\n" );
+ if( nToUnicodeStream )
+ {
+ aLine.append( "/ToUnicode " );
+ aLine.append( nToUnicodeStream );
+ aLine.append( " 0 R\n" );
+ }
+ aLine.append( "/FirstChar 0\n"
+ "/LastChar " );
+ aLine.append( (sal_Int32)(nEncoded-1) );
+ aLine.append( "\n"
+ "/Widths[" );
+ for( int i = 0; i < nEncoded; i++ )
+ {
+ aLine.append( aEncWidths[i] );
+ aLine.append( ((i&15) == 15) ? "\n" : " " );
+ }
+ aLine.append( " ]\n"
+ "/FontDescriptor " );
+ aLine.append( nFontDescriptor );
+ aLine.append( " 0 R>>\n"
+ "endobj\n\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ throw FontException();
+
+ aRet[ enc_it->m_nFontID ] = nObject;
+ }
+ }
+ }
+ catch( FontException& )
+ {
+ // these do nothing in case there was no compression or encryption ongoing
+ endCompression();
+ disableStreamEncryption();
+ }
+
+ if( pFontData )
+ m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen );
+
+ return aRet;
+}
+
+static void appendSubsetName( int nSubsetID, const OUString& rPSName, OStringBuffer& rBuffer )
+{
+ if( nSubsetID )
+ {
+ for( int i = 0; i < 6; i++ )
+ {
+ int nOffset = (nSubsetID % 26);
+ nSubsetID /= 26;
+ rBuffer.append( (sal_Char)('A'+nOffset) );
+ }
+ rBuffer.append( '+' );
+ }
+ appendName( rPSName, rBuffer );
+}
+
+sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding,
+ sal_Ucs* pUnicodes,
+ sal_Int32* pUnicodesPerGlyph,
+ sal_Int32* pEncToUnicodeIndex,
+ int nGlyphs )
+{
+ int nMapped = 0, n = 0;
+ for( n = 0; n < nGlyphs; n++ )
+ if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
+ nMapped++;
+
+ if( nMapped == 0 )
+ return 0;
+
+ sal_Int32 nStream = createObject();
+ CHECK_RETURN( updateObject( nStream ) );
+
+ OStringBuffer aContents( 1024 );
+ aContents.append(
+ "/CIDInit/ProcSet findresource begin\n"
+ "12 dict begin\n"
+ "begincmap\n"
+ "/CIDSystemInfo<<\n"
+ "/Registry (Adobe)\n"
+ "/Ordering (UCS)\n"
+ "/Supplement 0\n"
+ ">> def\n"
+ "/CMapName/Adobe-Identity-UCS def\n"
+ "/CMapType 2 def\n"
+ "1 begincodespacerange\n"
+ "<00> <FF>\n"
+ "endcodespacerange\n"
+ );
+ int nCount = 0;
+ for( n = 0; n < nGlyphs; n++ )
+ {
+ if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
+ {
+ if( (nCount % 100) == 0 )
+ {
+ if( nCount )
+ aContents.append( "endbfchar\n" );
+ aContents.append( (sal_Int32)((nMapped-nCount > 100) ? 100 : nMapped-nCount ) );
+ aContents.append( " beginbfchar\n" );
+ }
+ aContents.append( '<' );
+ appendHex( (sal_Int8)pEncoding[n], aContents );
+ aContents.append( "> <" );
+ // TODO: handle unicodes>U+FFFF
+ sal_Int32 nIndex = pEncToUnicodeIndex[n];
+ for( sal_Int32 j = 0; j < pUnicodesPerGlyph[n]; j++ )
+ {
+ appendHex( (sal_Int8)(pUnicodes[nIndex + j] / 256), aContents );
+ appendHex( (sal_Int8)(pUnicodes[nIndex + j] & 255), aContents );
+ }
+ aContents.append( ">\n" );
+ nCount++;
+ }
+ }
+ aContents.append( "endbfchar\n"
+ "endcmap\n"
+ "CMapName currentdict /CMap defineresource pop\n"
+ "end\n"
+ "end\n" );
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 );
+ SvMemoryStream aStream;
+ pCodec->BeginCompression();
+ pCodec->Write( aStream, (const BYTE*)aContents.getStr(), aContents.getLength() );
+ pCodec->EndCompression();
+ delete pCodec;
+#endif
+
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( " PDFWriterImpl::createToUnicodeCMap" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+ OStringBuffer aLine( 40 );
+
+ aLine.append( nStream );
+ aLine.append( " 0 obj\n<</Length " );
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ sal_Int32 nLen = (sal_Int32)aStream.Tell();
+ aStream.Seek( 0 );
+ aLine.append( nLen );
+ aLine.append( "/Filter/FlateDecode" );
+#else
+ aLine.append( aContents.getLength() );
+#endif
+ aLine.append( ">>\nstream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ checkAndEnableStreamEncryption( nStream );
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ CHECK_RETURN( writeBuffer( aStream.GetData(), nLen ) );
+#else
+ CHECK_RETURN( writeBuffer( aContents.getStr(), aContents.getLength() ) );
+#endif
+ disableStreamEncryption();
+ aLine.setLength( 0 );
+ aLine.append( "\nendstream\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ return nStream;
+}
+
+sal_Int32 PDFWriterImpl::emitFontDescriptor( const ImplFontData* pFont, FontSubsetInfo& rInfo, sal_Int32 nSubsetID, sal_Int32 nFontStream )
+{
+ OStringBuffer aLine( 1024 );
+ // get font flags, see PDF reference 1.4 p. 358
+ // possibly characters outside Adobe standard encoding
+ // so set Symbolic flag
+ sal_Int32 nFontFlags = (1<<2);
+ if( pFont->GetSlant() == ITALIC_NORMAL || pFont->GetSlant() == ITALIC_OBLIQUE )
+ nFontFlags |= (1 << 6);
+ if( pFont->GetPitch() == PITCH_FIXED )
+ nFontFlags |= 1;
+ if( pFont->GetFamilyType() == FAMILY_SCRIPT )
+ nFontFlags |= (1 << 3);
+ else if( pFont->GetFamilyType() == FAMILY_ROMAN )
+ nFontFlags |= (1 << 1);
+
+ sal_Int32 nFontDescriptor = createObject();
+ CHECK_RETURN( updateObject( nFontDescriptor ) );
+ aLine.setLength( 0 );
+ aLine.append( nFontDescriptor );
+ aLine.append( " 0 obj\n"
+ "<</Type/FontDescriptor/FontName/" );
+ appendSubsetName( nSubsetID, rInfo.m_aPSName, aLine );
+ aLine.append( "\n"
+ "/Flags " );
+ aLine.append( nFontFlags );
+ aLine.append( "\n"
+ "/FontBBox[" );
+ // note: Top and Bottom are reversed in VCL and PDF rectangles
+ aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().X() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().Y() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)rInfo.m_aFontBBox.BottomRight().X() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)(rInfo.m_aFontBBox.BottomRight().Y()+1) );
+ aLine.append( "]/ItalicAngle " );
+ if( pFont->GetSlant() == ITALIC_OBLIQUE || pFont->GetSlant() == ITALIC_NORMAL )
+ aLine.append( "-30" );
+ else
+ aLine.append( "0" );
+ aLine.append( "\n"
+ "/Ascent " );
+ aLine.append( (sal_Int32)rInfo.m_nAscent );
+ aLine.append( "\n"
+ "/Descent " );
+ aLine.append( (sal_Int32)-rInfo.m_nDescent );
+ aLine.append( "\n"
+ "/CapHeight " );
+ aLine.append( (sal_Int32)rInfo.m_nCapHeight );
+ // According to PDF reference 1.4 StemV is required
+ // seems a tad strange to me, but well ...
+ aLine.append( "\n"
+ "/StemV 80\n" );
+ if( nFontStream )
+ {
+ aLine.append( "/FontFile" );
+ switch( rInfo.m_nFontType )
+ {
+ case FontSubsetInfo::SFNT_TTF:
+ aLine.append( '2' );
+ break;
+ case FontSubsetInfo::TYPE1_PFA:
+ case FontSubsetInfo::TYPE1_PFB:
+ case FontSubsetInfo::ANY_TYPE1:
+ break;
+ default:
+ DBG_ERROR( "unknown fonttype in PDF font descriptor" );
+ return 0;
+ }
+ aLine.append( ' ' );
+ aLine.append( nFontStream );
+ aLine.append( " 0 R\n" );
+ }
+ aLine.append( ">>\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ return nFontDescriptor;
+}
+
+void PDFWriterImpl::appendBuiltinFontsToDict( OStringBuffer& rDict ) const
+{
+ for( std::map< sal_Int32, sal_Int32 >::const_iterator it =
+ m_aBuiltinFontToObjectMap.begin(); it != m_aBuiltinFontToObjectMap.end(); ++it )
+ {
+ rDict.append( m_aBuiltinFonts[it->first].getNameObject() );
+ rDict.append( ' ' );
+ rDict.append( it->second );
+ rDict.append( " 0 R" );
+ }
+}
+
+bool PDFWriterImpl::emitFonts()
+{
+ if( ! m_pReferenceDevice->ImplGetGraphics() )
+ return false;
+
+ OStringBuffer aLine( 1024 );
+
+ std::map< sal_Int32, sal_Int32 > aFontIDToObject;
+
+ OUString aTmpName;
+ osl_createTempFile( NULL, NULL, &aTmpName.pData );
+ for( FontSubsetData::iterator it = m_aSubsets.begin(); it != m_aSubsets.end(); ++it )
+ {
+ for( FontEmitList::iterator lit = it->second.m_aSubsets.begin(); lit != it->second.m_aSubsets.end(); ++lit )
+ {
+ sal_Int32 pGlyphIDs[ 256 ];
+ sal_Int32 pWidths[ 256 ];
+ sal_uInt8 pEncoding[ 256 ];
+ sal_Int32 pEncToUnicodeIndex[ 256 ];
+ sal_Int32 pUnicodesPerGlyph[ 256 ];
+ std::vector<sal_Ucs> aUnicodes;
+ aUnicodes.reserve( 256 );
+ int nGlyphs = 1;
+ // fill arrays and prepare encoding index map
+ sal_Int32 nToUnicodeStream = 0;
+
+ rtl_zeroMemory( pGlyphIDs, sizeof( pGlyphIDs ) );
+ rtl_zeroMemory( pEncoding, sizeof( pEncoding ) );
+ rtl_zeroMemory( pUnicodesPerGlyph, sizeof( pUnicodesPerGlyph ) );
+ rtl_zeroMemory( pEncToUnicodeIndex, sizeof( pEncToUnicodeIndex ) );
+ for( FontEmitMapping::iterator fit = lit->m_aMapping.begin(); fit != lit->m_aMapping.end();++fit )
+ {
+ sal_uInt8 nEnc = fit->second.getGlyphId();
+
+ DBG_ASSERT( pGlyphIDs[nEnc] == 0 && pEncoding[nEnc] == 0, "duplicate glyph" );
+ DBG_ASSERT( nEnc <= lit->m_aMapping.size(), "invalid glyph encoding" );
+
+ pGlyphIDs[ nEnc ] = fit->first;
+ pEncoding[ nEnc ] = nEnc;
+ pEncToUnicodeIndex[ nEnc ] = static_cast<sal_Int32>(aUnicodes.size());
+ pUnicodesPerGlyph[ nEnc ] = fit->second.countCodes();
+ for( sal_Int32 n = 0; n < pUnicodesPerGlyph[ nEnc ]; n++ )
+ aUnicodes.push_back( fit->second.getCode( n ) );
+ if( fit->second.getCode(0) )
+ nToUnicodeStream = 1;
+ if( nGlyphs < 256 )
+ nGlyphs++;
+ else
+ {
+ DBG_ERROR( "too many glyphs for subset" );
+ }
+ }
+ FontSubsetInfo aSubsetInfo;
+ if( m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, it->first, pGlyphIDs, pEncoding, pWidths, nGlyphs, aSubsetInfo ) )
+ {
+ // create font stream
+ oslFileHandle aFontFile;
+ CHECK_RETURN( (osl_File_E_None == osl_openFile( aTmpName.pData, &aFontFile, osl_File_OpenFlag_Read ) ) );
+ // get file size
+ sal_uInt64 nLength1;
+ CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_End, 0 ) ) );
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( aFontFile, &nLength1 ) ) );
+ CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) );
+
+ #if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine1( " PDFWriterImpl::emitFonts" );
+ emitComment( aLine1.getStr() );
+ }
+ #endif
+ sal_Int32 nFontStream = createObject();
+ sal_Int32 nStreamLengthObject = createObject();
+ CHECK_RETURN( updateObject( nFontStream ) );
+ aLine.setLength( 0 );
+ aLine.append( nFontStream );
+ aLine.append( " 0 obj\n"
+ "<</Length " );
+ aLine.append( (sal_Int32)nStreamLengthObject );
+ aLine.append( " 0 R"
+ #ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ "/Filter/FlateDecode"
+ #endif
+ "/Length1 " );
+
+ sal_uInt64 nStartPos = 0;
+ if( aSubsetInfo.m_nFontType == FontSubsetInfo::SFNT_TTF )
+ {
+ aLine.append( (sal_Int32)nLength1 );
+
+ aLine.append( ">>\n"
+ "stream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) );
+
+ // copy font file
+ beginCompression();
+ checkAndEnableStreamEncryption( nFontStream );
+ sal_Bool bEOF = sal_False;
+ do
+ {
+ char buf[8192];
+ sal_uInt64 nRead;
+ CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, buf, sizeof( buf ), &nRead ) ) );
+ CHECK_RETURN( writeBuffer( buf, nRead ) );
+ CHECK_RETURN( (osl_File_E_None == osl_isEndOfFile( aFontFile, &bEOF ) ) );
+ } while( ! bEOF );
+ }
+ else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::CFF_FONT) != 0 )
+ {
+ // TODO: implement
+ DBG_ERROR( "PDFWriterImpl does not support CFF-font subsets yet!" );
+ }
+ else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::TYPE1_PFB) != 0 ) // TODO: also support PFA?
+ {
+ boost::shared_array<unsigned char> pBuffer( new unsigned char[ nLength1 ] );
+
+ sal_uInt64 nBytesRead = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, pBuffer.get(), nLength1, &nBytesRead ) ) );
+ DBG_ASSERT( nBytesRead==nLength1, "PDF-FontSubset read incomplete!" );
+ CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) );
+ // get the PFB-segment lengths
+ ThreeInts aSegmentLengths = {0,0,0};
+ getPfbSegmentLengths( pBuffer.get(), (int)nBytesRead, aSegmentLengths );
+ // the lengths below are mandatory for PDF-exported Type1 fonts
+ // because the PFB segment headers get stripped! WhyOhWhy.
+ aLine.append( (sal_Int32)aSegmentLengths[0] );
+ aLine.append( "/Length2 " );
+ aLine.append( (sal_Int32)aSegmentLengths[1] );
+ aLine.append( "/Length3 " );
+ aLine.append( (sal_Int32)aSegmentLengths[2] );
+
+ aLine.append( ">>\n"
+ "stream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) );
+
+ // emit PFB-sections without section headers
+ beginCompression();
+ checkAndEnableStreamEncryption( nFontStream );
+ CHECK_RETURN( writeBuffer( &pBuffer[6], aSegmentLengths[0] ) );
+ CHECK_RETURN( writeBuffer( &pBuffer[12] + aSegmentLengths[0], aSegmentLengths[1] ) );
+ CHECK_RETURN( writeBuffer( &pBuffer[18] + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) );
+ }
+ else
+ {
+ fprintf( stderr, "PDF: CreateFontSubset result in not yet supported format=%d\n",aSubsetInfo.m_nFontType);
+ aLine.append( "0 >>\nstream\n" );
+ }
+
+ endCompression();
+ disableStreamEncryption();
+ // close the file
+ osl_closeFile( aFontFile );
+
+ sal_uInt64 nEndPos = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos ) ) );
+ // end the stream
+ aLine.setLength( 0 );
+ aLine.append( "\nendstream\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ // emit stream length object
+ CHECK_RETURN( updateObject( nStreamLengthObject ) );
+ aLine.setLength( 0 );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( (sal_Int64)(nEndPos-nStartPos) );
+ aLine.append( "\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ // write font descriptor
+ sal_Int32 nFontDescriptor = emitFontDescriptor( it->first, aSubsetInfo, lit->m_nFontID, nFontStream );
+
+ if( nToUnicodeStream )
+ nToUnicodeStream = createToUnicodeCMap( pEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nGlyphs );
+
+ sal_Int32 nFontObject = createObject();
+ CHECK_RETURN( updateObject( nFontObject ) );
+ aLine.setLength( 0 );
+ aLine.append( nFontObject );
+
+ aLine.append( " 0 obj\n" );
+ aLine.append( ((aSubsetInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) != 0) ?
+ "<</Type/Font/Subtype/Type1/BaseFont/" :
+ "<</Type/Font/Subtype/TrueType/BaseFont/" );
+ appendSubsetName( lit->m_nFontID, aSubsetInfo.m_aPSName, aLine );
+ aLine.append( "\n"
+ "/FirstChar 0\n"
+ "/LastChar " );
+ aLine.append( (sal_Int32)(nGlyphs-1) );
+ aLine.append( "\n"
+ "/Widths[" );
+ for( int i = 0; i < nGlyphs; i++ )
+ {
+ aLine.append( pWidths[ i ] );
+ aLine.append( ((i & 15) == 15) ? "\n" : " " );
+ }
+ aLine.append( "]\n"
+ "/FontDescriptor " );
+ aLine.append( nFontDescriptor );
+ aLine.append( " 0 R\n" );
+ if( nToUnicodeStream )
+ {
+ aLine.append( "/ToUnicode " );
+ aLine.append( nToUnicodeStream );
+ aLine.append( " 0 R\n" );
+ }
+ aLine.append( ">>\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ aFontIDToObject[ lit->m_nFontID ] = nFontObject;
+ }
+ else
+ {
+ const ImplFontData* pFont = it->first;
+ rtl::OStringBuffer aErrorComment( 256 );
+ aErrorComment.append( "CreateFontSubset failed for font \"" );
+ aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
+ aErrorComment.append( '\"' );
+ if( pFont->GetSlant() == ITALIC_NORMAL )
+ aErrorComment.append( " italic" );
+ else if( pFont->GetSlant() == ITALIC_OBLIQUE )
+ aErrorComment.append( " oblique" );
+ aErrorComment.append( " weight=" );
+ aErrorComment.append( sal_Int32(pFont->GetWeight()) );
+ emitComment( aErrorComment.getStr() );
+ }
+ }
+ }
+ osl_removeFile( aTmpName.pData );
+
+ // emit embedded fonts
+ for( FontEmbedData::iterator eit = m_aEmbeddedFonts.begin(); eit != m_aEmbeddedFonts.end(); ++eit )
+ {
+ std::map< sal_Int32, sal_Int32 > aObjects = emitEmbeddedFont( eit->first, eit->second );
+ for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
+ {
+ CHECK_RETURN( fit->second );
+ aFontIDToObject[ fit->first ] = fit->second;
+ }
+ }
+
+ // emit system fonts
+ for( FontEmbedData::iterator sit = m_aSystemFonts.begin(); sit != m_aSystemFonts.end(); ++sit )
+ {
+ std::map< sal_Int32, sal_Int32 > aObjects = emitSystemFont( sit->first, sit->second );
+ for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
+ {
+ CHECK_RETURN( fit->second );
+ aFontIDToObject[ fit->first ] = fit->second;
+ }
+ }
+
+ OStringBuffer aFontDict( 1024 );
+ aFontDict.append( getFontDictObject() );
+ aFontDict.append( " 0 obj\n"
+ "<<" );
+ int ni = 0;
+ for( std::map< sal_Int32, sal_Int32 >::iterator mit = aFontIDToObject.begin(); mit != aFontIDToObject.end(); ++mit )
+ {
+ aFontDict.append( "/F" );
+ aFontDict.append( mit->first );
+ aFontDict.append( ' ' );
+ aFontDict.append( mit->second );
+ aFontDict.append( " 0 R" );
+ if( ((++ni) & 7) == 0 )
+ aFontDict.append( '\n' );
+ }
+ // emit builtin font for widget apperances / variable text
+ for( std::map< sal_Int32, sal_Int32 >::iterator it = m_aBuiltinFontToObjectMap.begin();
+ it != m_aBuiltinFontToObjectMap.end(); ++it )
+ {
+ ImplPdfBuiltinFontData aData(m_aBuiltinFonts[it->first]);
+ it->second = emitBuiltinFont( &aData, it->second );
+ }
+ appendBuiltinFontsToDict( aFontDict );
+ aFontDict.append( "\n>>\nendobj\n\n" );
+
+ CHECK_RETURN( updateObject( getFontDictObject() ) );
+ CHECK_RETURN( writeBuffer( aFontDict.getStr(), aFontDict.getLength() ) );
+ return true;
+}
+
+sal_Int32 PDFWriterImpl::emitResources()
+{
+ // emit shadings
+ if( ! m_aGradients.empty() )
+ CHECK_RETURN( emitGradients() );
+ // emit tilings
+ if( ! m_aTilings.empty() )
+ CHECK_RETURN( emitTilings() );
+
+ // emit font dict
+ CHECK_RETURN( emitFonts() );
+
+ // emit Resource dict
+ OStringBuffer aLine( 512 );
+ sal_Int32 nResourceDict = getResourceDictObj();
+ CHECK_RETURN( updateObject( nResourceDict ) );
+ aLine.setLength( 0 );
+ aLine.append( nResourceDict );
+ aLine.append( " 0 obj\n" );
+ m_aGlobalResourceDict.append( aLine, getFontDictObject() );
+ aLine.append( "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ return nResourceDict;
+}
+
+sal_Int32 PDFWriterImpl::updateOutlineItemCount( std::vector< sal_Int32 >& rCounts,
+ sal_Int32 nItemLevel,
+ sal_Int32 nCurrentItemId )
+{
+ /* The /Count number of an item is
+ positive: the number of visible subitems
+ negative: the negative number of subitems that will become visible if
+ the item gets opened
+ see PDF ref 1.4 p 478
+ */
+
+ sal_Int32 nCount = 0;
+
+ if( m_aContext.OpenBookmarkLevels < 0 || // all levels arevisible
+ m_aContext.OpenBookmarkLevels >= nItemLevel // this level is visible
+ )
+ {
+ PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
+ sal_Int32 nChildren = rItem.m_aChildren.size();
+ for( sal_Int32 i = 0; i < nChildren; i++ )
+ nCount += updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
+ rCounts[nCurrentItemId] = nCount;
+ // return 1 (this item) + visible sub items
+ if( nCount < 0 )
+ nCount = 0;
+ nCount++;
+ }
+ else
+ {
+ // this bookmark level is invisible
+ PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
+ sal_Int32 nChildren = rItem.m_aChildren.size();
+ rCounts[ nCurrentItemId ] = -sal_Int32(rItem.m_aChildren.size());
+ for( sal_Int32 i = 0; i < nChildren; i++ )
+ updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
+ nCount = -1;
+ }
+
+ return nCount;
+}
+
+sal_Int32 PDFWriterImpl::emitOutline()
+{
+ int i, nItems = m_aOutline.size();
+
+ // do we have an outline at all ?
+ if( nItems < 2 )
+ return 0;
+
+ // reserve object numbers for all outline items
+ for( i = 0; i < nItems; ++i )
+ m_aOutline[i].m_nObject = createObject();
+
+ // update all parent, next and prev object ids
+ for( i = 0; i < nItems; ++i )
+ {
+ PDFOutlineEntry& rItem = m_aOutline[i];
+ int nChildren = rItem.m_aChildren.size();
+
+ if( nChildren )
+ {
+ for( int n = 0; n < nChildren; ++n )
+ {
+ PDFOutlineEntry& rChild = m_aOutline[ rItem.m_aChildren[n] ];
+
+ rChild.m_nParentObject = rItem.m_nObject;
+ rChild.m_nPrevObject = (n > 0) ? m_aOutline[ rItem.m_aChildren[n-1] ].m_nObject : 0;
+ rChild.m_nNextObject = (n < nChildren-1) ? m_aOutline[ rItem.m_aChildren[n+1] ].m_nObject : 0;
+ }
+
+ }
+ }
+
+ // calculate Count entries for all items
+ std::vector< sal_Int32 > aCounts( nItems );
+ updateOutlineItemCount( aCounts, 0, 0 );
+
+ // emit hierarchy
+ for( i = 0; i < nItems; ++i )
+ {
+ PDFOutlineEntry& rItem = m_aOutline[i];
+ OStringBuffer aLine( 1024 );
+
+ CHECK_RETURN( updateObject( rItem.m_nObject ) );
+ aLine.append( rItem.m_nObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( "<<" );
+ // number of visible children (all levels)
+ if( i > 0 || aCounts[0] > 0 )
+ {
+ aLine.append( "/Count " );
+ aLine.append( aCounts[i] );
+ }
+ if( ! rItem.m_aChildren.empty() )
+ {
+ // children list: First, Last
+ aLine.append( "/First " );
+ aLine.append( m_aOutline[rItem.m_aChildren.front()].m_nObject );
+ aLine.append( " 0 R/Last " );
+ aLine.append( m_aOutline[rItem.m_aChildren.back()].m_nObject );
+ aLine.append( " 0 R\n" );
+ }
+ if( i > 0 )
+ {
+ // Title, Dest, Parent, Prev, Next
+ aLine.append( "/Title" );
+ appendUnicodeTextStringEncrypt( rItem.m_aTitle, rItem.m_nObject, aLine );
+ aLine.append( "\n" );
+ // Dest is not required
+ if( rItem.m_nDestID >= 0 && rItem.m_nDestID < (sal_Int32)m_aDests.size() )
+ {
+ aLine.append( "/Dest" );
+ appendDest( rItem.m_nDestID, aLine );
+ }
+ aLine.append( "/Parent " );
+ aLine.append( rItem.m_nParentObject );
+ aLine.append( " 0 R" );
+ if( rItem.m_nPrevObject )
+ {
+ aLine.append( "/Prev " );
+ aLine.append( rItem.m_nPrevObject );
+ aLine.append( " 0 R" );
+ }
+ if( rItem.m_nNextObject )
+ {
+ aLine.append( "/Next " );
+ aLine.append( rItem.m_nNextObject );
+ aLine.append( " 0 R" );
+ }
+ }
+ aLine.append( ">>\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
+ return m_aOutline[0].m_nObject;
+}
+
+#undef CHECK_RETURN
+#define CHECK_RETURN( x ) if( !x ) return false
+
+bool PDFWriterImpl::appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer )
+{
+ if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "ERROR: invalid dest %d requested\n", (int)nDestID );
+#endif
+ return false;
+ }
+
+
+ const PDFDest& rDest = m_aDests[ nDestID ];
+ const PDFPage& rDestPage = m_aPages[ rDest.m_nPage ];
+
+ rBuffer.append( '[' );
+ rBuffer.append( rDestPage.m_nPageObject );
+ rBuffer.append( " 0 R" );
+
+ switch( rDest.m_eType )
+ {
+ case PDFWriter::XYZ:
+ default:
+ rBuffer.append( "/XYZ " );
+ appendFixedInt( rDest.m_aRect.Left(), rBuffer );
+ rBuffer.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
+ rBuffer.append( " 0" );
+ break;
+ case PDFWriter::Fit:
+ rBuffer.append( "/Fit" );
+ break;
+ case PDFWriter::FitRectangle:
+ rBuffer.append( "/FitR " );
+ appendFixedInt( rDest.m_aRect.Left(), rBuffer );
+ rBuffer.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Top(), rBuffer );
+ rBuffer.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Right(), rBuffer );
+ rBuffer.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
+ break;
+ case PDFWriter::FitHorizontal:
+ rBuffer.append( "/FitH " );
+ appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
+ break;
+ case PDFWriter::FitVertical:
+ rBuffer.append( "/FitV " );
+ appendFixedInt( rDest.m_aRect.Left(), rBuffer );
+ break;
+ case PDFWriter::FitPageBoundingBox:
+ rBuffer.append( "/FitB" );
+ break;
+ case PDFWriter::FitPageBoundingBoxHorizontal:
+ rBuffer.append( "/FitBH " );
+ appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
+ break;
+ case PDFWriter::FitPageBoundingBoxVertical:
+ rBuffer.append( "/FitBV " );
+ appendFixedInt( rDest.m_aRect.Left(), rBuffer );
+ break;
+ }
+ rBuffer.append( ']' );
+
+ return true;
+}
+
+bool PDFWriterImpl::emitLinkAnnotations()
+{
+ int nAnnots = m_aLinks.size();
+ for( int i = 0; i < nAnnots; i++ )
+ {
+ const PDFLink& rLink = m_aLinks[i];
+ if( ! updateObject( rLink.m_nObject ) )
+ continue;
+
+ OStringBuffer aLine( 1024 );
+ aLine.append( rLink.m_nObject );
+ aLine.append( " 0 obj\n" );
+//i59651 key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
+// see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
+ aLine.append( "<</Type/Annot" );
+ if( m_bIsPDF_A1 )
+ aLine.append( "/F 4" );
+ aLine.append( "/Subtype/Link/Border[0 0 0]/Rect[" );
+
+ appendFixedInt( rLink.m_aRect.Left()-7, aLine );//the +7 to have a better shape of the border rectangle
+ aLine.append( ' ' );
+ appendFixedInt( rLink.m_aRect.Top(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rLink.m_aRect.Right()+7, aLine );//the +7 to have a better shape of the border rectangle
+ aLine.append( ' ' );
+ appendFixedInt( rLink.m_aRect.Bottom(), aLine );
+ aLine.append( "]" );
+ if( rLink.m_nDest >= 0 )
+ {
+ aLine.append( "/Dest" );
+ appendDest( rLink.m_nDest, aLine );
+ }
+ else
+ {
+/*--->i56629
+destination is external to the document, so
+we check in the following sequence:
+
+ if target type is neither .pdf, nor .od[tpgs], then
+ check if relative or absolute and act accordingly (use URI or 'launch application' as requested)
+ end processing
+ else if target is .od[tpgs]: then
+ if conversion of type from od[tpgs] to pdf is requested, convert it and this becomes the new target file
+ processing continue
+
+ if (new)target is .pdf : then
+ if GotToR is requested, then
+ convert the target in GoToR where the fragment of the URI is
+ considered the named destination in the target file, set relative or absolute as requested
+ else strip the fragment from URL and then set URI or 'launch application' as requested
+*/
+//
+// FIXME: check if the decode mechanisms for URL processing throughout this implementation
+// are the correct one!!
+//
+// extract target file type
+ INetURLObject aDocumentURL( m_aContext.BaseURL );
+ INetURLObject aTargetURL( rLink.m_aURL );
+ sal_Int32 nChangeFileExtensionToPDF = 0;
+ sal_Int32 nSetGoToRMode = 0;
+ sal_Bool bTargetHasPDFExtension = sal_False;
+ INetProtocol eTargetProtocol = aTargetURL.GetProtocol();
+ sal_Bool bIsUNCPath = sal_False;
+// check if the protocol is a known one, or if there is no protocol at all (on target only)
+// if there is no protocol, make the target relative to the current document directory
+// getting the needed URL information from the current document path
+ if( eTargetProtocol == INET_PROT_NOT_VALID )
+ {
+ if( rLink.m_aURL.getLength() > 4 && rLink.m_aURL.compareToAscii( "\\\\\\\\", 4 ) == 0)
+ {
+ bIsUNCPath = sal_True;
+ }
+ else
+ {
+ INetURLObject aNewBase( aDocumentURL );//duplicate document URL
+ aNewBase.removeSegment(); //remove last segment from it, obtaining the base URL of the
+ //target document
+ aNewBase.insertName( rLink.m_aURL );
+ aTargetURL = aNewBase;//reassign the new target URL
+//recompute the target protocol, with the new URL
+//normal URL processing resumes
+ eTargetProtocol = aTargetURL.GetProtocol();
+ }
+ }
+
+ rtl::OUString aFileExtension = aTargetURL.GetFileExtension();
+
+// Check if the URL ends in '/': if yes it's a directory,
+// it will be forced to a URI link.
+// possibly a malformed URI, leave it as it is, force as URI
+ if( aTargetURL.hasFinalSlash() )
+ m_aContext.DefaultLinkAction = PDFWriter::URIAction;
+
+ if( aFileExtension.getLength() > 0 )
+ {
+ if( m_aContext.ConvertOOoTargetToPDFTarget )
+ {
+//examine the file type (.odm .odt. .odp, odg, ods)
+ if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odm" ) ) ) )
+ nChangeFileExtensionToPDF++;
+ if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odt" ) ) ) )
+ nChangeFileExtensionToPDF++;
+ else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odp" ) ) ) )
+ nChangeFileExtensionToPDF++;
+ else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odg" ) ) ) )
+ nChangeFileExtensionToPDF++;
+ else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ods" ) ) ) )
+ nChangeFileExtensionToPDF++;
+ if( nChangeFileExtensionToPDF )
+ aTargetURL.setExtension(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "pdf" ) ) );
+ }
+//check if extension is pdf, see if GoToR should be forced
+ bTargetHasPDFExtension = aTargetURL.GetFileExtension().equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "pdf" ) ) );
+ if( m_aContext.ForcePDFAction && bTargetHasPDFExtension )
+ nSetGoToRMode++;
+ }
+//prepare the URL, if relative or not
+ INetProtocol eBaseProtocol = aDocumentURL.GetProtocol();
+//queue the string common to all types of actions
+ aLine.append( "/A<</Type/Action/S");
+ if( bIsUNCPath ) // handle Win UNC paths
+ {
+ aLine.append( "/Launch/Win<</F" );
+ // INetURLObject is not good with UNC paths, use original path
+ appendLiteralStringEncrypt( rLink.m_aURL, rLink.m_nObject, aLine );
+ aLine.append( ">>" );
+ }
+ else
+ {
+ sal_Int32 nSetRelative = 0;
+//check if relative file link is requested and if the protocol is 'file://'
+ if( m_aContext.RelFsys && eBaseProtocol == eTargetProtocol && eTargetProtocol == INET_PROT_FILE )
+ nSetRelative++;
+
+ rtl::OUString aFragment = aTargetURL.GetMark( INetURLObject::NO_DECODE /*DECODE_WITH_CHARSET*/ ); //fragment as is,
+ if( nSetGoToRMode == 0 )
+ switch( m_aContext.DefaultLinkAction )
+ {
+ default:
+ case PDFWriter::URIAction :
+ case PDFWriter::URIActionDestination :
+ aLine.append( "/URI/URI" );
+ break;
+ case PDFWriter::LaunchAction:
+// now:
+// if a launch action is requested and the hyperlink target has a fragment
+// and the target file does not have a pdf extension, or it's not a 'file:://' protocol
+// then force the uri action on it
+// This code will permit the correct opening of application on web pages, the one that
+// normally have fragments (but I may be wrong...)
+// and will force the use of URI when the protocol is not file://
+ if( (aFragment.getLength() > 0 && !bTargetHasPDFExtension) ||
+ eTargetProtocol != INET_PROT_FILE )
+ aLine.append( "/URI/URI" );
+ else
+ aLine.append( "/Launch/F" );
+ break;
+ }
+//fragment are encoded in the same way as in the named destination processing
+ rtl::OUString aURLNoMark = aTargetURL.GetURLNoMark( INetURLObject::DECODE_WITH_CHARSET );
+ if( nSetGoToRMode )
+ {//add the fragment
+ aLine.append("/GoToR");
+ aLine.append("/F");
+ appendLiteralStringEncrypt( nSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURLNoMark,
+ INetURLObject::WAS_ENCODED,
+ INetURLObject::DECODE_WITH_CHARSET ) :
+ aURLNoMark, rLink.m_nObject, aLine );
+ if( aFragment.getLength() > 0 )
+ {
+ aLine.append("/D/");
+ appendDestinationName( aFragment , aLine );
+ }
+ }
+ else
+ {
+// change the fragment to accomodate the bookmark (only if the file extension is PDF and
+// the requested action is of the correct type)
+ if(m_aContext.DefaultLinkAction == PDFWriter::URIActionDestination &&
+ bTargetHasPDFExtension && aFragment.getLength() > 0 )
+ {
+ OStringBuffer aLineLoc( 1024 );
+ appendDestinationName( aFragment , aLineLoc );
+//substitute the fragment
+ aTargetURL.SetMark( aLineLoc.getStr() );
+ }
+ rtl::OUString aURL = aTargetURL.GetMainURL( (nSetRelative || eTargetProtocol == INET_PROT_FILE) ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE );
+// check if we have a URL available, if the string is empty, set it as the original one
+// if( aURL.getLength() == 0 )
+// appendLiteralStringEncrypt( rLink.m_aURL , rLink.m_nObject, aLine );
+// else
+ appendLiteralStringEncrypt( nSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURL ) :
+ aURL , rLink.m_nObject, aLine );
+ }
+//<--- i56629
+ }
+ aLine.append( ">>\n" );
+ }
+ if( rLink.m_nStructParent > 0 )
+ {
+ aLine.append( "/StructParent " );
+ aLine.append( rLink.m_nStructParent );
+ }
+ aLine.append( ">>\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
+ return true;
+}
+
+bool PDFWriterImpl::emitNoteAnnotations()
+{
+ // emit note annotations
+ int nAnnots = m_aNotes.size();
+ for( int i = 0; i < nAnnots; i++ )
+ {
+ const PDFNoteEntry& rNote = m_aNotes[i];
+ if( ! updateObject( rNote.m_nObject ) )
+ return false;
+
+ OStringBuffer aLine( 1024 );
+ aLine.append( rNote.m_nObject );
+ aLine.append( " 0 obj\n" );
+//i59651 key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
+// see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
+ aLine.append( "<</Type/Annot" );
+ if( m_bIsPDF_A1 )
+ aLine.append( "/F 4" );
+ aLine.append( "/Subtype/Text/Rect[" );
+
+ appendFixedInt( rNote.m_aRect.Left(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rNote.m_aRect.Top(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rNote.m_aRect.Right(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rNote.m_aRect.Bottom(), aLine );
+ aLine.append( "]" );
+
+ // contents of the note (type text string)
+ aLine.append( "/Contents\n" );
+ appendUnicodeTextStringEncrypt( rNote.m_aContents.Contents, rNote.m_nObject, aLine );
+ aLine.append( "\n" );
+
+ // optional title
+ if( rNote.m_aContents.Title.Len() )
+ {
+ aLine.append( "/T" );
+ appendUnicodeTextStringEncrypt( rNote.m_aContents.Title, rNote.m_nObject, aLine );
+ aLine.append( "\n" );
+ }
+
+ aLine.append( ">>\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+ return true;
+}
+
+Font PDFWriterImpl::replaceFont( const Font& rControlFont, const Font& rAppSetFont )
+{
+ bool bAdjustSize = false;
+
+ Font aFont( rControlFont );
+ if( ! aFont.GetName().Len() )
+ {
+ aFont = rAppSetFont;
+ if( rControlFont.GetHeight() )
+ aFont.SetSize( Size( 0, rControlFont.GetHeight() ) );
+ else
+ bAdjustSize = true;
+ if( rControlFont.GetItalic() != ITALIC_DONTKNOW )
+ aFont.SetItalic( rControlFont.GetItalic() );
+ if( rControlFont.GetWeight() != WEIGHT_DONTKNOW )
+ aFont.SetWeight( rControlFont.GetWeight() );
+ }
+ else if( ! aFont.GetHeight() )
+ {
+ aFont.SetSize( rAppSetFont.GetSize() );
+ bAdjustSize = true;
+ }
+ if( bAdjustSize )
+ {
+ Size aFontSize = aFont.GetSize();
+ OutputDevice* pDefDev = Application::GetDefaultDevice();
+ aFontSize = OutputDevice::LogicToLogic( aFontSize, pDefDev->GetMapMode(), getMapMode() );
+ aFont.SetSize( aFontSize );
+ }
+ return aFont;
+}
+
+sal_Int32 PDFWriterImpl::getBestBuiltinFont( const Font& rFont )
+{
+ sal_Int32 nBest = 4; // default to Helvetica
+ OUString aFontName( rFont.GetName() );
+ aFontName = aFontName.toAsciiLowerCase();
+
+ if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "times" ) ) ) != -1 )
+ nBest = 8;
+ else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "courier" ) ) ) != -1 )
+ nBest = 0;
+ else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "dingbats" ) ) ) != -1 )
+ nBest = 13;
+ else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "symbol" ) ) ) != -1 )
+ nBest = 12;
+ if( nBest < 12 )
+ {
+ if( rFont.GetItalic() == ITALIC_OBLIQUE || rFont.GetItalic() == ITALIC_NORMAL )
+ nBest += 1;
+ if( rFont.GetWeight() > WEIGHT_MEDIUM )
+ nBest += 2;
+ }
+
+ if( m_aBuiltinFontToObjectMap.find( nBest ) == m_aBuiltinFontToObjectMap.end() )
+ m_aBuiltinFontToObjectMap[ nBest ] = createObject();
+
+ return nBest;
+}
+
+static inline const Color& replaceColor( const Color& rCol1, const Color& rCol2 )
+{
+ return (rCol1 == Color( COL_TRANSPARENT )) ? rCol2 : rCol1;
+}
+
+void PDFWriterImpl::createDefaultPushButtonAppearance( PDFWidget& rButton, const PDFWriter::PushButtonWidget& rWidget )
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+
+ // save graphics state
+ push( sal::static_int_cast<sal_uInt16>(~0U) );
+
+ // transform relative to control's coordinates since an
+ // appearance stream is a form XObject
+ // this relies on the m_aRect member of rButton NOT already being transformed
+ // to default user space
+ if( rWidget.Background || rWidget.Border )
+ {
+ setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetLightColor() ) : Color( COL_TRANSPARENT ) );
+ setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetDialogColor() ) : Color( COL_TRANSPARENT ) );
+ drawRectangle( rWidget.Location );
+ }
+ // prepare font to use
+ Font aFont = replaceFont( rWidget.TextFont, rSettings.GetPushButtonFont() );
+ setFont( aFont );
+ setTextColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ) );
+
+ drawText( rButton.m_aRect, rButton.m_aText, rButton.m_nTextStyle );
+
+ // create DA string while local mapmode is still in place
+ // (that is before endRedirect())
+ OStringBuffer aDA( 256 );
+ appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ), aDA );
+ Font aDummyFont( String( RTL_CONSTASCII_USTRINGPARAM( "Helvetica" ) ), aFont.GetSize() );
+ sal_Int32 nDummyBuiltin = getBestBuiltinFont( aDummyFont );
+ aDA.append( ' ' );
+ aDA.append( m_aBuiltinFonts[nDummyBuiltin].getNameObject() );
+ aDA.append( ' ' );
+ m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
+ aDA.append( " Tf" );
+ rButton.m_aDAString = aDA.makeStringAndClear();
+
+ pop();
+
+ rButton.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream();
+
+ /* seems like a bad hack but at least works in both AR5 and 6:
+ we draw the button ourselves and tell AR
+ the button would be totally transparent with no text
+
+ One would expect that simply setting a normal appearance
+ should suffice, but no, as soon as the user actually presses
+ the button and an action is tied to it (gasp! a button that
+ does something) the appearance gets replaced by some crap that AR
+ creates on the fly even if no DA or MK is given. On AR6 at least
+ the DA and MK work as expected, but on AR5 this creates a region
+ filled with the background color but nor text. Urgh.
+ */
+ rButton.m_aMKDict = "/BC [] /BG [] /CA";
+ rButton.m_aMKDictCAString = "";
+}
+
+Font PDFWriterImpl::drawFieldBorder( PDFWidget& rIntern,
+ const PDFWriter::AnyWidget& rWidget,
+ const StyleSettings& rSettings )
+{
+ Font aFont = replaceFont( rWidget.TextFont, rSettings.GetFieldFont() );
+
+ if( rWidget.Background || rWidget.Border )
+ {
+ if( rWidget.Border && rWidget.BorderColor == Color( COL_TRANSPARENT ) )
+ {
+ sal_Int32 nDelta = getReferenceDevice()->ImplGetDPIX() / 500;
+ if( nDelta < 1 )
+ nDelta = 1;
+ setLineColor( Color( COL_TRANSPARENT ) );
+ Rectangle aRect = rIntern.m_aRect;
+ setFillColor( rSettings.GetLightBorderColor() );
+ drawRectangle( aRect );
+ aRect.Left() += nDelta; aRect.Top() += nDelta;
+ aRect.Right() -= nDelta; aRect.Bottom() -= nDelta;
+ setFillColor( rSettings.GetFieldColor() );
+ drawRectangle( aRect );
+ setFillColor( rSettings.GetLightColor() );
+ drawRectangle( Rectangle( Point( aRect.Left(), aRect.Bottom()-nDelta ), aRect.BottomRight() ) );
+ drawRectangle( Rectangle( Point( aRect.Right()-nDelta, aRect.Top() ), aRect.BottomRight() ) );
+ setFillColor( rSettings.GetDarkShadowColor() );
+ drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Left()+nDelta, aRect.Bottom() ) ) );
+ drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Right(), aRect.Top()+nDelta ) ) );
+ }
+ else
+ {
+ setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetShadowColor() ) : Color( COL_TRANSPARENT ) );
+ setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
+ drawRectangle( rIntern.m_aRect );
+ }
+
+ if( rWidget.Border )
+ {
+ // adjust edit area accounting for border
+ sal_Int32 nDelta = aFont.GetHeight()/4;
+ if( nDelta < 1 )
+ nDelta = 1;
+ rIntern.m_aRect.Left() += nDelta;
+ rIntern.m_aRect.Top() += nDelta;
+ rIntern.m_aRect.Right() -= nDelta;
+ rIntern.m_aRect.Bottom()-= nDelta;
+ }
+ }
+ return aFont;
+}
+
+void PDFWriterImpl::createDefaultEditAppearance( PDFWidget& rEdit, const PDFWriter::EditWidget& rWidget )
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ SvMemoryStream* pEditStream = new SvMemoryStream( 1024, 1024 );
+
+ push( sal::static_int_cast<sal_uInt16>(~0U) );
+
+ // prepare font to use, draw field border
+ Font aFont = drawFieldBorder( rEdit, rWidget, rSettings );
+ sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
+
+ // prepare DA string
+ OStringBuffer aDA( 32 );
+ appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
+ aDA.append( ' ' );
+ if( m_aContext.FieldsUseSystemFonts )
+ {
+ aDA.append( "/F" );
+ aDA.append( nBest );
+
+ OStringBuffer aDR( 32 );
+ aDR.append( "/Font " );
+ aDR.append( getFontDictObject() );
+ aDR.append( " 0 R" );
+ rEdit.m_aDRDict = aDR.makeStringAndClear();
+ }
+ else
+ aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
+ aDA.append( ' ' );
+ m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
+ aDA.append( " Tf" );
+
+ /* create an empty appearance stream, let the viewer create
+ the appearance at runtime. This is because AR5 seems to
+ paint the widget appearance always, and a dynamically created
+ appearance on top of it. AR6 is well behaved in that regard, so
+ that behaviour seems to be a bug. Anyway this empty appearance
+ relies on /NeedAppearances in the AcroForm dictionary set to "true"
+ */
+ beginRedirect( pEditStream, rEdit.m_aRect );
+ OStringBuffer aAppearance( 32 );
+ aAppearance.append( "/Tx BMC\nEMC\n" );
+ writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
+
+ endRedirect();
+ pop();
+
+ rEdit.m_aAppearances[ "N" ][ "Standard" ] = pEditStream;
+
+ rEdit.m_aDAString = aDA.makeStringAndClear();
+}
+
+void PDFWriterImpl::createDefaultListBoxAppearance( PDFWidget& rBox, const PDFWriter::ListBoxWidget& rWidget )
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ SvMemoryStream* pListBoxStream = new SvMemoryStream( 1024, 1024 );
+
+ push( sal::static_int_cast<sal_uInt16>(~0U) );
+
+ // prepare font to use, draw field border
+ Font aFont = drawFieldBorder( rBox, rWidget, rSettings );
+ sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
+
+ beginRedirect( pListBoxStream, rBox.m_aRect );
+ OStringBuffer aAppearance( 64 );
+
+#if 0
+ if( ! rWidget.DropDown )
+ {
+ // prepare linewidth for DA string hack, see below
+ Size aFontSize = lcl_convert( m_aGraphicsStack.front().m_aMapMode,
+ m_aMapMode,
+ getReferenceDevice(),
+ Size( 0, aFont.GetHeight() ) );
+ sal_Int32 nLW = aFontSize.Height() / 40;
+ appendFixedInt( nLW > 0 ? nLW : 1, aAppearance );
+ aAppearance.append( " w\n" );
+ writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
+ aAppearance.setLength( 0 );
+ }
+#endif
+
+ setLineColor( Color( COL_TRANSPARENT ) );
+ setFillColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) );
+ drawRectangle( rBox.m_aRect );
+
+ // empty appearance, see createDefaultEditAppearance for reference
+ aAppearance.append( "/Tx BMC\nEMC\n" );
+ writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
+
+ endRedirect();
+ pop();
+
+ rBox.m_aAppearances[ "N" ][ "Standard" ] = pListBoxStream;
+
+ // prepare DA string
+ OStringBuffer aDA( 256 );
+#if 0
+ if( !rWidget.DropDown )
+ {
+ /* another of AR5's peculiarities: the selected item of a choice
+ field is highlighted using the non stroking color - same as the
+ text color. so workaround that by using text rendering mode 2
+ (fill, then stroke) and set the stroking color
+ */
+ appendStrokingColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ), aDA );
+ aDA.append( " 2 Tr " );
+ }
+#endif
+ // prepare DA string
+ appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
+ aDA.append( ' ' );
+ if( m_aContext.FieldsUseSystemFonts )
+ {
+ aDA.append( "/F" );
+ aDA.append( nBest );
+
+ OStringBuffer aDR( 32 );
+ aDR.append( "/Font " );
+ aDR.append( getFontDictObject() );
+ aDR.append( " 0 R" );
+ rBox.m_aDRDict = aDR.makeStringAndClear();
+ }
+ else
+ aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
+ aDA.append( ' ' );
+ m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
+ aDA.append( " Tf" );
+ rBox.m_aDAString = aDA.makeStringAndClear();
+}
+
+void PDFWriterImpl::createDefaultCheckBoxAppearance( PDFWidget& rBox, const PDFWriter::CheckBoxWidget& rWidget )
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+
+ // save graphics state
+ push( sal::static_int_cast<sal_uInt16>(~0U) );
+
+ if( rWidget.Background || rWidget.Border )
+ {
+ setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
+ setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
+ drawRectangle( rBox.m_aRect );
+ }
+
+ Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
+ setFont( aFont );
+ Size aFontSize = aFont.GetSize();
+ if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
+ aFontSize.Height() = rBox.m_aRect.GetHeight();
+ sal_Int32 nDelta = aFontSize.Height()/10;
+ if( nDelta < 1 )
+ nDelta = 1;
+
+ Rectangle aCheckRect, aTextRect;
+ if( rWidget.ButtonIsLeft )
+ {
+ aCheckRect.Left() = rBox.m_aRect.Left() + nDelta;
+ aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
+ aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
+ aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
+
+ // #i74206# handle small controls without text area
+ while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
+ {
+ aCheckRect.Right() -= nDelta;
+ aCheckRect.Top() += nDelta/2;
+ aCheckRect.Bottom() -= nDelta - (nDelta/2);
+ }
+
+ aTextRect.Left() = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
+ aTextRect.Top() = rBox.m_aRect.Top();
+ aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
+ aTextRect.Bottom() = rBox.m_aRect.Bottom();
+ }
+ else
+ {
+ aCheckRect.Left() = rBox.m_aRect.Right() - nDelta - aFontSize.Height();
+ aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
+ aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
+ aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
+
+ // #i74206# handle small controls without text area
+ while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
+ {
+ aCheckRect.Left() += nDelta;
+ aCheckRect.Top() += nDelta/2;
+ aCheckRect.Bottom() -= nDelta - (nDelta/2);
+ }
+
+ aTextRect.Left() = rBox.m_aRect.Left();
+ aTextRect.Top() = rBox.m_aRect.Top();
+ aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
+ aTextRect.Bottom() = rBox.m_aRect.Bottom();
+ }
+ setLineColor( Color( COL_BLACK ) );
+ setFillColor( Color( COL_TRANSPARENT ) );
+ OStringBuffer aLW( 32 );
+ aLW.append( "q " );
+ m_aPages[m_nCurrentPage].appendMappedLength( nDelta, aLW );
+ aLW.append( " w " );
+ writeBuffer( aLW.getStr(), aLW.getLength() );
+ drawRectangle( aCheckRect );
+ writeBuffer( " Q\n", 3 );
+ setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
+ drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
+
+ pop();
+
+ OStringBuffer aDA( 256 );
+ appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
+ sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) );
+ aDA.append( ' ' );
+ aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
+ aDA.append( " 0 Tf" );
+ rBox.m_aDAString = aDA.makeStringAndClear();
+ rBox.m_aMKDict = "/CA";
+ rBox.m_aMKDictCAString = "8";
+ rBox.m_aRect = aCheckRect;
+
+ // create appearance streams
+ sal_Char cMark = '8';
+ sal_Int32 nCharXOffset = 1000-m_aBuiltinFonts[13].m_aWidths[sal_Int32(cMark)];
+ nCharXOffset *= aCheckRect.GetHeight();
+ nCharXOffset /= 2000;
+ sal_Int32 nCharYOffset = 1000-
+ (m_aBuiltinFonts[13].m_nAscent+m_aBuiltinFonts[13].m_nDescent); // descent is negative
+ nCharYOffset *= aCheckRect.GetHeight();
+ nCharYOffset /= 2000;
+
+ SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
+ beginRedirect( pCheckStream, aCheckRect );
+ aDA.append( "/Tx BMC\nq BT\n" );
+ appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
+ aDA.append( ' ' );
+ aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
+ aDA.append( ' ' );
+ m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
+ aDA.append( " Tf\n" );
+ m_aPages[ m_nCurrentPage ].appendMappedLength( nCharXOffset, aDA );
+ aDA.append( " " );
+ m_aPages[ m_nCurrentPage ].appendMappedLength( nCharYOffset, aDA );
+ aDA.append( " Td (" );
+ aDA.append( cMark );
+ aDA.append( ") Tj\nET\nQ\nEMC\n" );
+ writeBuffer( aDA.getStr(), aDA.getLength() );
+ endRedirect();
+ rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
+
+ SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
+ beginRedirect( pUncheckStream, aCheckRect );
+ writeBuffer( "/Tx BMC\nEMC\n", 12 );
+ endRedirect();
+ rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
+}
+
+void PDFWriterImpl::createDefaultRadioButtonAppearance( PDFWidget& rBox, const PDFWriter::RadioButtonWidget& rWidget )
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+
+ // save graphics state
+ push( sal::static_int_cast<sal_uInt16>(~0U) );
+
+ if( rWidget.Background || rWidget.Border )
+ {
+ setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
+ setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
+ drawRectangle( rBox.m_aRect );
+ }
+
+ Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
+ setFont( aFont );
+ Size aFontSize = aFont.GetSize();
+ if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
+ aFontSize.Height() = rBox.m_aRect.GetHeight();
+ sal_Int32 nDelta = aFontSize.Height()/10;
+ if( nDelta < 1 )
+ nDelta = 1;
+
+ Rectangle aCheckRect, aTextRect;
+ if( rWidget.ButtonIsLeft )
+ {
+ aCheckRect.Left() = rBox.m_aRect.Left() + nDelta;
+ aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
+ aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
+ aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
+
+ // #i74206# handle small controls without text area
+ while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
+ {
+ aCheckRect.Right() -= nDelta;
+ aCheckRect.Top() += nDelta/2;
+ aCheckRect.Bottom() -= nDelta - (nDelta/2);
+ }
+
+ aTextRect.Left() = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
+ aTextRect.Top() = rBox.m_aRect.Top();
+ aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
+ aTextRect.Bottom() = rBox.m_aRect.Bottom();
+ }
+ else
+ {
+ aCheckRect.Left() = rBox.m_aRect.Right() - nDelta - aFontSize.Height();
+ aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
+ aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
+ aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
+
+ // #i74206# handle small controls without text area
+ while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
+ {
+ aCheckRect.Left() += nDelta;
+ aCheckRect.Top() += nDelta/2;
+ aCheckRect.Bottom() -= nDelta - (nDelta/2);
+ }
+
+ aTextRect.Left() = rBox.m_aRect.Left();
+ aTextRect.Top() = rBox.m_aRect.Top();
+ aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
+ aTextRect.Bottom() = rBox.m_aRect.Bottom();
+ }
+ setLineColor( Color( COL_BLACK ) );
+ setFillColor( Color( COL_TRANSPARENT ) );
+ OStringBuffer aLW( 32 );
+ aLW.append( "q " );
+ m_aPages[ m_nCurrentPage ].appendMappedLength( nDelta, aLW );
+ aLW.append( " w " );
+ writeBuffer( aLW.getStr(), aLW.getLength() );
+ drawEllipse( aCheckRect );
+ writeBuffer( " Q\n", 3 );
+ setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
+ drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
+
+ pop();
+
+ OStringBuffer aDA( 256 );
+ appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
+ sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) );
+ aDA.append( ' ' );
+ aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
+ aDA.append( " 0 Tf" );
+ rBox.m_aDAString = aDA.makeStringAndClear();
+//to encrypt this (el)
+ rBox.m_aMKDict = "/CA";
+//after this assignement, to m_aMKDic cannot be added anything
+ rBox.m_aMKDictCAString = "l";
+
+ rBox.m_aRect = aCheckRect;
+
+ // create appearance streams
+ push( sal::static_int_cast<sal_uInt16>(~0U) );
+ SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
+
+ beginRedirect( pCheckStream, aCheckRect );
+ aDA.append( "/Tx BMC\nq BT\n" );
+ appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
+ aDA.append( ' ' );
+ aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
+ aDA.append( ' ' );
+ m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
+ aDA.append( " Tf\n0 0 Td\nET\nQ\n" );
+ writeBuffer( aDA.getStr(), aDA.getLength() );
+ setFillColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
+ setLineColor( Color( COL_TRANSPARENT ) );
+ aCheckRect.Left() += 3*nDelta;
+ aCheckRect.Top() += 3*nDelta;
+ aCheckRect.Bottom() -= 3*nDelta;
+ aCheckRect.Right() -= 3*nDelta;
+ drawEllipse( aCheckRect );
+ writeBuffer( "\nEMC\n", 5 );
+ endRedirect();
+
+ pop();
+ rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
+
+ SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
+ beginRedirect( pUncheckStream, aCheckRect );
+ writeBuffer( "/Tx BMC\nEMC\n", 12 );
+ endRedirect();
+ rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
+}
+
+bool PDFWriterImpl::emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict )
+{
+
+ // TODO: check and insert default streams
+ rtl::OString aStandardAppearance;
+ switch( rWidget.m_eType )
+ {
+ case PDFWriter::CheckBox:
+ aStandardAppearance = OUStringToOString( rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US );
+ break;
+ default:
+ break;
+ }
+
+ if( rWidget.m_aAppearances.size() )
+ {
+ rAnnotDict.append( "/AP<<\n" );
+ for( PDFAppearanceMap::iterator dict_it = rWidget.m_aAppearances.begin(); dict_it != rWidget.m_aAppearances.end(); ++dict_it )
+ {
+ rAnnotDict.append( "/" );
+ rAnnotDict.append( dict_it->first );
+ bool bUseSubDict = (dict_it->second.size() > 1);
+ rAnnotDict.append( bUseSubDict ? "<<" : " " );
+
+ for( PDFAppearanceStreams::const_iterator stream_it = dict_it->second.begin();
+ stream_it != dict_it->second.end(); ++stream_it )
+ {
+ SvMemoryStream* pApppearanceStream = stream_it->second;
+ dict_it->second[ stream_it->first ] = NULL;
+
+ bool bDeflate = compressStream( pApppearanceStream );
+
+ pApppearanceStream->Seek( STREAM_SEEK_TO_END );
+ sal_Int64 nStreamLen = pApppearanceStream->Tell();
+ pApppearanceStream->Seek( STREAM_SEEK_TO_BEGIN );
+ sal_Int32 nObject = createObject();
+ CHECK_RETURN( updateObject( nObject ) );
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( " PDFWriterImpl::emitAppearances" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+ OStringBuffer aLine;
+ aLine.append( nObject );
+
+ aLine.append( " 0 obj\n"
+ "<</Type/XObject\n"
+ "/Subtype/Form\n"
+ "/BBox[0 0 " );
+ appendFixedInt( rWidget.m_aRect.GetWidth()-1, aLine );
+ aLine.append( " " );
+ appendFixedInt( rWidget.m_aRect.GetHeight()-1, aLine );
+ aLine.append( "]\n"
+ "/Resources " );
+ aLine.append( getResourceDictObj() );
+ aLine.append( " 0 R\n"
+ "/Length " );
+ aLine.append( nStreamLen );
+ aLine.append( "\n" );
+ if( bDeflate )
+ aLine.append( "/Filter/FlateDecode\n" );
+ aLine.append( ">>\nstream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ checkAndEnableStreamEncryption( nObject );
+ CHECK_RETURN( writeBuffer( pApppearanceStream->GetData(), nStreamLen ) );
+ disableStreamEncryption();
+ CHECK_RETURN( writeBuffer( "\nendstream\nendobj\n\n", 19 ) );
+
+ if( bUseSubDict )
+ {
+ rAnnotDict.append( " /" );
+ rAnnotDict.append( stream_it->first );
+ rAnnotDict.append( " " );
+ }
+ rAnnotDict.append( nObject );
+ rAnnotDict.append( " 0 R" );
+
+ delete pApppearanceStream;
+ }
+
+ rAnnotDict.append( bUseSubDict ? ">>\n" : "\n" );
+ }
+ rAnnotDict.append( ">>\n" );
+ if( aStandardAppearance.getLength() )
+ {
+ rAnnotDict.append( "/AS /" );
+ rAnnotDict.append( aStandardAppearance );
+ rAnnotDict.append( "\n" );
+ }
+ }
+
+ return true;
+}
+
+bool PDFWriterImpl::emitWidgetAnnotations()
+{
+ ensureUniqueRadioOnValues();
+
+ int nAnnots = m_aWidgets.size();
+ for( int a = 0; a < nAnnots; a++ )
+ {
+ PDFWidget& rWidget = m_aWidgets[a];
+
+ OStringBuffer aLine( 1024 );
+ OStringBuffer aValue( 256 );
+ aLine.append( rWidget.m_nObject );
+ aLine.append( " 0 obj\n"
+ "<<" );
+ if( rWidget.m_eType != PDFWriter::Hierarchy )
+ {
+ // emit widget annotation only for terminal fields
+ if( rWidget.m_aKids.empty() )
+ {
+ aLine.append( "/Type/Annot/Subtype/Widget/F 4\n"
+ "/Rect[" );
+ appendFixedInt( rWidget.m_aRect.Left()-1, aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rWidget.m_aRect.Top()+1, aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rWidget.m_aRect.Right()+1, aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rWidget.m_aRect.Bottom()-1, aLine );
+ aLine.append( "]\n" );
+ }
+ aLine.append( "/FT/" );
+ switch( rWidget.m_eType )
+ {
+ case PDFWriter::RadioButton:
+ case PDFWriter::CheckBox:
+ // for radio buttons only the RadioButton field, not the
+ // CheckBox children should have a value, else acrobat reader
+ // does not always check the right button
+ // of course real check boxes (not belonging to a readio group)
+ // need their values, too
+ if( rWidget.m_eType == PDFWriter::RadioButton || rWidget.m_nRadioGroup < 0 )
+ {
+ aValue.append( "/" );
+ // check for radio group with all buttons unpressed
+ if( rWidget.m_aValue.getLength() == 0 )
+ aValue.append( "Off" );
+ else
+ appendName( rWidget.m_aValue, aValue );
+ }
+ case PDFWriter::PushButton:
+ aLine.append( "Btn" );
+ break;
+ case PDFWriter::ListBox:
+ if( rWidget.m_nFlags & 0x200000 ) // multiselect
+ {
+ aValue.append( "[" );
+ for( unsigned int i = 0; i < rWidget.m_aSelectedEntries.size(); i++ )
+ {
+ sal_Int32 nEntry = rWidget.m_aSelectedEntries[i];
+ if( nEntry >= 0 && nEntry < sal_Int32(rWidget.m_aListEntries.size()) )
+ appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ nEntry ], rWidget.m_nObject, aValue );
+ }
+ aValue.append( "]" );
+ }
+ else if( rWidget.m_aSelectedEntries.size() > 0 &&
+ rWidget.m_aSelectedEntries[0] >= 0 &&
+ rWidget.m_aSelectedEntries[0] < sal_Int32(rWidget.m_aListEntries.size()) )
+ {
+ appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ rWidget.m_aSelectedEntries[0] ], rWidget.m_nObject, aValue );
+ }
+ else
+ appendUnicodeTextStringEncrypt( rtl::OUString(), rWidget.m_nObject, aValue );
+ aLine.append( "Ch" );
+ break;
+ case PDFWriter::ComboBox:
+ appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
+ aLine.append( "Ch" );
+ break;
+ case PDFWriter::Edit:
+ aLine.append( "Tx" );
+ appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
+ break;
+ case PDFWriter::Hierarchy: // make the compiler happy
+ break;
+ }
+ aLine.append( "\n" );
+ aLine.append( "/P " );
+ aLine.append( m_aPages[ rWidget.m_nPage ].m_nPageObject );
+ aLine.append( " 0 R\n" );
+ }
+ if( rWidget.m_nParent )
+ {
+ aLine.append( "/Parent " );
+ aLine.append( rWidget.m_nParent );
+ aLine.append( " 0 R\n" );
+ }
+ if( rWidget.m_aKids.size() )
+ {
+ aLine.append( "/Kids[" );
+ for( unsigned int i = 0; i < rWidget.m_aKids.size(); i++ )
+ {
+ aLine.append( rWidget.m_aKids[i] );
+ aLine.append( " 0 R" );
+ aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
+ }
+ aLine.append( "]\n" );
+ }
+ if( rWidget.m_aName.getLength() )
+ {
+ aLine.append( "/T" );
+ appendLiteralStringEncrypt( rWidget.m_aName, rWidget.m_nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( m_aContext.Version > PDFWriter::PDF_1_2 && rWidget.m_aDescription.getLength() )
+ {
+ // the alternate field name should be unicode able since it is
+ // supposed to be used in UI
+ aLine.append( "/TU" );
+ appendUnicodeTextStringEncrypt( rWidget.m_aDescription, rWidget.m_nObject, aLine );
+ aLine.append( "\n" );
+ }
+
+ if( rWidget.m_nFlags )
+ {
+ aLine.append( "/Ff " );
+ aLine.append( rWidget.m_nFlags );
+ aLine.append( "\n" );
+ }
+ if( aValue.getLength() )
+ {
+ OString aVal = aValue.makeStringAndClear();
+ aLine.append( "/V " );
+ aLine.append( aVal );
+ aLine.append( "\n"
+ "/DV " );
+ aLine.append( aVal );
+ aLine.append( "\n" );
+ }
+ if( rWidget.m_eType == PDFWriter::ListBox || rWidget.m_eType == PDFWriter::ComboBox )
+ {
+ sal_Int32 nTI = -1;
+ aLine.append( "/Opt[\n" );
+ sal_Int32 i = 0;
+ for( std::vector< OUString >::const_iterator it = rWidget.m_aListEntries.begin(); it != rWidget.m_aListEntries.end(); ++it, ++i )
+ {
+ appendUnicodeTextStringEncrypt( *it, rWidget.m_nObject, aLine );
+ aLine.append( "\n" );
+ if( *it == rWidget.m_aValue )
+ nTI = i;
+ }
+ aLine.append( "]\n" );
+ if( nTI > 0 )
+ {
+ aLine.append( "/TI " );
+ aLine.append( nTI );
+ aLine.append( "\n" );
+ if( rWidget.m_nFlags & 0x200000 ) // Multiselect
+ {
+ aLine.append( "/I [" );
+ aLine.append( nTI );
+ aLine.append( "]\n" );
+ }
+ }
+ }
+ if( rWidget.m_eType == PDFWriter::Edit && rWidget.m_nMaxLen > 0 )
+ {
+ aLine.append( "/MaxLen " );
+ aLine.append( rWidget.m_nMaxLen );
+ aLine.append( "\n" );
+ }
+ if( rWidget.m_eType == PDFWriter::PushButton )
+ {
+ if(!m_bIsPDF_A1)
+ {
+ OStringBuffer aDest;
+ if( rWidget.m_nDest != -1 && appendDest( rWidget.m_nDest, aDest ) )
+ {
+ aLine.append( "/AA<</D<</Type/Action/S/GoTo/D " );
+ aLine.append( aDest.makeStringAndClear() );
+ aLine.append( ">>>>\n" );
+ }
+ else if( rWidget.m_aListEntries.empty() )
+ {
+ // create a reset form action
+ aLine.append( "/AA<</D<</Type/Action/S/ResetForm>>>>\n" );
+ }
+ else if( rWidget.m_bSubmit )
+ {
+ // create a submit form action
+ aLine.append( "/AA<</D<</Type/Action/S/SubmitForm/F" );
+ appendLiteralStringEncrypt( rWidget.m_aListEntries.front(), rWidget.m_nObject, aLine );
+ aLine.append( "/Flags " );
+
+ sal_Int32 nFlags = 0;
+ switch( m_aContext.SubmitFormat )
+ {
+ case PDFWriter::HTML:
+ nFlags |= 4;
+ break;
+ case PDFWriter::XML:
+ if( m_aContext.Version > PDFWriter::PDF_1_3 )
+ nFlags |= 32;
+ break;
+ case PDFWriter::PDF:
+ if( m_aContext.Version > PDFWriter::PDF_1_3 )
+ nFlags |= 256;
+ break;
+ case PDFWriter::FDF:
+ default:
+ break;
+ }
+ if( rWidget.m_bSubmitGet )
+ nFlags |= 8;
+ aLine.append( nFlags );
+ aLine.append( ">>>>\n" );
+ }
+ else
+ {
+ // create a URI action
+ aLine.append( "/AA<</D<</Type/Action/S/URI/URI(" );
+ aLine.append( OUStringToOString( rWidget.m_aListEntries.front(), RTL_TEXTENCODING_ASCII_US ) );
+ aLine.append( ")>>>>\n" );
+ }
+ }
+ else
+ m_aErrors.insert( PDFWriter::Warning_FormAction_Omitted_PDFA );
+ }
+ if( rWidget.m_aDAString.getLength() )
+ {
+ if( rWidget.m_aDRDict.getLength() )
+ {
+ aLine.append( "/DR<<" );
+ aLine.append( rWidget.m_aDRDict );
+ aLine.append( ">>\n" );
+ }
+ else
+ {
+ aLine.append( "/DR<</Font<<" );
+ appendBuiltinFontsToDict( aLine );
+ aLine.append( ">>>>\n" );
+ }
+ aLine.append( "/DA" );
+ appendLiteralStringEncrypt( rWidget.m_aDAString, rWidget.m_nObject, aLine );
+ aLine.append( "\n" );
+ if( rWidget.m_nTextStyle & TEXT_DRAW_CENTER )
+ aLine.append( "/Q 1\n" );
+ else if( rWidget.m_nTextStyle & TEXT_DRAW_RIGHT )
+ aLine.append( "/Q 2\n" );
+ }
+ // appearance charactristics for terminal fields
+ // which are supposed to have an appearance constructed
+ // by the viewer application
+ if( rWidget.m_aMKDict.getLength() )
+ {
+ aLine.append( "/MK<<" );
+ aLine.append( rWidget.m_aMKDict );
+//add the CA string, encrypting it
+ appendLiteralStringEncrypt(rWidget.m_aMKDictCAString, rWidget.m_nObject, aLine);
+ aLine.append( ">>\n" );
+ }
+
+ CHECK_RETURN( emitAppearances( rWidget, aLine ) );
+
+ aLine.append( ">>\n"
+ "endobj\n\n" );
+ CHECK_RETURN( updateObject( rWidget.m_nObject ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+ return true;
+}
+
+bool PDFWriterImpl::emitAnnotations()
+{
+ if( m_aPages.size() < 1 )
+ return false;
+
+ CHECK_RETURN( emitLinkAnnotations() );
+
+ CHECK_RETURN( emitNoteAnnotations() );
+
+ CHECK_RETURN( emitWidgetAnnotations() );
+
+ return true;
+}
+
+#undef CHECK_RETURN
+#define CHECK_RETURN( x ) if( !x ) return false
+
+bool PDFWriterImpl::emitCatalog()
+{
+ // build page tree
+ // currently there is only one node that contains all leaves
+
+ // first create a page tree node id
+ sal_Int32 nTreeNode = createObject();
+
+ // emit global resource dictionary (page emit needs it)
+ CHECK_RETURN( emitResources() );
+
+ // emit all pages
+ for( std::vector<PDFPage>::iterator it = m_aPages.begin(); it != m_aPages.end(); ++it )
+ if( ! it->emit( nTreeNode ) )
+ return false;
+
+ sal_Int32 nNamedDestinationsDictionary = emitNamedDestinations();
+
+ sal_Int32 nOutlineDict = emitOutline();
+
+ //emit Output intent i59651
+ sal_Int32 nOutputIntentObject = emitOutputIntent();
+
+ //emit metadata
+ sal_Int32 nMetadataObject = emitDocumentMetadata();
+
+ sal_Int32 nStructureDict = 0;
+ if(m_aStructure.size() > 1)
+ {
+///check if dummy structure containers are needed
+ addInternalStructureContainer(m_aStructure[0]);
+ nStructureDict = m_aStructure[0].m_nObject = createObject();
+ emitStructure( m_aStructure[ 0 ] );
+ }
+
+ // adjust tree node file offset
+ if( ! updateObject( nTreeNode ) )
+ return false;
+
+ // emit tree node
+ OStringBuffer aLine( 2048 );
+ aLine.append( nTreeNode );
+ aLine.append( " 0 obj\n" );
+ aLine.append( "<</Type/Pages\n" );
+ aLine.append( "/Resources " );
+ aLine.append( getResourceDictObj() );
+ aLine.append( " 0 R\n" );
+
+ switch( m_eInheritedOrientation )
+ {
+ case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
+ case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break;
+
+ case PDFWriter::Inherit: // actually Inherit would be a bug, but insignificant
+ case PDFWriter::Portrait:
+ default:
+ break;
+ }
+ sal_Int32 nMediaBoxWidth = 0;
+ sal_Int32 nMediaBoxHeight = 0;
+ if( m_aPages.empty() ) // sanity check, this should not happen
+ {
+ nMediaBoxWidth = m_nInheritedPageWidth;
+ nMediaBoxHeight = m_nInheritedPageHeight;
+ }
+ else
+ {
+ for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter )
+ {
+ if( iter->m_nPageWidth > nMediaBoxWidth )
+ nMediaBoxWidth = iter->m_nPageWidth;
+ if( iter->m_nPageHeight > nMediaBoxHeight )
+ nMediaBoxHeight = iter->m_nPageHeight;
+ }
+ }
+ aLine.append( "/MediaBox[ 0 0 " );
+ aLine.append( nMediaBoxWidth );
+ aLine.append( ' ' );
+ aLine.append( nMediaBoxHeight );
+ aLine.append( " ]\n"
+ "/Kids[ " );
+ unsigned int i = 0;
+ for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter, i++ )
+ {
+ aLine.append( iter->m_nPageObject );
+ aLine.append( " 0 R" );
+ aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
+ }
+ aLine.append( "]\n"
+ "/Count " );
+ aLine.append( (sal_Int32)m_aPages.size() );
+ aLine.append( ">>\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ // emit annotation objects
+ CHECK_RETURN( emitAnnotations() );
+
+ // emit Catalog
+ m_nCatalogObject = createObject();
+ if( ! updateObject( m_nCatalogObject ) )
+ return false;
+ aLine.setLength( 0 );
+ aLine.append( m_nCatalogObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/Catalog/Pages " );
+ aLine.append( nTreeNode );
+ aLine.append( " 0 R\n" );
+//--->i56629
+//check if there are named destinations to emit (root must be inside the catalog)
+ if( nNamedDestinationsDictionary )
+ {
+ aLine.append("/Dests ");
+ aLine.append( nNamedDestinationsDictionary );
+ aLine.append( " 0 R\n" );
+ }
+//<----
+ if( m_aContext.PageLayout != PDFWriter::DefaultLayout )
+ switch( m_aContext.PageLayout )
+ {
+ default :
+ case PDFWriter::SinglePage :
+ aLine.append( "/PageLayout/SinglePage\n" );
+ break;
+ case PDFWriter::Continuous :
+ aLine.append( "/PageLayout/OneColumn\n" );
+ break;
+ case PDFWriter::ContinuousFacing :
+//the flag m_aContext.FirstPageLeft below is used to set the page on the left side
+ aLine.append( "/PageLayout/TwoColumnRight\n" );//odd page on the right side
+ break;
+ }
+ if( m_aContext.PDFDocumentMode != PDFWriter::ModeDefault && !m_aContext.OpenInFullScreenMode )
+ switch( m_aContext.PDFDocumentMode )
+ {
+ default :
+ aLine.append( "/PageMode/UseNone\n" );
+ break;
+ case PDFWriter::UseOutlines :
+ aLine.append( "/PageMode/UseOutlines\n" ); //document is opened with outline pane open
+ break;
+ case PDFWriter::UseThumbs :
+ aLine.append( "/PageMode/UseThumbs\n" ); //document is opened with thumbnails pane open
+ break;
+ }
+ else if( m_aContext.OpenInFullScreenMode )
+ aLine.append( "/PageMode/FullScreen\n" ); //document is opened full screen
+
+ OStringBuffer aInitPageRef;
+ if( m_aContext.InitialPage >= 0 && m_aContext.InitialPage < (sal_Int32)m_aPages.size() )
+ {
+ aInitPageRef.append( m_aPages[m_aContext.InitialPage].m_nPageObject );
+ aInitPageRef.append( " 0 R" );
+ }
+ else
+ aInitPageRef.append( "0" );
+ switch( m_aContext.PDFDocumentAction )
+ {
+ case PDFWriter::ActionDefault : //do nothing, this is the Acrobat default
+ default:
+ if( aInitPageRef.getLength() > 1 )
+ {
+ aLine.append( "/OpenAction[" );
+ aLine.append( aInitPageRef );
+ aLine.append( " /XYZ null null 0]\n" );
+ }
+ break;
+ case PDFWriter::FitInWindow :
+ aLine.append( "/OpenAction[" );
+ aLine.append( aInitPageRef );
+ aLine.append( " /Fit]\n" ); //Open fit page
+ break;
+ case PDFWriter::FitWidth :
+ aLine.append( "/OpenAction[" );
+ aLine.append( aInitPageRef );
+ aLine.append( " /FitH " );
+ aLine.append( m_nInheritedPageHeight );//Open fit width
+ aLine.append( "]\n" );
+ break;
+ case PDFWriter::FitVisible :
+ aLine.append( "/OpenAction[" );
+ aLine.append( aInitPageRef );
+ aLine.append( " /FitBH " );
+ aLine.append( m_nInheritedPageHeight );//Open fit visible
+ aLine.append( "]\n" );
+ break;
+ case PDFWriter::ActionZoom :
+ aLine.append( "/OpenAction[" );
+ aLine.append( aInitPageRef );
+ aLine.append( " /XYZ null null " );
+ if( m_aContext.Zoom >= 50 && m_aContext.Zoom <= 1600 )
+ aLine.append( (double)m_aContext.Zoom/100.0 );
+ else
+ aLine.append( "0" );
+ aLine.append( "]\n" );
+ break;
+ }
+// viewer preferences, if we had some, then emit
+ if( m_aContext.HideViewerToolbar ||
+ ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aDocInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) ||
+ m_aContext.HideViewerMenubar ||
+ m_aContext.HideViewerWindowControls || m_aContext.FitWindow ||
+ m_aContext.CenterWindow || (m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) ||
+ m_aContext.OpenInFullScreenMode )
+ {
+ aLine.append( "/ViewerPreferences<<" );
+ if( m_aContext.HideViewerToolbar )
+ aLine.append( "/HideToolbar true\n" );
+ if( m_aContext.HideViewerMenubar )
+ aLine.append( "/HideMenubar true\n" );
+ if( m_aContext.HideViewerWindowControls )
+ aLine.append( "/HideWindowUI true\n" );
+ if( m_aContext.FitWindow )
+ aLine.append( "/FitWindow true\n" );
+ if( m_aContext.CenterWindow )
+ aLine.append( "/CenterWindow true\n" );
+ if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aDocInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle )
+ aLine.append( "/DisplayDocTitle true\n" );
+ if( m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing )
+ aLine.append( "/Direction/R2L\n" );
+ if( m_aContext.OpenInFullScreenMode )
+ switch( m_aContext.PDFDocumentMode )
+ {
+ default :
+ case PDFWriter::ModeDefault :
+ aLine.append( "/NonFullScreenPageMode/UseNone\n" );
+ break;
+ case PDFWriter::UseOutlines :
+ aLine.append( "/NonFullScreenPageMode/UseOutlines\n" );
+ break;
+ case PDFWriter::UseThumbs :
+ aLine.append( "/NonFullScreenPageMode/UseThumbs\n" );
+ break;
+ }
+ aLine.append( ">>\n" );
+ }
+
+ if( nOutlineDict )
+ {
+ aLine.append( "/Outlines " );
+ aLine.append( nOutlineDict );
+ aLine.append( " 0 R\n" );
+ }
+ if( nStructureDict )
+ {
+ aLine.append( "/StructTreeRoot " );
+ aLine.append( nStructureDict );
+ aLine.append( " 0 R\n" );
+ }
+ if( m_aContext.DocumentLocale.Language.getLength() > 0 )
+ {
+ OUStringBuffer aLocBuf( 16 );
+ aLocBuf.append( m_aContext.DocumentLocale.Language.toAsciiLowerCase() );
+ if( m_aContext.DocumentLocale.Country.getLength() > 0 )
+ {
+ aLocBuf.append( sal_Unicode('-') );
+ aLocBuf.append( m_aContext.DocumentLocale.Country );
+ }
+ aLine.append( "/Lang" );
+ appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), m_nCatalogObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( m_aContext.Tagged && m_aContext.Version > PDFWriter::PDF_1_3 )
+ {
+ aLine.append( "/MarkInfo<</Marked true>>\n" );
+ }
+ if( m_aWidgets.size() > 0 )
+ {
+ aLine.append( "/AcroForm<</Fields[\n" );
+ int nWidgets = m_aWidgets.size();
+ int nOut = 0;
+ for( int j = 0; j < nWidgets; j++ )
+ {
+ // output only root fields
+ if( m_aWidgets[j].m_nParent < 1 )
+ {
+ aLine.append( m_aWidgets[j].m_nObject );
+ aLine.append( (nOut++ % 5)==4 ? " 0 R\n" : " 0 R " );
+ }
+ }
+ aLine.append( "\n]/DR " );
+ aLine.append( getResourceDictObj() );
+ aLine.append( " 0 R" );
+ if( m_bIsPDF_A1 )
+ aLine.append( ">>\n" );
+ else
+ aLine.append( "/NeedAppearances true>>\n" );
+ }
+//--->i59651
+//check if there is a Metadata object
+ if( nOutputIntentObject )
+ {
+ aLine.append("/OutputIntents[");
+ aLine.append( nOutputIntentObject );
+ aLine.append( " 0 R]" );
+ }
+ if( nMetadataObject )
+ {
+ aLine.append("/Metadata ");
+ aLine.append( nMetadataObject );
+ aLine.append( " 0 R" );
+ }
+//<----
+ aLine.append( ">>\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ return true;
+}
+
+sal_Int32 PDFWriterImpl::emitInfoDict( )
+{
+ sal_Int32 nObject = createObject();
+
+ if( updateObject( nObject ) )
+ {
+ OStringBuffer aLine( 1024 );
+ aLine.append( nObject );
+ aLine.append( " 0 obj\n"
+ "<<" );
+ if( m_aDocInfo.Title.Len() )
+ {
+ aLine.append( "/Title" );
+ appendUnicodeTextStringEncrypt( m_aDocInfo.Title, nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( m_aDocInfo.Author.Len() )
+ {
+ aLine.append( "/Author" );
+ appendUnicodeTextStringEncrypt( m_aDocInfo.Author, nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( m_aDocInfo.Subject.Len() )
+ {
+ aLine.append( "/Subject" );
+ appendUnicodeTextStringEncrypt( m_aDocInfo.Subject, nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( m_aDocInfo.Keywords.Len() )
+ {
+ aLine.append( "/Keywords" );
+ appendUnicodeTextStringEncrypt( m_aDocInfo.Keywords, nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( m_aDocInfo.Creator.Len() )
+ {
+ aLine.append( "/Creator" );
+ appendUnicodeTextStringEncrypt( m_aDocInfo.Creator, nObject, aLine );
+ aLine.append( "\n" );
+ }
+ if( m_aDocInfo.Producer.Len() )
+ {
+ aLine.append( "/Producer" );
+ appendUnicodeTextStringEncrypt( m_aDocInfo.Producer, nObject, aLine );
+ aLine.append( "\n" );
+ }
+
+ aLine.append( "/CreationDate" );
+ appendLiteralStringEncrypt( m_aCreationDateString, nObject, aLine );
+ aLine.append( ">>\nendobj\n\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ nObject = 0;
+ }
+ else
+ nObject = 0;
+
+ return nObject;
+}
+
+//--->i56629
+// Part of this function may be shared with method appendDest.
+//
+sal_Int32 PDFWriterImpl::emitNamedDestinations()
+{
+ sal_Int32 nCount = m_aNamedDests.size();
+ if( nCount <= 0 )
+ return 0;//define internal error
+
+//get the object number for all the destinations
+ sal_Int32 nObject = createObject();
+
+ if( updateObject( nObject ) )
+ {
+//emit the dictionary
+ OStringBuffer aLine( 1024 );
+ aLine.append( nObject );
+ aLine.append( " 0 obj\n"
+ "<<" );
+
+ sal_Int32 nDestID;
+ for( nDestID = 0; nDestID < nCount; nDestID++ )
+ {
+ const PDFNamedDest& rDest = m_aNamedDests[ nDestID ];
+// In order to correctly function both under an Internet browser and
+// directly with a reader (provided the reader has the feature) we
+// need to set the name of the destination the same way it will be encoded
+// in an Internet link
+ INetURLObject aLocalURL(
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "http://ahost.ax" ) ) ); //dummy location, won't be used
+ aLocalURL.SetMark( rDest.m_aDestName );
+
+ const rtl::OUString aName = aLocalURL.GetMark( INetURLObject::NO_DECODE ); //same coding as
+ // in link creation ( see PDFWriterImpl::emitLinkAnnotations )
+ const PDFPage& rDestPage = m_aPages[ rDest.m_nPage ];
+
+ aLine.append( '/' );
+ appendDestinationName( aName, aLine ); // this conversion must be done when forming the link to target ( see in emitCatalog )
+ aLine.append( '[' ); // the '[' can be emitted immediately, because the appendDestinationName function
+ //maps the preceeding character properly
+ aLine.append( rDestPage.m_nPageObject );
+ aLine.append( " 0 R" );
+
+ switch( rDest.m_eType )
+ {
+ case PDFWriter::XYZ:
+ default:
+ aLine.append( "/XYZ " );
+ appendFixedInt( rDest.m_aRect.Left(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Bottom(), aLine );
+ aLine.append( " 0" );
+ break;
+ case PDFWriter::Fit:
+ aLine.append( "/Fit" );
+ break;
+ case PDFWriter::FitRectangle:
+ aLine.append( "/FitR " );
+ appendFixedInt( rDest.m_aRect.Left(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Top(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Right(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rDest.m_aRect.Bottom(), aLine );
+ break;
+ case PDFWriter::FitHorizontal:
+ aLine.append( "/FitH " );
+ appendFixedInt( rDest.m_aRect.Bottom(), aLine );
+ break;
+ case PDFWriter::FitVertical:
+ aLine.append( "/FitV " );
+ appendFixedInt( rDest.m_aRect.Left(), aLine );
+ break;
+ case PDFWriter::FitPageBoundingBox:
+ aLine.append( "/FitB" );
+ break;
+ case PDFWriter::FitPageBoundingBoxHorizontal:
+ aLine.append( "/FitBH " );
+ appendFixedInt( rDest.m_aRect.Bottom(), aLine );
+ break;
+ case PDFWriter::FitPageBoundingBoxVertical:
+ aLine.append( "/FitBV " );
+ appendFixedInt( rDest.m_aRect.Left(), aLine );
+ break;
+ }
+ aLine.append( "]\n" );
+ }
+//close
+
+ aLine.append( ">>\nendobj\n\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ nObject = 0;
+ }
+ else
+ nObject = 0;
+
+ return nObject;
+}
+//<--- i56629
+
+//--->i59651
+// emits the output intent dictionary
+
+sal_Int32 PDFWriterImpl::emitOutputIntent()
+{
+ if( !m_bIsPDF_A1 )
+ return 0;
+
+//emit the sRGB standard profile, in ICC format, in a stream, per IEC61966-2.1
+
+ OStringBuffer aLine( 1024 );
+ sal_Int32 nICCObject = createObject();
+ sal_Int32 nStreamLengthObject = createObject();
+
+ aLine.append( nICCObject );
+// sRGB has 3 colors, hence /N 3 below (PDF 1.4 table 4.16)
+ aLine.append( " 0 obj\n<</N 3/Length " );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 R" );
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ aLine.append( "/Filter/FlateDecode" );
+#endif
+ aLine.append( ">>\nstream\n" );
+ CHECK_RETURN( updateObject( nICCObject ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+//get file position
+ sal_uInt64 nBeginStreamPos = 0;
+ osl_getFilePos( m_aFile, &nBeginStreamPos );
+ beginCompression();
+ checkAndEnableStreamEncryption( nICCObject );
+ sal_Int32 nStreamSize = writeBuffer( nsRGB_ICC_profile, (sal_Int32) sizeof( nsRGB_ICC_profile ) );
+ disableStreamEncryption();
+ endCompression();
+ sal_uInt64 nEndStreamPos = 0;
+ osl_getFilePos( m_aFile, &nEndStreamPos );
+
+ if( nStreamSize == 0 )
+ return 0;
+ if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
+ return 0 ;
+ aLine.setLength( 0 );
+
+//emit the stream length object
+ CHECK_RETURN( updateObject( nStreamLengthObject ) );
+ aLine.setLength( 0 );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
+ aLine.append( "\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ aLine.setLength( 0 );
+
+//emit the OutputIntent dictionary
+ sal_Int32 nOIObject = createObject();
+ CHECK_RETURN( updateObject( nOIObject ) );
+ aLine.append( nOIObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/OutputIntent/S/GTS_PDFA1/OutputConditionIdentifier");
+
+ rtl::OUString aComment( RTL_CONSTASCII_USTRINGPARAM( "sRGB IEC61966-2.1" ) );
+ appendLiteralStringEncrypt( aComment ,nOIObject, aLine );
+ aLine.append("/DestOutputProfile ");
+ aLine.append( nICCObject );
+ aLine.append( " 0 R>>\nendobj\n\n" );;
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ return nOIObject;
+}
+
+// formats the string for the XML stream
+static void escapeStringXML( const rtl::OUString& rStr, rtl::OUString &rValue)
+{
+ const sal_Unicode* pUni = rStr.getStr();
+ int nLen = rStr.getLength();
+ for( ; nLen; nLen--, pUni++ )
+ {
+ switch( *pUni )
+ {
+ case sal_Unicode('&'):
+ rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&amp;" ) );
+ break;
+ case sal_Unicode('<'):
+ rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&lt;" ) );
+ break;
+ case sal_Unicode('>'):
+ rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&gt;" ) );
+ break;
+ case sal_Unicode('\''):
+ rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&apos;" ) );
+ break;
+ case sal_Unicode('"'):
+ rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&quot;" ) );
+ break;
+ default:
+ rValue += rtl::OUString( *pUni );
+ break;
+ }
+ }
+}
+
+// emits the document metadata
+//
+sal_Int32 PDFWriterImpl::emitDocumentMetadata()
+{
+ if( !m_bIsPDF_A1 )
+ return 0;
+
+ //get the object number for all the destinations
+ sal_Int32 nObject = createObject();
+
+ if( updateObject( nObject ) )
+ {
+// the following string are written in UTF-8 unicode
+ OStringBuffer aMetadataStream( 8192 );
+
+ aMetadataStream.append( "<?xpacket begin=\"" );
+// this lines writes Unicode “zero width non-breaking space character†(U+FEFF) (aka byte-order mark ) used
+// as a byte-order marker.
+ aMetadataStream.append( OUStringToOString( OUString( sal_Unicode( 0xFEFF ) ), RTL_TEXTENCODING_UTF8 ) );
+ aMetadataStream.append( "\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" );
+ aMetadataStream.append( "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n" );
+ aMetadataStream.append( " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" );
+//PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
+ aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
+ aMetadataStream.append( " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" );
+ aMetadataStream.append( " <pdfaid:part>1</pdfaid:part>\n" );
+ aMetadataStream.append( " <pdfaid:conformance>A</pdfaid:conformance>\n" );
+ aMetadataStream.append( " </rdf:Description>\n" );
+//... Dublin Core properties go here
+ if( m_aDocInfo.Title.Len() ||
+ m_aDocInfo.Author.Len() ||
+ m_aDocInfo.Subject.Len() )
+ {
+ aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
+ aMetadataStream.append( " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" );
+ if( m_aDocInfo.Title.Len() )
+ {
+// this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
+ aMetadataStream.append( " <dc:title>\n" );
+ aMetadataStream.append( " <rdf:Alt>\n" );
+ aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" );
+ rtl::OUString aTitle;
+ escapeStringXML( m_aDocInfo.Title, aTitle );
+ aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ) );
+ aMetadataStream.append( "</rdf:li>\n" );
+ aMetadataStream.append( " </rdf:Alt>\n" );
+ aMetadataStream.append( " </dc:title>\n" );
+ }
+ if( m_aDocInfo.Author.Len() )
+ {
+ aMetadataStream.append( " <dc:creator>\n" );
+ aMetadataStream.append( " <rdf:Seq>\n" );
+ aMetadataStream.append( " <rdf:li>" );
+ rtl::OUString aAuthor;
+ escapeStringXML( m_aDocInfo.Author, aAuthor );
+ aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 ) );
+ aMetadataStream.append( "</rdf:li>\n" );
+ aMetadataStream.append( " </rdf:Seq>\n" );
+ aMetadataStream.append( " </dc:creator>\n" );
+ }
+ if( m_aDocInfo.Subject.Len() )
+ {
+// this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
+ aMetadataStream.append( " <dc:description>\n" );
+ aMetadataStream.append( " <rdf:Alt>\n" );
+ aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" );
+ rtl::OUString aSubject;
+ escapeStringXML( m_aDocInfo.Subject, aSubject );
+ aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 ) );
+ aMetadataStream.append( "</rdf:li>\n" );
+ aMetadataStream.append( " </rdf:Alt>\n" );
+ aMetadataStream.append( " </dc:description>\n" );
+ }
+ aMetadataStream.append( " </rdf:Description>\n" );
+ }
+
+//... PDF properties go here
+ if( m_aDocInfo.Producer.Len() ||
+ m_aDocInfo.Keywords.Len() )
+ {
+ aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
+ aMetadataStream.append( " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" );
+ if( m_aDocInfo.Producer.Len() )
+ {
+ aMetadataStream.append( " <pdf:Producer>" );
+ rtl::OUString aProducer;
+ escapeStringXML( m_aDocInfo.Producer, aProducer );
+ aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 ) );
+ aMetadataStream.append( "</pdf:Producer>\n" );
+ }
+ if( m_aDocInfo.Keywords.Len() )
+ {
+ aMetadataStream.append( " <pdf:Keywords>" );
+ rtl::OUString aKeywords;
+ escapeStringXML( m_aDocInfo.Keywords, aKeywords );
+ aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 ) );
+ aMetadataStream.append( "</pdf:Keywords>\n" );
+ }
+ aMetadataStream.append( " </rdf:Description>\n" );
+ }
+
+ aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
+ aMetadataStream.append( " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" );
+ if( m_aDocInfo.Creator.Len() )
+ {
+ aMetadataStream.append( " <xmp:CreatorTool>" );
+ rtl::OUString aCreator;
+ escapeStringXML( m_aDocInfo.Creator, aCreator );
+ aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 ) );
+ aMetadataStream.append( "</xmp:CreatorTool>\n" );
+ }
+//creation date
+ aMetadataStream.append( " <xmp:CreateDate>" );
+ aMetadataStream.append( m_aCreationMetaDateString );
+ aMetadataStream.append( "</xmp:CreateDate>\n" );
+
+ aMetadataStream.append( " </rdf:Description>\n" );
+ aMetadataStream.append( " </rdf:RDF>\n" );
+ aMetadataStream.append( "</x:xmpmeta>\n" );
+
+//add the padding
+ for( sal_Int32 nSpaces = 1; nSpaces <= 2100; nSpaces++ )
+ {
+ aMetadataStream.append( " " );
+ if( nSpaces % 100 == 0 )
+ aMetadataStream.append( "\n" );
+ }
+
+ aMetadataStream.append( "<?xpacket end=\"w\"?>\n" );
+
+ OStringBuffer aMetadataObj( 1024 );
+
+ aMetadataObj.append( nObject );
+ aMetadataObj.append( " 0 obj\n" );
+
+ aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " );
+
+ aMetadataObj.append( (sal_Int32) aMetadataStream.getLength() );
+ aMetadataObj.append( ">>\nstream\n" );
+ CHECK_RETURN( writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) );
+//emit the stream
+ CHECK_RETURN( writeBuffer( aMetadataStream.getStr(), aMetadataStream.getLength() ) );
+
+ aMetadataObj.setLength( 0 );
+ aMetadataObj.append( "\nendstream\nendobj\n\n" );
+ if( ! writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) )
+ nObject = 0;
+ }
+ else
+ nObject = 0;
+
+ return nObject;
+}
+//<---i59651
+
+bool PDFWriterImpl::emitTrailer()
+{
+ // emit doc info
+ OString aInfoValuesOut;
+ sal_Int32 nDocInfoObject = emitInfoDict( );
+
+ sal_Int32 nSecObject = 0;
+
+ if( m_aContext.Encrypt == true )
+ {
+//emit the security information
+//must be emitted as indirect dictionary object, since
+//Acrobat Reader 5 works only with this kind of implementation
+ nSecObject = createObject();
+
+ if( updateObject( nSecObject ) )
+ {
+ OStringBuffer aLineS( 1024 );
+ aLineS.append( nSecObject );
+ aLineS.append( " 0 obj\n"
+ "<</Filter/Standard/V " );
+ // check the version
+ if( m_aContext.Security128bit == true )
+ aLineS.append( "2/Length 128/R 3" );
+ else
+ aLineS.append( "1/R 2" );
+
+ // emit the owner password, must not be encrypted
+ aLineS.append( "/O(" );
+ appendLiteralString( (const sal_Char*)m_nEncryptedOwnerPassword, 32, aLineS );
+ aLineS.append( ")/U(" );
+ appendLiteralString( (const sal_Char*)m_nEncryptedUserPassword, 32, aLineS );
+ aLineS.append( ")/P " );// the permission set
+ aLineS.append( m_nAccessPermissions );
+ aLineS.append( ">>\nendobj\n\n" );
+ if( !writeBuffer( aLineS.getStr(), aLineS.getLength() ) )
+ nSecObject = 0;
+ }
+ else
+ nSecObject = 0;
+ }
+ // emit xref table
+ // remember start
+ sal_uInt64 nXRefOffset = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nXRefOffset )) );
+ CHECK_RETURN( writeBuffer( "xref\n", 5 ) );
+
+ sal_Int32 nObjects = m_aObjects.size();
+ OStringBuffer aLine;
+ aLine.append( "0 " );
+ aLine.append( (sal_Int32)(nObjects+1) );
+ aLine.append( "\n" );
+ aLine.append( "0000000000 65535 f \n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ for( sal_Int32 i = 0; i < nObjects; i++ )
+ {
+ aLine.setLength( 0 );
+ OString aOffset = OString::valueOf( (sal_Int64)m_aObjects[i] );
+ for( sal_Int32 j = 0; j < (10-aOffset.getLength()); j++ )
+ aLine.append( '0' );
+ aLine.append( aOffset );
+ aLine.append( " 00000 n \n" );
+ DBG_ASSERT( aLine.getLength() == 20, "invalid xref entry" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
+ // prepare document checksum
+ OStringBuffer aDocChecksum( 2*RTL_DIGEST_LENGTH_MD5+1 );
+ if( m_aDocDigest )
+ {
+ sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
+ rtl_digest_getMD5( m_aDocDigest, nMD5Sum, sizeof(nMD5Sum) );
+ for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
+ appendHex( nMD5Sum[i], aDocChecksum );
+ }
+ // document id set in setDocInfo method
+ // emit trailer
+ aLine.setLength( 0 );
+ aLine.append( "trailer\n"
+ "<</Size " );
+ aLine.append( (sal_Int32)(nObjects+1) );
+ aLine.append( "/Root " );
+ aLine.append( m_nCatalogObject );
+ aLine.append( " 0 R\n" );
+ if( nSecObject |= 0 )
+ {
+ aLine.append( "/Encrypt ");
+ aLine.append( nSecObject );
+ aLine.append( " 0 R\n" );
+ }
+ if( nDocInfoObject )
+ {
+ aLine.append( "/Info " );
+ aLine.append( nDocInfoObject );
+ aLine.append( " 0 R\n" );
+ }
+ if( m_aDocID.getLength() )
+ {
+ aLine.append( "/ID [ <" );
+ aLine.append( m_aDocID.getStr(), m_aDocID.getLength() );
+ aLine.append( ">\n"
+ "<" );
+ aLine.append( m_aDocID.getStr(), m_aDocID.getLength() );
+ aLine.append( "> ]\n" );
+ }
+ if( aDocChecksum.getLength() )
+ {
+ aLine.append( "/DocChecksum /" );
+ aLine.append( aDocChecksum );
+ aLine.append( "\n" );
+ }
+ if( m_aAdditionalStreams.size() > 0 )
+ {
+ aLine.append( "/AdditionalStreams [" );
+ for( unsigned int i = 0; i < m_aAdditionalStreams.size(); i++ )
+ {
+ aLine.append( "/" );
+ appendName( m_aAdditionalStreams[i].m_aMimeType, aLine );
+ aLine.append( " " );
+ aLine.append( m_aAdditionalStreams[i].m_nStreamObject );
+ aLine.append( " 0 R\n" );
+ }
+ aLine.append( "]\n" );
+ }
+ aLine.append( ">>\n"
+ "startxref\n" );
+ aLine.append( (sal_Int64)nXRefOffset );
+ aLine.append( "\n"
+ "%%EOF\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ return true;
+}
+
+struct AnnotationSortEntry
+{
+ sal_Int32 nTabOrder;
+ sal_Int32 nObject;
+ sal_Int32 nWidgetIndex;
+
+ AnnotationSortEntry( sal_Int32 nTab, sal_Int32 nObj, sal_Int32 nI ) :
+ nTabOrder( nTab ),
+ nObject( nObj ),
+ nWidgetIndex( nI )
+ {}
+};
+
+struct AnnotSortContainer
+{
+ std::set< sal_Int32 > aObjects;
+ std::vector< AnnotationSortEntry > aSortedAnnots;
+};
+
+struct AnnotSorterLess
+{
+ std::vector< PDFWriterImpl::PDFWidget >& m_rWidgets;
+
+ AnnotSorterLess( std::vector< PDFWriterImpl::PDFWidget >& rWidgets ) : m_rWidgets( rWidgets ) {}
+
+ bool operator()( const AnnotationSortEntry& rLeft, const AnnotationSortEntry& rRight )
+ {
+ if( rLeft.nTabOrder < rRight.nTabOrder )
+ return true;
+ if( rRight.nTabOrder < rLeft.nTabOrder )
+ return false;
+ if( rLeft.nWidgetIndex < 0 && rRight.nWidgetIndex < 0 )
+ return false;
+ if( rRight.nWidgetIndex < 0 )
+ return true;
+ if( rLeft.nWidgetIndex < 0 )
+ return false;
+ // remember: widget rects are in PDF coordinates, so they are ordered down up
+ if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() >
+ m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() )
+ return true;
+ if( m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() >
+ m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() )
+ return false;
+ if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Left() <
+ m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Left() )
+ return true;
+ return false;
+ }
+};
+
+void PDFWriterImpl::sortWidgets()
+{
+ // sort widget annotations on each page as per their
+ // TabOrder attribute
+ std::hash_map< sal_Int32, AnnotSortContainer > sorted;
+ int nWidgets = m_aWidgets.size();
+ for( int nW = 0; nW < nWidgets; nW++ )
+ {
+ const PDFWidget& rWidget = m_aWidgets[nW];
+ if( rWidget.m_nPage >= 0 )
+ {
+ AnnotSortContainer& rCont = sorted[ rWidget.m_nPage ];
+ // optimize vector allocation
+ if( rCont.aSortedAnnots.empty() )
+ rCont.aSortedAnnots.reserve( m_aPages[ rWidget.m_nPage ].m_aAnnotations.size() );
+ // insert widget to tab sorter
+ // RadioButtons are not page annotations, only their individual check boxes are
+ if( rWidget.m_eType != PDFWriter::RadioButton )
+ {
+ rCont.aObjects.insert( rWidget.m_nObject );
+ rCont.aSortedAnnots.push_back( AnnotationSortEntry( rWidget.m_nTabOrder, rWidget.m_nObject, nW ) );
+ }
+ }
+ }
+ for( std::hash_map< sal_Int32, AnnotSortContainer >::iterator it = sorted.begin(); it != sorted.end(); ++it )
+ {
+ // append entries for non widget annotations
+ PDFPage& rPage = m_aPages[ it->first ];
+ unsigned int nAnnots = rPage.m_aAnnotations.size();
+ for( unsigned int nA = 0; nA < nAnnots; nA++ )
+ if( it->second.aObjects.find( rPage.m_aAnnotations[nA] ) == it->second.aObjects.end())
+ it->second.aSortedAnnots.push_back( AnnotationSortEntry( 10000, rPage.m_aAnnotations[nA], -1 ) );
+
+ AnnotSorterLess aLess( m_aWidgets );
+ std::stable_sort( it->second.aSortedAnnots.begin(), it->second.aSortedAnnots.end(), aLess );
+ // sanity check
+ if( it->second.aSortedAnnots.size() == nAnnots)
+ {
+ for( unsigned int nA = 0; nA < nAnnots; nA++ )
+ rPage.m_aAnnotations[nA] = it->second.aSortedAnnots[nA].nObject;
+ }
+ else
+ {
+ DBG_ASSERT( 0, "wrong number of sorted annotations" );
+ #if OSL_DEBUG_LEVEL > 0
+ fprintf( stderr, "PDFWriterImpl::sortWidgets(): wrong number of sorted assertions on page nr %ld\n"
+ " %ld sorted and %ld unsorted\n", (long int)it->first, (long int)it->second.aSortedAnnots.size(), (long int)nAnnots );
+ #endif
+ }
+ }
+
+ // FIXME: implement tab order in structure tree for PDF 1.5
+}
+
+namespace vcl {
+class PDFStreamIf :
+ public cppu::WeakImplHelper1< com::sun::star::io::XOutputStream >
+{
+ PDFWriterImpl* m_pWriter;
+ bool m_bWrite;
+ public:
+ PDFStreamIf( PDFWriterImpl* pWriter ) : m_pWriter( pWriter ), m_bWrite( true ) {}
+ virtual ~PDFStreamIf();
+
+ virtual void SAL_CALL writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw();
+ virtual void SAL_CALL flush() throw();
+ virtual void SAL_CALL closeOutput() throw();
+};
+}
+
+PDFStreamIf::~PDFStreamIf()
+{
+}
+
+void SAL_CALL PDFStreamIf::writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw()
+{
+ if( m_bWrite )
+ {
+ sal_Int32 nBytes = aData.getLength();
+ if( nBytes > 0 )
+ m_pWriter->writeBuffer( aData.getConstArray(), nBytes );
+ }
+}
+
+void SAL_CALL PDFStreamIf::flush() throw()
+{
+}
+
+void SAL_CALL PDFStreamIf::closeOutput() throw()
+{
+ m_bWrite = false;
+}
+
+bool PDFWriterImpl::emitAdditionalStreams()
+{
+ unsigned int nStreams = m_aAdditionalStreams.size();
+ for( unsigned int i = 0; i < nStreams; i++ )
+ {
+ PDFAddStream& rStream = m_aAdditionalStreams[i];
+ rStream.m_nStreamObject = createObject();
+ sal_Int32 nSizeObject = createObject();
+
+ if( ! updateObject( rStream.m_nStreamObject ) )
+ return false;
+
+ OStringBuffer aLine;
+ aLine.append( rStream.m_nStreamObject );
+ aLine.append( " 0 obj\n<</Length " );
+ aLine.append( nSizeObject );
+ aLine.append( " 0 R" );
+ if( rStream.m_bCompress )
+ aLine.append( "/Filter/FlateDecode" );
+ aLine.append( ">>\nstream\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ return false;
+ sal_uInt64 nBeginStreamPos = 0, nEndStreamPos = 0;
+ if( osl_File_E_None != osl_getFilePos( m_aFile, &nBeginStreamPos ) )
+ {
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+ }
+ if( rStream.m_bCompress )
+ beginCompression();
+
+ checkAndEnableStreamEncryption( rStream.m_nStreamObject );
+ com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xStream( new PDFStreamIf( this ) );
+ rStream.m_pStream->write( xStream );
+ xStream.clear();
+ delete rStream.m_pStream;
+ rStream.m_pStream = NULL;
+ disableStreamEncryption();
+
+ if( rStream.m_bCompress )
+ endCompression();
+
+ if( osl_File_E_None != osl_getFilePos( m_aFile, &nEndStreamPos ) )
+ {
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+ return false;
+ }
+ if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
+ return false ;
+ // emit stream length object
+ if( ! updateObject( nSizeObject ) )
+ return false;
+ aLine.setLength( 0 );
+ aLine.append( nSizeObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
+ aLine.append( "\nendobj\n\n" );
+ if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ return false;
+ }
+ return true;
+}
+
+bool PDFWriterImpl::emit()
+{
+ endPage();
+
+ // resort structure tree and annotations if necessary
+ // needed for widget tab order
+ sortWidgets();
+
+ // emit additional streams
+ CHECK_RETURN( emitAdditionalStreams() );
+
+ // emit catalog
+ CHECK_RETURN( emitCatalog() );
+
+ // emit trailer
+ CHECK_RETURN( emitTrailer() );
+
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+
+ return true;
+}
+
+std::set< PDFWriter::ErrorCode > PDFWriterImpl::getErrors()
+{
+ return m_aErrors;
+}
+
+sal_Int32 PDFWriterImpl::getSystemFont( const Font& i_rFont )
+{
+ getReferenceDevice()->Push();
+ getReferenceDevice()->SetFont( i_rFont );
+ getReferenceDevice()->ImplNewFont();
+
+ const ImplFontData* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
+ sal_Int32 nFontID = 0;
+ FontEmbedData::iterator it = m_aSystemFonts.find( pDevFont );
+ if( it != m_aSystemFonts.end() )
+ nFontID = it->second.m_nNormalFontID;
+ else
+ {
+ nFontID = m_nNextFID++;
+ m_aSystemFonts[ pDevFont ] = EmbedFont();
+ m_aSystemFonts[ pDevFont ].m_nNormalFontID = nFontID;
+ }
+
+ getReferenceDevice()->Pop();
+ getReferenceDevice()->ImplNewFont();
+
+ return nFontID;
+}
+
+void PDFWriterImpl::registerGlyphs( int nGlyphs,
+ sal_GlyphId* pGlyphs,
+ sal_Int32* pGlyphWidths,
+ sal_Ucs* pUnicodes,
+ sal_Int32* pUnicodesPerGlyph,
+ sal_uInt8* pMappedGlyphs,
+ sal_Int32* pMappedFontObjects,
+ const ImplFontData* pFallbackFonts[] )
+{
+ const ImplFontData* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
+ sal_Ucs* pCurUnicode = pUnicodes;
+ for( int i = 0; i < nGlyphs; pCurUnicode += pUnicodesPerGlyph[i] , i++ )
+ {
+ const int nFontGlyphId = pGlyphs[i] & (GF_IDXMASK | GF_ISCHAR | GF_GSUB);
+ const ImplFontData* pCurrentFont = pFallbackFonts[i] ? pFallbackFonts[i] : pDevFont;
+
+ if( isBuiltinFont( pCurrentFont ) )
+ {
+ sal_Int32 nFontID = 0;
+ FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont );
+ if( it != m_aEmbeddedFonts.end() )
+ nFontID = it->second.m_nNormalFontID;
+ else
+ {
+ nFontID = m_nNextFID++;
+ m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont();
+ m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID;
+ }
+
+ pGlyphWidths[ i ] = 0;
+ pMappedGlyphs[ i ] = sal::static_int_cast<sal_Int8>( nFontGlyphId );
+ pMappedFontObjects[ i ] = nFontID;
+ const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pCurrentFont );
+ if( pFD )
+ {
+ const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
+ pGlyphWidths[i] = pBuiltinFont->m_aWidths[ nFontGlyphId & 0x00ff ];
+ }
+ }
+ else if( pCurrentFont->mbSubsettable )
+ {
+ FontSubset& rSubset = m_aSubsets[ pCurrentFont ];
+ // search for font specific glyphID
+ FontMapping::iterator it = rSubset.m_aMapping.find( nFontGlyphId );
+ if( it != rSubset.m_aMapping.end() )
+ {
+ pMappedFontObjects[i] = it->second.m_nFontID;
+ pMappedGlyphs[i] = it->second.m_nSubsetGlyphID;
+ }
+ else
+ {
+ // create new subset if necessary
+ if( rSubset.m_aSubsets.empty()
+ || (rSubset.m_aSubsets.back().m_aMapping.size() > 254) )
+ {
+ rSubset.m_aSubsets.push_back( FontEmit( m_nNextFID++ ) );
+ }
+
+ // copy font id
+ pMappedFontObjects[i] = rSubset.m_aSubsets.back().m_nFontID;
+ // create new glyph in subset
+ sal_uInt8 nNewId = sal::static_int_cast<sal_uInt8>(rSubset.m_aSubsets.back().m_aMapping.size()+1);
+ pMappedGlyphs[i] = nNewId;
+
+ // add new glyph to emitted font subset
+ GlyphEmit& rNewGlyphEmit = rSubset.m_aSubsets.back().m_aMapping[ nFontGlyphId ];
+ rNewGlyphEmit.setGlyphId( nNewId );
+ for( sal_Int32 n = 0; n < pUnicodesPerGlyph[i]; n++ )
+ rNewGlyphEmit.addCode( pCurUnicode[n] );
+
+ // add new glyph to font mapping
+ Glyph& rNewGlyph = rSubset.m_aMapping[ nFontGlyphId ];
+ rNewGlyph.m_nFontID = pMappedFontObjects[i];
+ rNewGlyph.m_nSubsetGlyphID = nNewId;
+ }
+ getReferenceDevice()->ImplGetGraphics();
+ const bool bVertical = ((pGlyphs[i] & GF_ROTMASK) != 0);
+ pGlyphWidths[i] = m_aFontCache.getGlyphWidth( pCurrentFont,
+ nFontGlyphId,
+ bVertical,
+ m_pReferenceDevice->mpGraphics );
+ }
+ else if( pCurrentFont->IsEmbeddable() )
+ {
+ sal_Int32 nFontID = 0;
+ FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont );
+ if( it != m_aEmbeddedFonts.end() )
+ nFontID = it->second.m_nNormalFontID;
+ else
+ {
+ nFontID = m_nNextFID++;
+ m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont();
+ m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID;
+ }
+ EmbedFont& rEmbedFont = m_aEmbeddedFonts[pCurrentFont];
+
+ const Ucs2SIntMap* pEncoding = NULL;
+ const Ucs2OStrMap* pNonEncoded = NULL;
+ getReferenceDevice()->ImplGetGraphics();
+ pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pCurrentFont, &pNonEncoded );
+
+ Ucs2SIntMap::const_iterator enc_it;
+ Ucs2OStrMap::const_iterator nonenc_it;
+
+ sal_Int32 nCurFontID = nFontID;
+ sal_Ucs cChar = *pCurUnicode;
+ if( pEncoding )
+ {
+ enc_it = pEncoding->find( cChar );
+ if( enc_it != pEncoding->end() && enc_it->second > 0 )
+ {
+ DBG_ASSERT( (enc_it->second & 0xffffff00) == 0, "Invalid character code" );
+ cChar = (sal_Ucs)enc_it->second;
+ }
+ else if( (enc_it == pEncoding->end() || enc_it->second == -1) &&
+ pNonEncoded &&
+ (nonenc_it = pNonEncoded->find( cChar )) != pNonEncoded->end() )
+ {
+ nCurFontID = 0;
+ // find non encoded glyph
+ for( std::list< EmbedEncoding >::iterator nec_it = rEmbedFont.m_aExtendedEncodings.begin(); nec_it != rEmbedFont.m_aExtendedEncodings.end(); ++nec_it )
+ {
+ if( nec_it->m_aCMap.find( cChar ) != nec_it->m_aCMap.end() )
+ {
+ nCurFontID = nec_it->m_nFontID;
+ cChar = (sal_Ucs)nec_it->m_aCMap[ cChar ];
+ break;
+ }
+ }
+ if( nCurFontID == 0 ) // new nonencoded glyph
+ {
+ if( rEmbedFont.m_aExtendedEncodings.empty() || rEmbedFont.m_aExtendedEncodings.back().m_aEncVector.size() == 255 )
+ {
+ rEmbedFont.m_aExtendedEncodings.push_back( EmbedEncoding() );
+ rEmbedFont.m_aExtendedEncodings.back().m_nFontID = m_nNextFID++;
+ }
+ EmbedEncoding& rEncoding = rEmbedFont.m_aExtendedEncodings.back();
+ rEncoding.m_aEncVector.push_back( EmbedCode() );
+ rEncoding.m_aEncVector.back().m_aUnicode = cChar;
+ rEncoding.m_aEncVector.back().m_aName = nonenc_it->second;
+ rEncoding.m_aCMap[ cChar ] = (sal_Int8)(rEncoding.m_aEncVector.size()-1);
+ nCurFontID = rEncoding.m_nFontID;
+ cChar = (sal_Ucs)rEncoding.m_aCMap[ cChar ];
+ }
+ }
+ else
+ pEncoding = NULL;
+ }
+ if( ! pEncoding )
+ {
+ if( cChar & 0xff00 )
+ {
+ // some characters can be used by conversion
+ if( cChar >= 0xf000 && cChar <= 0xf0ff ) // symbol encoding in private use area
+ cChar -= 0xf000;
+ else
+ {
+ String aString(cChar);
+ ByteString aChar( aString, RTL_TEXTENCODING_MS_1252 );
+ cChar = ((sal_Ucs)aChar.GetChar( 0 )) & 0x00ff;
+ }
+ }
+ }
+
+ pMappedGlyphs[ i ] = (sal_Int8)cChar;
+ pMappedFontObjects[ i ] = nCurFontID;
+ pGlyphWidths[ i ] = m_aFontCache.getGlyphWidth( pCurrentFont,
+ (pEncoding ? *pCurUnicode : cChar) | GF_ISCHAR,
+ false,
+ m_pReferenceDevice->mpGraphics );
+ }
+ }
+}
+
+void PDFWriterImpl::drawRelief( SalLayout& rLayout, const String& rText, bool bTextLines )
+{
+ push( PUSH_ALL );
+
+ FontRelief eRelief = m_aCurrentPDFState.m_aFont.GetRelief();
+
+ Color aTextColor = m_aCurrentPDFState.m_aFont.GetColor();
+ Color aTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
+ Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
+ Color aReliefColor( COL_LIGHTGRAY );
+ if( aTextColor == COL_BLACK )
+ aTextColor = Color( COL_WHITE );
+ if( aTextLineColor == COL_BLACK )
+ aTextLineColor = Color( COL_WHITE );
+ if( aOverlineColor == COL_BLACK )
+ aOverlineColor = Color( COL_WHITE );
+ if( aTextColor == COL_WHITE )
+ aReliefColor = Color( COL_BLACK );
+
+ Font aSetFont = m_aCurrentPDFState.m_aFont;
+ aSetFont.SetRelief( RELIEF_NONE );
+ aSetFont.SetShadow( FALSE );
+
+ aSetFont.SetColor( aReliefColor );
+ setTextLineColor( aReliefColor );
+ setOverlineColor( aReliefColor );
+ setFont( aSetFont );
+ long nOff = 1 + getReferenceDevice()->mnDPIX/300;
+ if( eRelief == RELIEF_ENGRAVED )
+ nOff = -nOff;
+
+ rLayout.DrawOffset() += Point( nOff, nOff );
+ updateGraphicsState();
+ drawLayout( rLayout, rText, bTextLines );
+
+ rLayout.DrawOffset() -= Point( nOff, nOff );
+ setTextLineColor( aTextLineColor );
+ setOverlineColor( aOverlineColor );
+ aSetFont.SetColor( aTextColor );
+ setFont( aSetFont );
+ updateGraphicsState();
+ drawLayout( rLayout, rText, bTextLines );
+
+ // clean up the mess
+ pop();
+}
+
+void PDFWriterImpl::drawShadow( SalLayout& rLayout, const String& rText, bool bTextLines )
+{
+ Font aSaveFont = m_aCurrentPDFState.m_aFont;
+ Color aSaveTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
+ Color aSaveOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
+
+ Font& rFont = m_aCurrentPDFState.m_aFont;
+ if( rFont.GetColor() == Color( COL_BLACK ) || rFont.GetColor().GetLuminance() < 8 )
+ rFont.SetColor( Color( COL_LIGHTGRAY ) );
+ else
+ rFont.SetColor( Color( COL_BLACK ) );
+ rFont.SetShadow( FALSE );
+ rFont.SetOutline( FALSE );
+ setFont( rFont );
+ setTextLineColor( rFont.GetColor() );
+ setOverlineColor( rFont.GetColor() );
+ updateGraphicsState();
+
+ long nOff = 1 + ((m_pReferenceDevice->mpFontEntry->mnLineHeight-24)/24);
+ if( rFont.IsOutline() )
+ nOff++;
+ rLayout.DrawBase() += Point( nOff, nOff );
+ drawLayout( rLayout, rText, bTextLines );
+ rLayout.DrawBase() -= Point( nOff, nOff );
+
+ setFont( aSaveFont );
+ setTextLineColor( aSaveTextLineColor );
+ setOverlineColor( aSaveOverlineColor );
+ updateGraphicsState();
+}
+
+void PDFWriterImpl::drawVerticalGlyphs(
+ const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
+ OStringBuffer& rLine,
+ const Point& rAlignOffset,
+ const Matrix3& rRotScale,
+ double fAngle,
+ double fXScale,
+ double fSkew,
+ sal_Int32 nFontHeight )
+{
+ long nXOffset = 0;
+ Point aCurPos( rGlyphs[0].m_aPos );
+ aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
+ aCurPos += rAlignOffset;
+ for( size_t i = 0; i < rGlyphs.size(); i++ )
+ {
+ // have to emit each glyph on its own
+ double fDeltaAngle = 0.0;
+ double fYScale = 1.0;
+ double fTempXScale = fXScale;
+ double fSkewB = fSkew;
+ double fSkewA = 0.0;
+
+ Point aDeltaPos;
+ if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTL )
+ {
+ fDeltaAngle = M_PI/2.0;
+ aDeltaPos.X() = m_pReferenceDevice->GetFontMetric().GetAscent();
+ aDeltaPos.Y() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent() * fXScale);
+ fYScale = fXScale;
+ fTempXScale = 1.0;
+ fSkewA = -fSkewB;
+ fSkewB = 0.0;
+ }
+ else if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTR )
+ {
+ fDeltaAngle = -M_PI/2.0;
+ aDeltaPos.X() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent()*fXScale);
+ aDeltaPos.Y() = -m_pReferenceDevice->GetFontMetric().GetAscent();
+ fYScale = fXScale;
+ fTempXScale = 1.0;
+ fSkewA = fSkewB;
+ fSkewB = 0.0;
+ }
+ aDeltaPos += (m_pReferenceDevice->PixelToLogic( Point( (int)((double)nXOffset/fXScale), 0 ) ) - m_pReferenceDevice->PixelToLogic( Point() ) );
+ if( i < rGlyphs.size()-1 )
+ nXOffset += rGlyphs[i+1].m_aPos.Y() - rGlyphs[i].m_aPos.Y();
+ if( ! rGlyphs[i].m_nGlyphId )
+ continue;
+
+ aDeltaPos = rRotScale.transform( aDeltaPos );
+
+ Matrix3 aMat;
+ if( fSkewB != 0.0 || fSkewA != 0.0 )
+ aMat.skew( fSkewA, fSkewB );
+ aMat.scale( fTempXScale, fYScale );
+ aMat.rotate( fAngle+fDeltaAngle );
+ aMat.translate( aCurPos.X()+aDeltaPos.X(), aCurPos.Y()+aDeltaPos.Y() );
+ aMat.append( m_aPages.back(), rLine );
+ rLine.append( " Tm" );
+ if( i == 0 || rGlyphs[i-1].m_nMappedFontId != rGlyphs[i].m_nMappedFontId )
+ {
+ rLine.append( " /F" );
+ rLine.append( rGlyphs[i].m_nMappedFontId );
+ rLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
+ rLine.append( " Tf" );
+ }
+ rLine.append( "<" );
+ appendHex( rGlyphs[i].m_nMappedGlyphId, rLine );
+ rLine.append( ">Tj\n" );
+ }
+}
+
+void PDFWriterImpl::drawHorizontalGlyphs(
+ const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
+ OStringBuffer& rLine,
+ const Point& rAlignOffset,
+ double fAngle,
+ double fXScale,
+ double fSkew,
+ sal_Int32 nFontHeight,
+ sal_Int32 nPixelFontHeight
+ )
+{
+ // horizontal (= normal) case
+
+ // fill in run end indices
+ // end is marked by index of the first glyph of the next run
+ // a run is marked by same mapped font id and same Y position
+ std::vector< sal_uInt32 > aRunEnds;
+ aRunEnds.reserve( rGlyphs.size() );
+ for( size_t i = 1; i < rGlyphs.size(); i++ )
+ {
+ if( rGlyphs[i].m_nMappedFontId != rGlyphs[i-1].m_nMappedFontId ||
+ rGlyphs[i].m_aPos.Y() != rGlyphs[i-1].m_aPos.Y() )
+ {
+ aRunEnds.push_back(i);
+ }
+ }
+ // last run ends at last glyph
+ aRunEnds.push_back( rGlyphs.size() );
+
+ // loop over runs of the same font
+ sal_uInt32 nBeginRun = 0;
+ for( size_t nRun = 0; nRun < aRunEnds.size(); nRun++ )
+ {
+ // setup text matrix
+ Point aCurPos = rGlyphs[nBeginRun].m_aPos;
+ // back transformation to current coordinate system
+ aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
+ aCurPos += rAlignOffset;
+ // the first run can be set with "Td" operator
+ // subsequent use of that operator would move
+ // the texline matrix relative to what was set before
+ // making use of that would drive us into rounding issues
+ Matrix3 aMat;
+ if( nRun == 0 && fAngle == 0.0 && fXScale == 1.0 && fSkew == 0.0 )
+ {
+ m_aPages.back().appendPoint( aCurPos, rLine, false );
+ rLine.append( " Td " );
+ }
+ else
+ {
+ if( fSkew != 0.0 )
+ aMat.skew( 0.0, fSkew );
+ aMat.scale( fXScale, 1.0 );
+ aMat.rotate( fAngle );
+ aMat.translate( aCurPos.X(), aCurPos.Y() );
+ aMat.append( m_aPages.back(), rLine );
+ rLine.append( " Tm\n" );
+ }
+ // set up correct font
+ rLine.append( "/F" );
+ rLine.append( rGlyphs[nBeginRun].m_nMappedFontId );
+ rLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
+ rLine.append( " Tf" );
+
+ // output glyphs using Tj or TJ
+ OStringBuffer aKernedLine( 256 ), aUnkernedLine( 256 );
+ aKernedLine.append( "[<" );
+ aUnkernedLine.append( '<' );
+ appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aKernedLine );
+ appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aUnkernedLine );
+
+ aMat.invert();
+ bool bNeedKern = false;
+ for( sal_uInt32 nPos = nBeginRun+1; nPos < aRunEnds[nRun]; nPos++ )
+ {
+ appendHex( rGlyphs[nPos].m_nMappedGlyphId, aUnkernedLine );
+ // check if default glyph positioning is sufficient
+ const Point aThisPos = aMat.transform( rGlyphs[nPos].m_aPos );
+ const Point aPrevPos = aMat.transform( rGlyphs[nPos-1].m_aPos );
+ double fAdvance = aThisPos.X() - aPrevPos.X();
+ fAdvance *= 1000.0 / nPixelFontHeight;
+ const sal_Int32 nAdjustment = (sal_Int32)(rGlyphs[nPos-1].m_nNativeWidth - fAdvance + 0.5);
+ if( nAdjustment != 0 )
+ {
+ // apply individual glyph positioning
+ bNeedKern = true;
+ aKernedLine.append( ">" );
+ aKernedLine.append( nAdjustment );
+ aKernedLine.append( "<" );
+ }
+ appendHex( rGlyphs[nPos].m_nMappedGlyphId, aKernedLine );
+ }
+ aKernedLine.append( ">]TJ\n" );
+ aUnkernedLine.append( ">Tj\n" );
+ rLine.append( bNeedKern ? aKernedLine : aUnkernedLine );
+
+ // set beginning of next run
+ nBeginRun = aRunEnds[nRun];
+ }
+}
+
+void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bTextLines )
+{
+ // relief takes precedence over shadow (see outdev3.cxx)
+ if( m_aCurrentPDFState.m_aFont.GetRelief() != RELIEF_NONE )
+ {
+ drawRelief( rLayout, rText, bTextLines );
+ return;
+ }
+ else if( m_aCurrentPDFState.m_aFont.IsShadow() )
+ drawShadow( rLayout, rText, bTextLines );
+
+ OStringBuffer aLine( 512 );
+
+ const int nMaxGlyphs = 256;
+
+ sal_GlyphId pGlyphs[nMaxGlyphs];
+ sal_Int32 pGlyphWidths[nMaxGlyphs];
+ sal_uInt8 pMappedGlyphs[nMaxGlyphs];
+ sal_Int32 pMappedFontObjects[nMaxGlyphs];
+ std::vector<sal_Ucs> aUnicodes;
+ aUnicodes.reserve( nMaxGlyphs );
+ sal_Int32 pUnicodesPerGlyph[nMaxGlyphs];
+ int pCharPosAry[nMaxGlyphs];
+ sal_Int32 nAdvanceWidths[nMaxGlyphs];
+ const ImplFontData* pFallbackFonts[nMaxGlyphs];
+ bool bVertical = m_aCurrentPDFState.m_aFont.IsVertical();
+ int nGlyphs;
+ int nIndex = 0;
+ int nMinCharPos = 0, nMaxCharPos = rText.Len()-1;
+ double fXScale = 1.0;
+ double fSkew = 0.0;
+ sal_Int32 nPixelFontHeight = m_pReferenceDevice->mpFontEntry->maFontSelData.mnHeight;
+ TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
+
+ // transform font height back to current units
+ // note: the layout calculates in outdevs device pixel !!
+ sal_Int32 nFontHeight = m_pReferenceDevice->ImplDevicePixelToLogicHeight( nPixelFontHeight );
+ if( m_aCurrentPDFState.m_aFont.GetWidth() )
+ {
+ Font aFont( m_aCurrentPDFState.m_aFont );
+ aFont.SetWidth( 0 );
+ FontMetric aMetric = m_pReferenceDevice->GetFontMetric( aFont );
+ if( aMetric.GetWidth() != m_aCurrentPDFState.m_aFont.GetWidth() )
+ {
+ fXScale =
+ (double)m_aCurrentPDFState.m_aFont.GetWidth() /
+ (double)aMetric.GetWidth();
+ }
+ // force state before GetFontMetric
+ m_pReferenceDevice->ImplNewFont();
+ }
+
+ // perform artificial italics if necessary
+ if( ( m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_NORMAL ||
+ m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_OBLIQUE ) &&
+ !( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_NORMAL ||
+ m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_OBLIQUE )
+ )
+ {
+ fSkew = M_PI/12.0;
+ }
+
+ // if the mapmode is distorted we need to adjust for that also
+ if( m_aCurrentPDFState.m_aMapMode.GetScaleX() != m_aCurrentPDFState.m_aMapMode.GetScaleY() )
+ {
+ fXScale *= double(m_aCurrentPDFState.m_aMapMode.GetScaleX()) / double(m_aCurrentPDFState.m_aMapMode.GetScaleY());
+ }
+
+ int nAngle = m_aCurrentPDFState.m_aFont.GetOrientation();
+ // normalize angles
+ while( nAngle < 0 )
+ nAngle += 3600;
+ nAngle = nAngle % 3600;
+ double fAngle = (double)nAngle * M_PI / 1800.0;
+
+ Matrix3 aRotScale;
+ aRotScale.scale( fXScale, 1.0 );
+ if( fAngle != 0.0 )
+ aRotScale.rotate( -fAngle );
+
+ bool bPop = false;
+ bool bABold = false;
+ // artificial bold necessary ?
+ if( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetWeight() <= WEIGHT_MEDIUM &&
+ m_pReferenceDevice->mpFontEntry->maFontSelData.GetWeight() > WEIGHT_MEDIUM )
+ {
+ if( ! bPop )
+ aLine.append( "q " );
+ bPop = true;
+ bABold = true;
+ }
+ // setup text colors (if necessary)
+ Color aStrokeColor( COL_TRANSPARENT );
+ Color aNonStrokeColor( COL_TRANSPARENT );
+
+ if( m_aCurrentPDFState.m_aFont.IsOutline() )
+ {
+ aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
+ aNonStrokeColor = Color( COL_WHITE );
+ }
+ else
+ aNonStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
+ if( bABold )
+ aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
+
+ if( aStrokeColor != Color( COL_TRANSPARENT ) && aStrokeColor != m_aCurrentPDFState.m_aLineColor )
+ {
+ if( ! bPop )
+ aLine.append( "q " );
+ bPop = true;
+ appendStrokingColor( aStrokeColor, aLine );
+ aLine.append( "\n" );
+ }
+ if( aNonStrokeColor != Color( COL_TRANSPARENT ) && aNonStrokeColor != m_aCurrentPDFState.m_aFillColor )
+ {
+ if( ! bPop )
+ aLine.append( "q " );
+ bPop = true;
+ appendNonStrokingColor( aNonStrokeColor, aLine );
+ aLine.append( "\n" );
+ }
+
+ // begin text object
+ aLine.append( "BT\n" );
+ // outline attribute ?
+ if( m_aCurrentPDFState.m_aFont.IsOutline() || bABold )
+ {
+ // set correct text mode, set stroke width
+ aLine.append( "2 Tr " ); // fill, then stroke
+
+ if( m_aCurrentPDFState.m_aFont.IsOutline() )
+ {
+ // unclear what to do in case of outline and artificial bold
+ // for the time being outline wins
+ aLine.append( "0.25 w \n" );
+ }
+ else
+ {
+ double fW = (double)m_aCurrentPDFState.m_aFont.GetHeight() / 30.0;
+ m_aPages.back().appendMappedLength( fW, aLine );
+ aLine.append ( " w\n" );
+ }
+ }
+
+ FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric();
+
+ // collect the glyphs into a single array
+ const int nTmpMaxGlyphs = rLayout.GetOrientation() ? 1 : nMaxGlyphs; // #i97991# temporary workaround for #i87686#
+ std::vector< PDFGlyph > aGlyphs;
+ aGlyphs.reserve( nTmpMaxGlyphs );
+ // first get all the glyphs and register them; coordinates still in Pixel
+ Point aGNGlyphPos;
+ while( (nGlyphs = rLayout.GetNextGlyphs( nTmpMaxGlyphs, pGlyphs, aGNGlyphPos, nIndex, nAdvanceWidths, pCharPosAry )) != 0 )
+ {
+ aUnicodes.clear();
+ for( int i = 0; i < nGlyphs; i++ )
+ {
+ pFallbackFonts[i] = rLayout.GetFallbackFontData( pGlyphs[i] );
+
+ // default case: 1 glyph is one unicode
+ pUnicodesPerGlyph[i] = 1;
+ if( (pGlyphs[i] & GF_ISCHAR) )
+ {
+ aUnicodes.push_back( static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK) );
+ }
+ else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos )
+ {
+ int nChars = 1;
+ aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]) ) );
+ pUnicodesPerGlyph[i] = 1;
+ // try to handle ligatures and such
+ if( i < nGlyphs-1 )
+ {
+ pUnicodesPerGlyph[i] = nChars = pCharPosAry[i+1] - pCharPosAry[i];
+ for( int n = 1; n < nChars; n++ )
+ aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]+n) ) );
+ }
+ // #i36691# hack that is needed because currently the pGlyphs[]
+ // argument is ignored for embeddable fonts and so the layout
+ // engine's glyph work is ignored (i.e. char mirroring)
+ // TODO: a real solution would be to map the layout engine's
+ // glyphid (i.e. FreeType's synthetic glyphid for a Type1 font)
+ // back to unicode and then to embeddable font's encoding
+ if( getReferenceDevice()->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL )
+ {
+ size_t nI = aUnicodes.size()-1;
+ for( int n = 0; n < nChars; n++, nI-- )
+ aUnicodes[nI] = static_cast<sal_Ucs>(GetMirroredChar(aUnicodes[nI]));
+ }
+ }
+ else
+ aUnicodes.push_back( 0 );
+ // note: in case of ctl one character may result
+ // in multiple glyphs. The current SalLayout
+ // implementations set -1 then to indicate that no direct
+ // mapping is possible
+ }
+
+ registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, &aUnicodes[0], pUnicodesPerGlyph, pMappedGlyphs, pMappedFontObjects, pFallbackFonts );
+
+ for( int i = 0; i < nGlyphs; i++ )
+ {
+ aGlyphs.push_back( PDFGlyph( aGNGlyphPos,
+ pGlyphWidths[i],
+ pGlyphs[i],
+ pMappedFontObjects[i],
+ pMappedGlyphs[i] ) );
+ if( bVertical )
+ aGNGlyphPos.Y() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
+ else
+ aGNGlyphPos.X() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
+ }
+ }
+
+ Point aAlignOffset;
+ if ( eAlign == ALIGN_BOTTOM )
+ aAlignOffset.Y() -= aRefDevFontMetric.GetDescent();
+ else if ( eAlign == ALIGN_TOP )
+ aAlignOffset.Y() += aRefDevFontMetric.GetAscent();
+ if( aAlignOffset.X() || aAlignOffset.Y() )
+ aAlignOffset = aRotScale.transform( aAlignOffset );
+
+ /* #159153# do not emit an empty glyph vector; this can happen if e.g. the original
+ string contained only on of the UTF16 BOMs
+ */
+ if( ! aGlyphs.empty() )
+ {
+ if( bVertical )
+ drawVerticalGlyphs( aGlyphs, aLine, aAlignOffset, aRotScale, fAngle, fXScale, fSkew, nFontHeight );
+ else
+ drawHorizontalGlyphs( aGlyphs, aLine, aAlignOffset, fAngle, fXScale, fSkew, nFontHeight, nPixelFontHeight );
+ }
+
+ // end textobject
+ aLine.append( "ET\n" );
+ if( bPop )
+ aLine.append( "Q\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ // draw eventual textlines
+ FontStrikeout eStrikeout = m_aCurrentPDFState.m_aFont.GetStrikeout();
+ FontUnderline eUnderline = m_aCurrentPDFState.m_aFont.GetUnderline();
+ FontUnderline eOverline = m_aCurrentPDFState.m_aFont.GetOverline();
+ if( bTextLines &&
+ (
+ ( eUnderline != UNDERLINE_NONE && eUnderline != UNDERLINE_DONTKNOW ) ||
+ ( eOverline != UNDERLINE_NONE && eOverline != UNDERLINE_DONTKNOW ) ||
+ ( eStrikeout != STRIKEOUT_NONE && eStrikeout != STRIKEOUT_DONTKNOW )
+ )
+ )
+ {
+ BOOL bUnderlineAbove = OutputDevice::ImplIsUnderlineAbove( m_aCurrentPDFState.m_aFont );
+ if( m_aCurrentPDFState.m_aFont.IsWordLineMode() )
+ {
+ Point aPos, aStartPt;
+ sal_Int32 nWidth = 0, nAdvance=0;
+ for( int nStart = 0;;)
+ {
+ sal_GlyphId nGlyphIndex;
+ if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
+ break;
+
+ if( !rLayout.IsSpacingGlyph( nGlyphIndex ) )
+ {
+ if( !nWidth )
+ aStartPt = aPos;
+
+ nWidth += nAdvance;
+ }
+ else if( nWidth > 0 )
+ {
+ drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
+ m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
+ eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+ nWidth = 0;
+ }
+ }
+
+ if( nWidth > 0 )
+ {
+ drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
+ m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
+ eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+ }
+ }
+ else
+ {
+ Point aStartPt = rLayout.GetDrawPosition();
+ int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel();
+ drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
+ m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
+ eStrikeout, eUnderline, eOverline, bUnderlineAbove );
+ }
+ }
+
+ // write eventual emphasis marks
+ if( m_aCurrentPDFState.m_aFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
+ {
+ PolyPolygon aEmphPoly;
+ Rectangle aEmphRect1;
+ Rectangle aEmphRect2;
+ long nEmphYOff;
+ long nEmphWidth;
+ long nEmphHeight;
+ BOOL bEmphPolyLine;
+ FontEmphasisMark nEmphMark;
+
+ push( PUSH_ALL );
+
+ aLine.setLength( 0 );
+ aLine.append( "q\n" );
+
+ nEmphMark = m_pReferenceDevice->ImplGetEmphasisMarkStyle( m_aCurrentPDFState.m_aFont );
+ if ( nEmphMark & EMPHASISMARK_POS_BELOW )
+ nEmphHeight = m_pReferenceDevice->mnEmphasisDescent;
+ else
+ nEmphHeight = m_pReferenceDevice->mnEmphasisAscent;
+ m_pReferenceDevice->ImplGetEmphasisMark( aEmphPoly,
+ bEmphPolyLine,
+ aEmphRect1,
+ aEmphRect2,
+ nEmphYOff,
+ nEmphWidth,
+ nEmphMark,
+ m_pReferenceDevice->ImplDevicePixelToLogicWidth(nEmphHeight),
+ m_pReferenceDevice->mpFontEntry->mnOrientation );
+ if ( bEmphPolyLine )
+ {
+ setLineColor( m_aCurrentPDFState.m_aFont.GetColor() );
+ setFillColor( Color( COL_TRANSPARENT ) );
+ }
+ else
+ {
+ setFillColor( m_aCurrentPDFState.m_aFont.GetColor() );
+ setLineColor( Color( COL_TRANSPARENT ) );
+ }
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ Point aOffset = Point(0,0);
+
+ if ( nEmphMark & EMPHASISMARK_POS_BELOW )
+ aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnDescent + nEmphYOff;
+ else
+ aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnAscent + nEmphYOff;
+
+ long nEmphWidth2 = nEmphWidth / 2;
+ long nEmphHeight2 = nEmphHeight / 2;
+ aOffset += Point( nEmphWidth2, nEmphHeight2 );
+
+ if ( eAlign == ALIGN_BOTTOM )
+ aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnDescent;
+ else if ( eAlign == ALIGN_TOP )
+ aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnAscent;
+
+ for( int nStart = 0;;)
+ {
+ Point aPos;
+ sal_GlyphId nGlyphIndex;
+ sal_Int32 nAdvance;
+ if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
+ break;
+
+ if( !rLayout.IsSpacingGlyph( nGlyphIndex ) )
+ {
+ Point aAdjOffset = aOffset;
+ aAdjOffset.X() += (nAdvance - nEmphWidth) / 2;
+ aAdjOffset = aRotScale.transform( aAdjOffset );
+
+ aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 );
+
+ aPos += aAdjOffset;
+ aPos = m_pReferenceDevice->PixelToLogic( aPos );
+ drawEmphasisMark( aPos.X(), aPos.Y(),
+ aEmphPoly, bEmphPolyLine,
+ aEmphRect1, aEmphRect2 );
+ }
+ }
+
+ writeBuffer( "Q\n", 2 );
+ pop();
+ }
+
+}
+
+void PDFWriterImpl::drawEmphasisMark( long nX, long nY,
+ const PolyPolygon& rPolyPoly, BOOL bPolyLine,
+ const Rectangle& rRect1, const Rectangle& rRect2 )
+{
+ // TODO: pass nWidth as width of this mark
+ // long nWidth = 0;
+
+ if ( rPolyPoly.Count() )
+ {
+ if ( bPolyLine )
+ {
+ Polygon aPoly = rPolyPoly.GetObject( 0 );
+ aPoly.Move( nX, nY );
+ drawPolyLine( aPoly );
+ }
+ else
+ {
+ PolyPolygon aPolyPoly = rPolyPoly;
+ aPolyPoly.Move( nX, nY );
+ drawPolyPolygon( aPolyPoly );
+ }
+ }
+
+ if ( !rRect1.IsEmpty() )
+ {
+ Rectangle aRect( Point( nX+rRect1.Left(),
+ nY+rRect1.Top() ), rRect1.GetSize() );
+ drawRectangle( aRect );
+ }
+
+ if ( !rRect2.IsEmpty() )
+ {
+ Rectangle aRect( Point( nX+rRect2.Left(),
+ nY+rRect2.Top() ), rRect2.GetSize() );
+
+ drawRectangle( aRect );
+ }
+}
+
+void PDFWriterImpl::drawText( const Point& rPos, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
+{
+ MARK( "drawText" );
+
+ updateGraphicsState();
+
+ // get a layout from the OuputDevice's SalGraphics
+ // this also enforces font substitution and sets the font on SalGraphics
+ SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos );
+ if( pLayout )
+ {
+ drawLayout( *pLayout, rText, bTextLines );
+ pLayout->Release();
+ }
+}
+
+void PDFWriterImpl::drawTextArray( const Point& rPos, const String& rText, const sal_Int32* pDXArray, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
+{
+ MARK( "drawText with array" );
+
+ updateGraphicsState();
+
+ // get a layout from the OuputDevice's SalGraphics
+ // this also enforces font substitution and sets the font on SalGraphics
+ SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray );
+ if( pLayout )
+ {
+ drawLayout( *pLayout, rText, bTextLines );
+ pLayout->Release();
+ }
+}
+
+void PDFWriterImpl::drawStretchText( const Point& rPos, ULONG nWidth, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
+{
+ MARK( "drawStretchText" );
+
+ updateGraphicsState();
+
+ // get a layout from the OuputDevice's SalGraphics
+ // this also enforces font substitution and sets the font on SalGraphics
+ SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, nWidth );
+ if( pLayout )
+ {
+ drawLayout( *pLayout, rText, bTextLines );
+ pLayout->Release();
+ }
+}
+
+void PDFWriterImpl::drawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle, bool bTextLines )
+{
+ long nWidth = rRect.GetWidth();
+ long nHeight = rRect.GetHeight();
+
+ if ( nWidth <= 0 || nHeight <= 0 )
+ return;
+
+ MARK( "drawText with rectangle" );
+
+ updateGraphicsState();
+
+ // clip with rectangle
+ OStringBuffer aLine;
+ aLine.append( "q " );
+ m_aPages.back().appendRect( rRect, aLine );
+ aLine.append( " W* n\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ // if disabled text is needed, put in here
+
+ Point aPos = rRect.TopLeft();
+
+ long nTextHeight = m_pReferenceDevice->GetTextHeight();
+ xub_StrLen nMnemonicPos = STRING_NOTFOUND;
+
+ String aStr = rOrigStr;
+ if ( nStyle & TEXT_DRAW_MNEMONIC )
+ aStr = m_pReferenceDevice->GetNonMnemonicString( aStr, nMnemonicPos );
+
+ // multiline text
+ if ( nStyle & TEXT_DRAW_MULTILINE )
+ {
+ XubString aLastLine;
+ ImplMultiTextLineInfo aMultiLineInfo;
+ ImplTextLineInfo* pLineInfo;
+ long nMaxTextWidth;
+ xub_StrLen i;
+ xub_StrLen nLines;
+ xub_StrLen nFormatLines;
+
+ if ( nTextHeight )
+ {
+ ::vcl::DefaultTextLayout aLayout( *m_pReferenceDevice );
+ nMaxTextWidth = OutputDevice::ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, aLayout );
+ nLines = (xub_StrLen)(nHeight/nTextHeight);
+ nFormatLines = aMultiLineInfo.Count();
+ if ( !nLines )
+ nLines = 1;
+ if ( nFormatLines > nLines )
+ {
+ if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
+ {
+ // handle last line
+ nFormatLines = nLines-1;
+
+ pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
+ aLastLine = aStr.Copy( pLineInfo->GetIndex() );
+ aLastLine.ConvertLineEnd( LINEEND_LF );
+ // replace line feed by space
+ xub_StrLen nLastLineLen = aLastLine.Len();
+ for ( i = 0; i < nLastLineLen; i++ )
+ {
+ if ( aLastLine.GetChar( i ) == _LF )
+ aLastLine.SetChar( i, ' ' );
+ }
+ aLastLine = m_pReferenceDevice->GetEllipsisString( aLastLine, nWidth, nStyle );
+ nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
+ nStyle |= TEXT_DRAW_TOP;
+ }
+ }
+
+ // vertical alignment
+ if ( nStyle & TEXT_DRAW_BOTTOM )
+ aPos.Y() += nHeight-(nFormatLines*nTextHeight);
+ else if ( nStyle & TEXT_DRAW_VCENTER )
+ aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
+
+ // draw all lines excluding the last
+ for ( i = 0; i < nFormatLines; i++ )
+ {
+ pLineInfo = aMultiLineInfo.GetLine( i );
+ if ( nStyle & TEXT_DRAW_RIGHT )
+ aPos.X() += nWidth-pLineInfo->GetWidth();
+ else if ( nStyle & TEXT_DRAW_CENTER )
+ aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
+ xub_StrLen nIndex = pLineInfo->GetIndex();
+ xub_StrLen nLineLen = pLineInfo->GetLen();
+ drawText( aPos, aStr, nIndex, nLineLen, bTextLines );
+ // mnemonics should not appear in documents,
+ // if the need arises, put them in here
+ aPos.Y() += nTextHeight;
+ aPos.X() = rRect.Left();
+ }
+
+
+ // output last line left adjusted since it was shortened
+ if ( aLastLine.Len() )
+ drawText( aPos, aLastLine, 0, STRING_LEN, bTextLines );
+ }
+ }
+ else
+ {
+ long nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
+
+ // Evt. Text kuerzen
+ if ( nTextWidth > nWidth )
+ {
+ if ( nStyle & (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) )
+ {
+ aStr = m_pReferenceDevice->GetEllipsisString( aStr, nWidth, nStyle );
+ nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
+ nStyle |= TEXT_DRAW_LEFT;
+ nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
+ }
+ }
+
+ // vertical alignment
+ if ( nStyle & TEXT_DRAW_RIGHT )
+ aPos.X() += nWidth-nTextWidth;
+ else if ( nStyle & TEXT_DRAW_CENTER )
+ aPos.X() += (nWidth-nTextWidth)/2;
+
+ if ( nStyle & TEXT_DRAW_BOTTOM )
+ aPos.Y() += nHeight-nTextHeight;
+ else if ( nStyle & TEXT_DRAW_VCENTER )
+ aPos.Y() += (nHeight-nTextHeight)/2;
+
+ // mnemonics should be inserted here if the need arises
+
+ // draw the actual text
+ drawText( aPos, aStr, 0, STRING_LEN, bTextLines );
+ }
+
+ // reset clip region to original value
+ aLine.setLength( 0 );
+ aLine.append( "Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop )
+{
+ MARK( "drawLine" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ OStringBuffer aLine;
+ m_aPages.back().appendPoint( rStart, aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( rStop, aLine );
+ aLine.append( " l S\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
+{
+ MARK( "drawLine with LineInfo" );
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ if( rInfo.GetStyle() == LINE_SOLID && rInfo.GetWidth() < 2 )
+ {
+ drawLine( rStart, rStop );
+ return;
+ }
+
+ OStringBuffer aLine;
+
+ aLine.append( "q " );
+ if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
+ {
+ m_aPages.back().appendPoint( rStart, aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( rStop, aLine );
+ aLine.append( " l S Q\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ }
+ else
+ {
+ PDFWriter::ExtLineInfo aInfo;
+ convertLineInfoToExtLineInfo( rInfo, aInfo );
+ Point aPolyPoints[2] = { rStart, rStop };
+ Polygon aPoly( 2, aPolyPoints );
+ drawPolyLine( aPoly, aInfo );
+ }
+}
+
+void PDFWriterImpl::drawWaveLine( const Point& rStart, const Point& rStop, sal_Int32 nDelta, sal_Int32 nLineWidth )
+{
+ Point aDiff( rStop-rStart );
+ double fLen = sqrt( (double)(aDiff.X()*aDiff.X() + aDiff.Y()*aDiff.Y()) );
+ if( fLen < 1.0 )
+ return;
+
+ MARK( "drawWaveLine" );
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ OStringBuffer aLine( 512 );
+ aLine.append( "q " );
+ m_aPages.back().appendMappedLength( nLineWidth, aLine, true );
+ aLine.append( " w " );
+
+ appendDouble( (double)aDiff.X()/fLen, aLine );
+ aLine.append( ' ' );
+ appendDouble( -(double)aDiff.Y()/fLen, aLine );
+ aLine.append( ' ' );
+ appendDouble( (double)aDiff.Y()/fLen, aLine );
+ aLine.append( ' ' );
+ appendDouble( (double)aDiff.X()/fLen, aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( rStart, aLine );
+ aLine.append( " cm " );
+ m_aPages.back().appendWaveLine( (sal_Int32)fLen, 0, nDelta, aLine );
+ aLine.append( "Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+#define WCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicWidth( x )
+#define HCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicHeight( x )
+
+void PDFWriterImpl::drawWaveTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
+{
+ // note: units in pFontEntry are ref device pixel
+ ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
+ long nLineHeight = 0;
+ long nLinePos = 0;
+
+ appendStrokingColor( aColor, aLine );
+ aLine.append( "\n" );
+
+ if ( bIsAbove )
+ {
+ if ( !pFontEntry->maMetric.mnAboveWUnderlineSize )
+ m_pReferenceDevice->ImplInitAboveTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnAboveWUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnAboveWUnderlineOffset );
+ }
+ else
+ {
+ if ( !pFontEntry->maMetric.mnWUnderlineSize )
+ m_pReferenceDevice->ImplInitTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnWUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnWUnderlineOffset );
+ }
+ if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
+ nLineHeight = 3;
+
+ long nLineWidth = getReferenceDevice()->mnDPIX/450;
+ if ( ! nLineWidth )
+ nLineWidth = 1;
+
+ if ( eTextLine == UNDERLINE_BOLDWAVE )
+ nLineWidth = 3*nLineWidth;
+
+ m_aPages.back().appendMappedLength( (sal_Int32)nLineWidth, aLine );
+ aLine.append( " w " );
+
+ if ( eTextLine == UNDERLINE_DOUBLEWAVE )
+ {
+ long nOrgLineHeight = nLineHeight;
+ nLineHeight /= 3;
+ if ( nLineHeight < 2 )
+ {
+ if ( nOrgLineHeight > 1 )
+ nLineHeight = 2;
+ else
+ nLineHeight = 1;
+ }
+ long nLineDY = nOrgLineHeight-(nLineHeight*2);
+ if ( nLineDY < nLineWidth )
+ nLineDY = nLineWidth;
+ long nLineDY2 = nLineDY/2;
+ if ( !nLineDY2 )
+ nLineDY2 = 1;
+
+ nLinePos -= nLineWidth-nLineDY2;
+
+ m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
+
+ nLinePos += nLineWidth+nLineDY;
+ m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
+ }
+ else
+ {
+ if ( eTextLine != UNDERLINE_BOLDWAVE )
+ nLinePos -= nLineWidth/2;
+ m_aPages.back().appendWaveLine( nWidth, -nLinePos, nLineHeight, aLine );
+ }
+}
+
+void PDFWriterImpl::drawStraightTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
+{
+ // note: units in pFontEntry are ref device pixel
+ ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
+ long nLineHeight = 0;
+ long nLinePos = 0;
+ long nLinePos2 = 0;
+
+ if ( eTextLine > UNDERLINE_BOLDWAVE )
+ eTextLine = UNDERLINE_SINGLE;
+
+ switch ( eTextLine )
+ {
+ case UNDERLINE_SINGLE:
+ case UNDERLINE_DOTTED:
+ case UNDERLINE_DASH:
+ case UNDERLINE_LONGDASH:
+ case UNDERLINE_DASHDOT:
+ case UNDERLINE_DASHDOTDOT:
+ if ( bIsAbove )
+ {
+ if ( !pFontEntry->maMetric.mnAboveUnderlineSize )
+ m_pReferenceDevice->ImplInitAboveTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnAboveUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnAboveUnderlineOffset );
+ }
+ else
+ {
+ if ( !pFontEntry->maMetric.mnUnderlineSize )
+ m_pReferenceDevice->ImplInitTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnUnderlineOffset );
+ }
+ break;
+ case UNDERLINE_BOLD:
+ case UNDERLINE_BOLDDOTTED:
+ case UNDERLINE_BOLDDASH:
+ case UNDERLINE_BOLDLONGDASH:
+ case UNDERLINE_BOLDDASHDOT:
+ case UNDERLINE_BOLDDASHDOTDOT:
+ if ( bIsAbove )
+ {
+ if ( !pFontEntry->maMetric.mnAboveBUnderlineSize )
+ m_pReferenceDevice->ImplInitAboveTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnAboveBUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnAboveBUnderlineOffset );
+ }
+ else
+ {
+ if ( !pFontEntry->maMetric.mnBUnderlineSize )
+ m_pReferenceDevice->ImplInitTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnBUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnBUnderlineOffset );
+ nLinePos += nLineHeight/2;
+ }
+ break;
+ case UNDERLINE_DOUBLE:
+ if ( bIsAbove )
+ {
+ if ( !pFontEntry->maMetric.mnAboveDUnderlineSize )
+ m_pReferenceDevice->ImplInitAboveTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnAboveDUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset1 );
+ nLinePos2 = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset2 );
+ }
+ else
+ {
+ if ( !pFontEntry->maMetric.mnDUnderlineSize )
+ m_pReferenceDevice->ImplInitTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnDUnderlineSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnDUnderlineOffset1 );
+ nLinePos2 = HCONV( pFontEntry->maMetric.mnDUnderlineOffset2 );
+ }
+ default:
+ break;
+ }
+
+ if ( nLineHeight )
+ {
+ m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
+ aLine.append( " w " );
+ appendStrokingColor( aColor, aLine );
+ aLine.append( "\n" );
+
+ switch ( eTextLine )
+ {
+ case UNDERLINE_DOTTED:
+ case UNDERLINE_BOLDDOTTED:
+ aLine.append( "[ " );
+ m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
+ aLine.append( " ] 0 d\n" );
+ break;
+ case UNDERLINE_DASH:
+ case UNDERLINE_LONGDASH:
+ case UNDERLINE_BOLDDASH:
+ case UNDERLINE_BOLDLONGDASH:
+ {
+ sal_Int32 nDashLength = 4*nLineHeight;
+ sal_Int32 nVoidLength = 2*nLineHeight;
+ if ( ( eTextLine == UNDERLINE_LONGDASH ) || ( eTextLine == UNDERLINE_BOLDLONGDASH ) )
+ nDashLength = 8*nLineHeight;
+
+ aLine.append( "[ " );
+ m_aPages.back().appendMappedLength( nDashLength, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
+ aLine.append( " ] 0 d\n" );
+ }
+ break;
+ case UNDERLINE_DASHDOT:
+ case UNDERLINE_BOLDDASHDOT:
+ {
+ sal_Int32 nDashLength = 4*nLineHeight;
+ sal_Int32 nVoidLength = 2*nLineHeight;
+ aLine.append( "[ " );
+ m_aPages.back().appendMappedLength( nDashLength, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
+ aLine.append( " ] 0 d\n" );
+ }
+ break;
+ case UNDERLINE_DASHDOTDOT:
+ case UNDERLINE_BOLDDASHDOTDOT:
+ {
+ sal_Int32 nDashLength = 4*nLineHeight;
+ sal_Int32 nVoidLength = 2*nLineHeight;
+ aLine.append( "[ " );
+ m_aPages.back().appendMappedLength( nDashLength, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
+ aLine.append( " ] 0 d\n" );
+ }
+ break;
+ default:
+ break;
+ }
+
+ aLine.append( "0 " );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
+ aLine.append( " m " );
+ m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
+ aLine.append( " l S\n" );
+ if ( eTextLine == UNDERLINE_DOUBLE )
+ {
+ aLine.append( "0 " );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
+ aLine.append( " m " );
+ m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
+ aLine.append( " l S\n" );
+ }
+ }
+}
+
+void PDFWriterImpl::drawStrikeoutLine( OStringBuffer& aLine, long nWidth, FontStrikeout eStrikeout, Color aColor )
+{
+ // note: units in pFontEntry are ref device pixel
+ ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
+ long nLineHeight = 0;
+ long nLinePos = 0;
+ long nLinePos2 = 0;
+
+ if ( eStrikeout > STRIKEOUT_X )
+ eStrikeout = STRIKEOUT_SINGLE;
+
+ switch ( eStrikeout )
+ {
+ case STRIKEOUT_SINGLE:
+ if ( !pFontEntry->maMetric.mnStrikeoutSize )
+ m_pReferenceDevice->ImplInitTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnStrikeoutSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnStrikeoutOffset );
+ break;
+ case STRIKEOUT_BOLD:
+ if ( !pFontEntry->maMetric.mnBStrikeoutSize )
+ m_pReferenceDevice->ImplInitTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnBStrikeoutSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnBStrikeoutOffset );
+ break;
+ case STRIKEOUT_DOUBLE:
+ if ( !pFontEntry->maMetric.mnDStrikeoutSize )
+ m_pReferenceDevice->ImplInitTextLineSize();
+ nLineHeight = HCONV( pFontEntry->maMetric.mnDStrikeoutSize );
+ nLinePos = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset1 );
+ nLinePos2 = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset2 );
+ break;
+ default:
+ break;
+ }
+
+ if ( nLineHeight )
+ {
+ m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
+ aLine.append( " w " );
+ appendStrokingColor( aColor, aLine );
+ aLine.append( "\n" );
+
+ aLine.append( "0 " );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
+ aLine.append( " m " );
+ m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
+ aLine.append( " l S\n" );
+
+ if ( eStrikeout == STRIKEOUT_DOUBLE )
+ {
+ aLine.append( "0 " );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
+ aLine.append( " m " );
+ m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
+ aLine.append( " l S\n" );
+ }
+ }
+}
+
+void PDFWriterImpl::drawStrikeoutChar( const Point& rPos, long nWidth, FontStrikeout eStrikeout )
+{
+ String aStrikeoutChar = String::CreateFromAscii( eStrikeout == STRIKEOUT_SLASH ? "/" : "X" );
+ String aStrikeout = aStrikeoutChar;
+ while( m_pReferenceDevice->GetTextWidth( aStrikeout ) < nWidth )
+ aStrikeout.Append( aStrikeout );
+
+ // do not get broader than nWidth modulo 1 character
+ while( m_pReferenceDevice->GetTextWidth( aStrikeout ) >= nWidth )
+ aStrikeout.Erase( 0, 1 );
+ aStrikeout.Append( aStrikeoutChar );
+ BOOL bShadow = m_aCurrentPDFState.m_aFont.IsShadow();
+ if ( bShadow )
+ {
+ Font aFont = m_aCurrentPDFState.m_aFont;
+ aFont.SetShadow( FALSE );
+ setFont( aFont );
+ updateGraphicsState();
+ }
+
+ // strikeout string is left aligned non-CTL text
+ ULONG nOrigTLM = m_pReferenceDevice->GetLayoutMode();
+ m_pReferenceDevice->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG|TEXT_LAYOUT_COMPLEX_DISABLED );
+ drawText( rPos, aStrikeout, 0, aStrikeout.Len(), false );
+ m_pReferenceDevice->SetLayoutMode( nOrigTLM );
+
+ if ( bShadow )
+ {
+ Font aFont = m_aCurrentPDFState.m_aFont;
+ aFont.SetShadow( TRUE );
+ setFont( aFont );
+ updateGraphicsState();
+ }
+}
+
+void PDFWriterImpl::drawTextLine( const Point& rPos, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bUnderlineAbove )
+{
+ if ( !nWidth ||
+ ( ((eStrikeout == STRIKEOUT_NONE)||(eStrikeout == STRIKEOUT_DONTKNOW)) &&
+ ((eUnderline == UNDERLINE_NONE)||(eUnderline == UNDERLINE_DONTKNOW)) &&
+ ((eOverline == UNDERLINE_NONE)||(eOverline == UNDERLINE_DONTKNOW)) ) )
+ return;
+
+ MARK( "drawTextLine" );
+ updateGraphicsState();
+
+ // note: units in pFontEntry are ref device pixel
+ ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
+ Color aUnderlineColor = m_aCurrentPDFState.m_aTextLineColor;
+ Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
+ Color aStrikeoutColor = m_aCurrentPDFState.m_aFont.GetColor();
+ bool bStrikeoutDone = false;
+ bool bUnderlineDone = false;
+ bool bOverlineDone = false;
+
+ if ( (eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X) )
+ {
+ drawStrikeoutChar( rPos, nWidth, eStrikeout );
+ bStrikeoutDone = true;
+ }
+
+ Point aPos( rPos );
+ TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
+ if( eAlign == ALIGN_TOP )
+ aPos.Y() += HCONV( pFontEntry->maMetric.mnAscent );
+ else if( eAlign == ALIGN_BOTTOM )
+ aPos.Y() -= HCONV( pFontEntry->maMetric.mnDescent );
+
+ OStringBuffer aLine( 512 );
+ // save GS
+ aLine.append( "q " );
+
+ // rotate and translate matrix
+ double fAngle = (double)m_aCurrentPDFState.m_aFont.GetOrientation() * M_PI / 1800.0;
+ Matrix3 aMat;
+ aMat.rotate( fAngle );
+ aMat.translate( aPos.X(), aPos.Y() );
+ aMat.append( m_aPages.back(), aLine );
+ aLine.append( " cm\n" );
+
+ if ( aUnderlineColor.GetTransparency() != 0 )
+ aUnderlineColor = aStrikeoutColor;
+
+ if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
+ (eUnderline == UNDERLINE_WAVE) ||
+ (eUnderline == UNDERLINE_DOUBLEWAVE) ||
+ (eUnderline == UNDERLINE_BOLDWAVE) )
+ {
+ drawWaveTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
+ bUnderlineDone = true;
+ }
+
+ if ( (eOverline == UNDERLINE_SMALLWAVE) ||
+ (eOverline == UNDERLINE_WAVE) ||
+ (eOverline == UNDERLINE_DOUBLEWAVE) ||
+ (eOverline == UNDERLINE_BOLDWAVE) )
+ {
+ drawWaveTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
+ bOverlineDone = true;
+ }
+
+ if ( !bUnderlineDone )
+ {
+ drawStraightTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
+ }
+
+ if ( !bOverlineDone )
+ {
+ drawStraightTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
+ }
+
+ if ( !bStrikeoutDone )
+ {
+ drawStrikeoutLine( aLine, nWidth, eStrikeout, aStrikeoutColor );
+ }
+
+ aLine.append( "Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawPolygon( const Polygon& rPoly )
+{
+ MARK( "drawPolygon" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ int nPoints = rPoly.GetSize();
+ OStringBuffer aLine( 20 * nPoints );
+ m_aPages.back().appendPolygon( rPoly, aLine );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "B*\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "S\n" );
+ else
+ aLine.append( "f*\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ MARK( "drawPolyPolygon" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ int nPolygons = rPolyPoly.Count();
+
+ OStringBuffer aLine( 40 * nPolygons );
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "B*\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "S\n" );
+ else
+ aLine.append( "f*\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent )
+{
+ DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
+ nTransparentPercent = nTransparentPercent % 100;
+
+ MARK( "drawTransparent" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ if( m_bIsPDF_A1 || m_aContext.Version < PDFWriter::PDF_1_4 )
+ {
+ m_aErrors.insert( m_bIsPDF_A1 ?
+ PDFWriter::Warning_Transparency_Omitted_PDFA :
+ PDFWriter::Warning_Transparency_Omitted_PDF13 );
+
+ drawPolyPolygon( rPolyPoly );
+ return;
+ }
+
+ // create XObject
+ m_aTransparentObjects.push_back( TransparencyEmit() );
+ // FIXME: polygons with beziers may yield incorrect bound rect
+ m_aTransparentObjects.back().m_aBoundRect = rPolyPoly.GetBoundRect();
+ // convert rectangle to default user space
+ m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
+ m_aTransparentObjects.back().m_nObject = createObject();
+ m_aTransparentObjects.back().m_nExtGStateObject = createObject();
+ m_aTransparentObjects.back().m_fAlpha = (double)(100-nTransparentPercent) / 100.0;
+ m_aTransparentObjects.back().m_pContentStream = new SvMemoryStream( 256, 256 );
+ // create XObject's content stream
+ OStringBuffer aContent( 256 );
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aContent );
+ if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aCurrentPDFState.m_aFillColor != Color( COL_TRANSPARENT ) )
+ aContent.append( " B*\n" );
+ else if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) )
+ aContent.append( " S\n" );
+ else
+ aContent.append( " f*\n" );
+ m_aTransparentObjects.back().m_pContentStream->Write( aContent.getStr(), aContent.getLength() );
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( "Tr" );
+ aObjName.append( m_aTransparentObjects.back().m_nObject );
+ OString aTrName( aObjName.makeStringAndClear() );
+ aObjName.append( "EGS" );
+ aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
+ OString aExtName( aObjName.makeStringAndClear() );
+
+ OStringBuffer aLine( 80 );
+ // insert XObject
+ aLine.append( "q /" );
+ aLine.append( aExtName );
+ aLine.append( " gs /" );
+ aLine.append( aTrName );
+ aLine.append( " Do Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
+ pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
+}
+
+void PDFWriterImpl::pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject )
+{
+ if( nObject >= 0 )
+ {
+ switch( eKind )
+ {
+ case ResXObject:
+ m_aGlobalResourceDict.m_aXObjects[ rResource ] = nObject;
+ if( ! m_aOutputStreams.empty() )
+ m_aOutputStreams.front().m_aResourceDict.m_aXObjects[ rResource ] = nObject;
+ break;
+ case ResExtGState:
+ m_aGlobalResourceDict.m_aExtGStates[ rResource ] = nObject;
+ if( ! m_aOutputStreams.empty() )
+ m_aOutputStreams.front().m_aResourceDict.m_aExtGStates[ rResource ] = nObject;
+ break;
+ case ResShading:
+ m_aGlobalResourceDict.m_aShadings[ rResource ] = nObject;
+ if( ! m_aOutputStreams.empty() )
+ m_aOutputStreams.front().m_aResourceDict.m_aShadings[ rResource ] = nObject;
+ break;
+ case ResPattern:
+ m_aGlobalResourceDict.m_aPatterns[ rResource ] = nObject;
+ if( ! m_aOutputStreams.empty() )
+ m_aOutputStreams.front().m_aResourceDict.m_aPatterns[ rResource ] = nObject;
+ break;
+ }
+ }
+}
+
+void PDFWriterImpl::beginRedirect( SvStream* pStream, const Rectangle& rTargetRect )
+{
+ push( PUSH_ALL );
+
+ clearClipRegion();
+ updateGraphicsState();
+
+ m_aOutputStreams.push_front( StreamRedirect() );
+ m_aOutputStreams.front().m_pStream = pStream;
+ m_aOutputStreams.front().m_aMapMode = m_aMapMode;
+
+ if( !rTargetRect.IsEmpty() )
+ {
+ m_aOutputStreams.front().m_aTargetRect =
+ lcl_convert( m_aGraphicsStack.front().m_aMapMode,
+ m_aMapMode,
+ getReferenceDevice(),
+ rTargetRect );
+ Point aDelta = m_aOutputStreams.front().m_aTargetRect.BottomLeft();
+ long nPageHeight = pointToPixel(m_aPages[m_nCurrentPage].getHeight());
+ aDelta.Y() = -(nPageHeight - m_aOutputStreams.front().m_aTargetRect.Bottom());
+ m_aMapMode.SetOrigin( m_aMapMode.GetOrigin() + aDelta );
+ }
+
+ // setup graphics state for independent object stream
+
+ // force reemitting colors
+ m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
+ m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
+}
+
+Rectangle PDFWriterImpl::getRedirectTargetRect() const
+{
+ return m_aOutputStreams.empty() ? Rectangle() : m_aOutputStreams.front().m_aTargetRect;
+}
+
+SvStream* PDFWriterImpl::endRedirect()
+{
+ SvStream* pStream = NULL;
+ if( ! m_aOutputStreams.empty() )
+ {
+ pStream = m_aOutputStreams.front().m_pStream;
+ m_aMapMode = m_aOutputStreams.front().m_aMapMode;
+ m_aOutputStreams.pop_front();
+ }
+
+ pop();
+ // force reemitting colors
+ m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
+ m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
+
+ updateGraphicsState();
+
+ return pStream;
+}
+
+void PDFWriterImpl::beginTransparencyGroup()
+{
+ updateGraphicsState();
+ if( m_aContext.Version >= PDFWriter::PDF_1_4 )
+ beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
+}
+
+void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent )
+{
+ DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
+ nTransparentPercent = nTransparentPercent % 100;
+
+ if( m_aContext.Version >= PDFWriter::PDF_1_4 )
+ {
+ // create XObject
+ m_aTransparentObjects.push_back( TransparencyEmit() );
+ m_aTransparentObjects.back().m_aBoundRect = rBoundingBox;
+ // convert rectangle to default user space
+ m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
+ m_aTransparentObjects.back().m_nObject = createObject();
+ m_aTransparentObjects.back().m_fAlpha = (double)(100-nTransparentPercent) / 100.0;
+ // get XObject's content stream
+ m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
+ m_aTransparentObjects.back().m_nExtGStateObject = createObject();
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( "Tr" );
+ aObjName.append( m_aTransparentObjects.back().m_nObject );
+ OString aTrName( aObjName.makeStringAndClear() );
+ aObjName.append( "EGS" );
+ aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
+ OString aExtName( aObjName.makeStringAndClear() );
+
+ OStringBuffer aLine( 80 );
+ // insert XObject
+ aLine.append( "q /" );
+ aLine.append( aExtName );
+ aLine.append( " gs /" );
+ aLine.append( aTrName );
+ aLine.append( " Do Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
+ pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
+ }
+}
+
+void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, const Bitmap& rAlphaMask )
+{
+ if( m_aContext.Version >= PDFWriter::PDF_1_4 )
+ {
+ // create XObject
+ m_aTransparentObjects.push_back( TransparencyEmit() );
+ m_aTransparentObjects.back().m_aBoundRect = rBoundingBox;
+ // convert rectangle to default user space
+ m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
+ m_aTransparentObjects.back().m_nObject = createObject();
+ m_aTransparentObjects.back().m_fAlpha = 0.0;
+ // get XObject's content stream
+ m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
+ m_aTransparentObjects.back().m_nExtGStateObject = createObject();
+
+ // draw soft mask
+ beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
+ drawBitmap( rBoundingBox.TopLeft(), rBoundingBox.GetSize(), rAlphaMask );
+ m_aTransparentObjects.back().m_pSoftMaskStream = static_cast<SvMemoryStream*>(endRedirect());
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( "Tr" );
+ aObjName.append( m_aTransparentObjects.back().m_nObject );
+ OString aTrName( aObjName.makeStringAndClear() );
+ aObjName.append( "EGS" );
+ aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
+ OString aExtName( aObjName.makeStringAndClear() );
+
+ OStringBuffer aLine( 80 );
+ // insert XObject
+ aLine.append( "q /" );
+ aLine.append( aExtName );
+ aLine.append( " gs /" );
+ aLine.append( aTrName );
+ aLine.append( " Do Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
+ pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
+ }
+}
+
+void PDFWriterImpl::drawRectangle( const Rectangle& rRect )
+{
+ MARK( "drawRectangle" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ OStringBuffer aLine( 40 );
+ m_aPages.back().appendRect( rRect, aLine );
+
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( " B*\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( " S\n" );
+ else
+ aLine.append( " f*\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound )
+{
+ MARK( "drawRectangle with rounded edges" );
+
+ if( !nHorzRound && !nVertRound )
+ drawRectangle( rRect );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ if( nHorzRound > (sal_uInt32)rRect.GetWidth()/2 )
+ nHorzRound = rRect.GetWidth()/2;
+ if( nVertRound > (sal_uInt32)rRect.GetHeight()/2 )
+ nVertRound = rRect.GetHeight()/2;
+
+ Point aPoints[16];
+ const double kappa = 0.5522847498;
+ const sal_uInt32 kx = (sal_uInt32)((kappa*(double)nHorzRound)+0.5);
+ const sal_uInt32 ky = (sal_uInt32)((kappa*(double)nVertRound)+0.5);
+
+ aPoints[1] = Point( rRect.TopLeft().X() + nHorzRound, rRect.TopLeft().Y() );
+ aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() );
+ aPoints[2] = Point( rRect.TopRight().X()+1 - nHorzRound, aPoints[1].Y() );
+ aPoints[3] = Point( aPoints[2].X()+kx, aPoints[2].Y() );
+
+ aPoints[5] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y()+nVertRound );
+ aPoints[4] = Point( aPoints[5].X(), aPoints[5].Y()-ky );
+ aPoints[6] = Point( aPoints[5].X(), rRect.BottomRight().Y()+1 - nVertRound );
+ aPoints[7] = Point( aPoints[6].X(), aPoints[6].Y()+ky );
+
+ aPoints[9] = Point( rRect.BottomRight().X()+1-nHorzRound, rRect.BottomRight().Y()+1 );
+ aPoints[8] = Point( aPoints[9].X()+kx, aPoints[9].Y() );
+ aPoints[10] = Point( rRect.BottomLeft().X() + nHorzRound, aPoints[9].Y() );
+ aPoints[11] = Point( aPoints[10].X()-kx, aPoints[10].Y() );
+
+ aPoints[13] = Point( rRect.BottomLeft().X(), rRect.BottomLeft().Y()+1-nVertRound );
+ aPoints[12] = Point( aPoints[13].X(), aPoints[13].Y()+ky );
+ aPoints[14] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y()+nVertRound );
+ aPoints[15] = Point( aPoints[14].X(), aPoints[14].Y()-ky );
+
+
+ OStringBuffer aLine( 80 );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( aPoints[2], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[3], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[4], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[5], aLine );
+ aLine.append( " c\n" );
+ m_aPages.back().appendPoint( aPoints[6], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[7], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[8], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[9], aLine );
+ aLine.append( " c\n" );
+ m_aPages.back().appendPoint( aPoints[10], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[11], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[12], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[13], aLine );
+ aLine.append( " c\n" );
+ m_aPages.back().appendPoint( aPoints[14], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[15], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[0], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " c " );
+
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "b*\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "s\n" );
+ else
+ aLine.append( "f*\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawEllipse( const Rectangle& rRect )
+{
+ MARK( "drawEllipse" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ Point aPoints[12];
+ const double kappa = 0.5522847498;
+ const sal_uInt32 kx = (sal_uInt32)((kappa*(double)rRect.GetWidth()/2.0)+0.5);
+ const sal_uInt32 ky = (sal_uInt32)((kappa*(double)rRect.GetHeight()/2.0)+0.5);
+
+ aPoints[1] = Point( rRect.TopLeft().X() + rRect.GetWidth()/2, rRect.TopLeft().Y() );
+ aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() );
+ aPoints[2] = Point( aPoints[1].X() + kx, aPoints[1].Y() );
+
+ aPoints[4] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y() + rRect.GetHeight()/2 );
+ aPoints[3] = Point( aPoints[4].X(), aPoints[4].Y() - ky );
+ aPoints[5] = Point( aPoints[4].X(), aPoints[4].Y() + ky );
+
+ aPoints[7] = Point( rRect.BottomLeft().X() + rRect.GetWidth()/2, rRect.BottomLeft().Y()+1 );
+ aPoints[6] = Point( aPoints[7].X() + kx, aPoints[7].Y() );
+ aPoints[8] = Point( aPoints[7].X() - kx, aPoints[7].Y() );
+
+ aPoints[10] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y() + rRect.GetHeight()/2 );
+ aPoints[9] = Point( aPoints[10].X(), aPoints[10].Y() + ky );
+ aPoints[11] = Point( aPoints[10].X(), aPoints[10].Y() - ky );
+
+ OStringBuffer aLine( 80 );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( aPoints[2], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[3], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[4], aLine );
+ aLine.append( " c\n" );
+ m_aPages.back().appendPoint( aPoints[5], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[6], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[7], aLine );
+ aLine.append( " c\n" );
+ m_aPages.back().appendPoint( aPoints[8], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[9], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[10], aLine );
+ aLine.append( " c\n" );
+ m_aPages.back().appendPoint( aPoints[11], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[0], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " c " );
+
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "b*\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "s\n" );
+ else
+ aLine.append( "f*\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+static double calcAngle( const Rectangle& rRect, const Point& rPoint )
+{
+ Point aOrigin((rRect.Left()+rRect.Right()+1)/2,
+ (rRect.Top()+rRect.Bottom()+1)/2);
+ Point aPoint = rPoint - aOrigin;
+
+ double fX = (double)aPoint.X();
+ double fY = (double)-aPoint.Y();
+
+ if( rRect.GetWidth() > rRect.GetHeight() )
+ fY = fY*((double)rRect.GetWidth()/(double)rRect.GetHeight());
+ else if( rRect.GetHeight() > rRect.GetWidth() )
+ fX = fX*((double)rRect.GetHeight()/(double)rRect.GetWidth());
+ return atan2( fY, fX );
+}
+
+void PDFWriterImpl::drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWithChord )
+{
+ MARK( "drawArc" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ // calculate start and stop angles
+ const double fStartAngle = calcAngle( rRect, rStart );
+ double fStopAngle = calcAngle( rRect, rStop );
+ while( fStopAngle < fStartAngle )
+ fStopAngle += 2.0*M_PI;
+ const int nFragments = (int)((fStopAngle-fStartAngle)/(M_PI/2.0))+1;
+ const double fFragmentDelta = (fStopAngle-fStartAngle)/(double)nFragments;
+ const double kappa = fabs( 4.0 * (1.0-cos(fFragmentDelta/2.0))/sin(fFragmentDelta/2.0) / 3.0);
+ const double halfWidth = (double)rRect.GetWidth()/2.0;
+ const double halfHeight = (double)rRect.GetHeight()/2.0;
+
+ const Point aCenter( (rRect.Left()+rRect.Right()+1)/2,
+ (rRect.Top()+rRect.Bottom()+1)/2 );
+
+ OStringBuffer aLine( 30*nFragments );
+ Point aPoint( (int)(halfWidth * cos(fStartAngle) ),
+ -(int)(halfHeight * sin(fStartAngle) ) );
+ aPoint += aCenter;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( " m " );
+ if( !basegfx::fTools::equal(fStartAngle, fStopAngle) )
+ {
+ for( int i = 0; i < nFragments; i++ )
+ {
+ const double fStartFragment = fStartAngle + (double)i*fFragmentDelta;
+ const double fStopFragment = fStartFragment + fFragmentDelta;
+ aPoint = Point( (int)(halfWidth * (cos(fStartFragment) - kappa*sin(fStartFragment) ) ),
+ -(int)(halfHeight * (sin(fStartFragment) + kappa*cos(fStartFragment) ) ) );
+ aPoint += aCenter;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( ' ' );
+
+ aPoint = Point( (int)(halfWidth * (cos(fStopFragment) + kappa*sin(fStopFragment) ) ),
+ -(int)(halfHeight * (sin(fStopFragment) - kappa*cos(fStopFragment) ) ) );
+ aPoint += aCenter;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( ' ' );
+
+ aPoint = Point( (int)(halfWidth * cos(fStopFragment) ),
+ -(int)(halfHeight * sin(fStopFragment) ) );
+ aPoint += aCenter;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( " c\n" );
+ }
+ }
+ if( bWithChord || bWithPie )
+ {
+ if( bWithPie )
+ {
+ m_aPages.back().appendPoint( aCenter, aLine );
+ aLine.append( " l " );
+ }
+ aLine.append( "h " );
+ }
+ if( ! bWithChord && ! bWithPie )
+ aLine.append( "S\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "B*\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "S\n" );
+ else
+ aLine.append( "f*\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawPolyLine( const Polygon& rPoly )
+{
+ MARK( "drawPolyLine" );
+
+ USHORT nPoints = rPoly.GetSize();
+ if( nPoints < 2 )
+ return;
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ OStringBuffer aLine( 20 * nPoints );
+ m_aPages.back().appendPolygon( rPoly, aLine, rPoly[0] == rPoly[nPoints-1] );
+ aLine.append( "S\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
+{
+ MARK( "drawPolyLine with LineInfo" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ OStringBuffer aLine;
+ aLine.append( "q " );
+ if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
+ {
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ drawPolyLine( rPoly );
+ writeBuffer( "Q\n", 2 );
+ }
+ else
+ {
+ PDFWriter::ExtLineInfo aInfo;
+ convertLineInfoToExtLineInfo( rInfo, aInfo );
+ drawPolyLine( rPoly, aInfo );
+ }
+}
+
+void PDFWriterImpl::convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut )
+{
+ DBG_ASSERT( rIn.GetStyle() == LINE_DASH, "invalid conversion" );
+ rOut.m_fLineWidth = rIn.GetWidth();
+ rOut.m_fTransparency = 0.0;
+ rOut.m_eCap = PDFWriter::capButt;
+ rOut.m_eJoin = PDFWriter::joinMiter;
+ rOut.m_fMiterLimit = 10;
+ rOut.m_aDashArray.clear();
+
+ int nDashes = rIn.GetDashCount();
+ int nDashLen = rIn.GetDashLen();
+ int nDistance = rIn.GetDistance();
+ for( int n = 0; n < nDashes; n++ )
+ {
+ rOut.m_aDashArray.push_back( nDashLen );
+ rOut.m_aDashArray.push_back( nDistance );
+ }
+ int nDots = rIn.GetDotCount();
+ int nDotLen = rIn.GetDotLen();
+ for( int n = 0; n < nDots; n++ )
+ {
+ rOut.m_aDashArray.push_back( nDotLen );
+ rOut.m_aDashArray.push_back( nDistance );
+ }
+}
+
+void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo )
+{
+ MARK( "drawPolyLine with ExtLineInfo" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ if( rInfo.m_fTransparency >= 1.0 )
+ return;
+
+ if( rInfo.m_fTransparency != 0.0 )
+ beginTransparencyGroup();
+
+ OStringBuffer aLine;
+ aLine.append( "q " );
+ m_aPages.back().appendMappedLength( rInfo.m_fLineWidth, aLine );
+ aLine.append( " w" );
+ if( rInfo.m_aDashArray.size() < 10 ) // implmentation limit of acrobat reader
+ {
+ switch( rInfo.m_eCap )
+ {
+ default:
+ case PDFWriter::capButt: aLine.append( " 0 J" );break;
+ case PDFWriter::capRound: aLine.append( " 1 J" );break;
+ case PDFWriter::capSquare: aLine.append( " 2 J" );break;
+ }
+ switch( rInfo.m_eJoin )
+ {
+ default:
+ case PDFWriter::joinMiter:
+ {
+ double fLimit = rInfo.m_fMiterLimit;
+ if( rInfo.m_fLineWidth < rInfo.m_fMiterLimit )
+ fLimit = fLimit / rInfo.m_fLineWidth;
+ if( fLimit < 1.0 )
+ fLimit = 1.0;
+ aLine.append( " 0 j " );
+ appendDouble( fLimit, aLine );
+ aLine.append( " M" );
+ }
+ break;
+ case PDFWriter::joinRound: aLine.append( " 1 j" );break;
+ case PDFWriter::joinBevel: aLine.append( " 2 j" );break;
+ }
+ if( rInfo.m_aDashArray.size() > 0 )
+ {
+ aLine.append( " [ " );
+ for( std::vector<double>::const_iterator it = rInfo.m_aDashArray.begin();
+ it != rInfo.m_aDashArray.end(); ++it )
+ {
+ m_aPages.back().appendMappedLength( *it, aLine );
+ aLine.append( ' ' );
+ }
+ aLine.append( "] 0 d" );
+ }
+ aLine.append( "\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ drawPolyLine( rPoly );
+ }
+ else
+ {
+ basegfx::B2DPolygon aPoly(rPoly.getB2DPolygon());
+ basegfx::B2DPolyPolygon aPolyPoly;
+
+ basegfx::tools::applyLineDashing(aPoly, rInfo.m_aDashArray, &aPolyPoly);
+
+ // Old applyLineDashing subdivided the polygon. New one will create bezier curve segments.
+ // To mimic old behaviour, apply subdivide here. If beziers shall be written (better quality)
+ // this line needs to be removed and the loop below adapted accordingly
+ aPolyPoly = basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly);
+
+ const sal_uInt32 nPolygonCount(aPolyPoly.count());
+
+ for( sal_uInt32 nPoly = 0; nPoly < nPolygonCount; nPoly++ )
+ {
+ aLine.append( (nPoly != 0 && (nPoly & 7) == 0) ? "\n" : " " );
+ aPoly = aPolyPoly.getB2DPolygon( nPoly );
+ const sal_uInt32 nPointCount(aPoly.count());
+
+ if(nPointCount)
+ {
+ const sal_uInt32 nEdgeCount(aPoly.isClosed() ? nPointCount : nPointCount - 1);
+ basegfx::B2DPoint aCurrent(aPoly.getB2DPoint(0));
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ if( a > 0 )
+ aLine.append( " " );
+ const sal_uInt32 nNextIndex((a + 1) % nPointCount);
+ const basegfx::B2DPoint aNext(aPoly.getB2DPoint(nNextIndex));
+
+ m_aPages.back().appendPoint( Point( FRound(aCurrent.getX()),
+ FRound(aCurrent.getY()) ),
+ aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( Point( FRound(aNext.getX()),
+ FRound(aNext.getY()) ),
+ aLine );
+ aLine.append( " l" );
+
+ // prepare next edge
+ aCurrent = aNext;
+ }
+ }
+ }
+ aLine.append( " S " );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ }
+ writeBuffer( "Q\n", 2 );
+
+ if( rInfo.m_fTransparency != 0.0 )
+ {
+ // FIXME: actually this may be incorrect with bezier polygons
+ Rectangle aBoundRect( rPoly.GetBoundRect() );
+ // avoid clipping with thick lines
+ if( rInfo.m_fLineWidth > 0.0 )
+ {
+ sal_Int32 nLW = sal_Int32(rInfo.m_fLineWidth);
+ aBoundRect.Top() -= nLW;
+ aBoundRect.Left() -= nLW;
+ aBoundRect.Right() += nLW;
+ aBoundRect.Bottom() += nLW;
+ }
+ endTransparencyGroup( aBoundRect, (USHORT)(100.0*rInfo.m_fTransparency) );
+ }
+}
+
+void PDFWriterImpl::drawPixel( const Point& rPoint, const Color& rColor )
+{
+ MARK( "drawPixel" );
+
+ Color aColor = ( rColor == Color( COL_TRANSPARENT ) ? m_aGraphicsStack.front().m_aLineColor : rColor );
+
+ if( aColor == Color( COL_TRANSPARENT ) )
+ return;
+
+ // pixels are drawn in line color, so have to set
+ // the nonstroking color to line color
+ Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
+ setFillColor( aColor );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine( 20 );
+ m_aPages.back().appendPoint( rPoint, aLine );
+ aLine.append( ' ' );
+ appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aLine );
+ aLine.append( ' ' );
+ appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aLine );
+ aLine.append( " re f\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ setFillColor( aOldFillColor );
+}
+
+void PDFWriterImpl::drawPixel( const Polygon& rPoints, const Color* pColors )
+{
+ MARK( "drawPixel with Polygon" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && ! pColors )
+ return;
+
+ USHORT nPoints = rPoints.GetSize();
+ OStringBuffer aLine( nPoints*40 );
+ aLine.append( "q " );
+ if( ! pColors )
+ {
+ appendNonStrokingColor( m_aGraphicsStack.front().m_aLineColor, aLine );
+ aLine.append( ' ' );
+ }
+
+ OStringBuffer aPixel(32);
+ aPixel.append( ' ' );
+ appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aPixel );
+ aPixel.append( ' ' );
+ appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aPixel );
+ OString aPixelStr = aPixel.makeStringAndClear();
+ for( USHORT i = 0; i < nPoints; i++ )
+ {
+ if( pColors )
+ {
+ if( pColors[i] == Color( COL_TRANSPARENT ) )
+ continue;
+
+ appendNonStrokingColor( pColors[i], aLine );
+ aLine.append( ' ' );
+ }
+ m_aPages.back().appendPoint( rPoints[i], aLine );
+ aLine.append( aPixelStr );
+ aLine.append( " re f\n" );
+ }
+ aLine.append( "Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+class AccessReleaser
+{
+ BitmapReadAccess* m_pAccess;
+public:
+ AccessReleaser( BitmapReadAccess* pAccess ) : m_pAccess( pAccess ){}
+ ~AccessReleaser() { delete m_pAccess; }
+};
+
+bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject )
+{
+ CHECK_RETURN( updateObject( rObject.m_nObject ) );
+
+ bool bFlateFilter = compressStream( rObject.m_pContentStream );
+ rObject.m_pContentStream->Seek( STREAM_SEEK_TO_END );
+ ULONG nSize = rObject.m_pContentStream->Tell();
+ rObject.m_pContentStream->Seek( STREAM_SEEK_TO_BEGIN );
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( " PDFWriterImpl::writeTransparentObject" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+ OStringBuffer aLine( 512 );
+ CHECK_RETURN( updateObject( rObject.m_nObject ) );
+ aLine.append( rObject.m_nObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/XObject\n"
+ "/Subtype/Form\n"
+ "/BBox[ " );
+ appendFixedInt( rObject.m_aBoundRect.Left(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rObject.m_aBoundRect.Top(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rObject.m_aBoundRect.Right(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aLine );
+ aLine.append( " ]\n" );
+ if( ! rObject.m_pSoftMaskStream )
+ {
+ if( ! m_bIsPDF_A1 )
+ {
+ aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/K true>>\n" );
+ }
+ }
+ /* #i42884# the PDF reference recommends that each Form XObject
+ * should have a resource dict; alas if that is the same object
+ * as the one of the page it triggers an endless recursion in
+ * acroread 5 (6 and up have that fixed). Since we have only one
+ * resource dict anyway, let's use the one from the page by NOT
+ * emitting a Resources entry.
+ */
+ #if 0
+ aLine.append( " /Resources " );
+ aLine.append( getResourceDictObj() );
+ aLine.append( " 0 R\n" );
+ #endif
+
+ aLine.append( "/Length " );
+ aLine.append( (sal_Int32)(nSize) );
+ aLine.append( "\n" );
+ if( bFlateFilter )
+ aLine.append( "/Filter/FlateDecode\n" );
+ aLine.append( ">>\n"
+ "stream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ checkAndEnableStreamEncryption( rObject.m_nObject );
+ CHECK_RETURN( writeBuffer( rObject.m_pContentStream->GetData(), nSize ) );
+ disableStreamEncryption();
+ aLine.setLength( 0 );
+ aLine.append( "\n"
+ "endstream\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ // write ExtGState dict for this XObject
+ aLine.setLength( 0 );
+ aLine.append( rObject.m_nExtGStateObject );
+ aLine.append( " 0 obj\n"
+ "<<" );
+ if( ! rObject.m_pSoftMaskStream )
+ {
+//i59651
+ if( m_bIsPDF_A1 )
+ {
+ aLine.append( "/CA 1.0/ca 1.0" );
+ m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
+ }
+ else
+ {
+ aLine.append( "/CA " );
+ appendDouble( rObject.m_fAlpha, aLine );
+ aLine.append( "\n"
+ " /ca " );
+ appendDouble( rObject.m_fAlpha, aLine );
+ }
+ aLine.append( "\n" );
+ }
+ else
+ {
+ if( m_bIsPDF_A1 )
+ {
+ aLine.append( "/SMask/None" );
+ m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
+ }
+ else
+ {
+ rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_END );
+ sal_Int32 nMaskSize = (sal_Int32)rObject.m_pSoftMaskStream->Tell();
+ rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_BEGIN );
+ sal_Int32 nMaskObject = createObject();
+ aLine.append( "/SMask<</Type/Mask/S/Luminosity/G " );
+ aLine.append( nMaskObject );
+ aLine.append( " 0 R>>\n" );
+
+ OStringBuffer aMask;
+ aMask.append( nMaskObject );
+ aMask.append( " 0 obj\n"
+ "<</Type/XObject\n"
+ "/Subtype/Form\n"
+ "/BBox[" );
+ appendFixedInt( rObject.m_aBoundRect.Left(), aMask );
+ aMask.append( ' ' );
+ appendFixedInt( rObject.m_aBoundRect.Top(), aMask );
+ aMask.append( ' ' );
+ appendFixedInt( rObject.m_aBoundRect.Right(), aMask );
+ aMask.append( ' ' );
+ appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aMask );
+ aMask.append( "]\n" );
+
+ /* #i42884# see above */
+#if 0
+ aLine.append( "/Resources " );
+ aMask.append( getResourceDictObj() );
+ aMask.append( " 0 R\n" );
+#endif
+
+ aMask.append( "/Group<</S/Transparency/CS/DeviceRGB>>\n" );
+ aMask.append( "/Length " );
+ aMask.append( nMaskSize );
+ aMask.append( ">>\n"
+ "stream\n" );
+ CHECK_RETURN( updateObject( nMaskObject ) );
+ checkAndEnableStreamEncryption( nMaskObject );
+ CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
+ CHECK_RETURN( writeBuffer( rObject.m_pSoftMaskStream->GetData(), nMaskSize ) );
+ disableStreamEncryption();
+ aMask.setLength( 0 );
+ aMask.append( "\nendstream\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
+ }
+ }
+ aLine.append( ">>\n"
+ "endobj\n\n" );
+ CHECK_RETURN( updateObject( rObject.m_nExtGStateObject ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ return true;
+}
+
+bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
+{
+ sal_Int32 nFunctionObject = createObject();
+ CHECK_RETURN( updateObject( nFunctionObject ) );
+
+ OutputDevice* pRefDevice = getReferenceDevice();
+ pRefDevice->Push( PUSH_ALL );
+ if( rObject.m_aSize.Width() > pRefDevice->GetOutputSizePixel().Width() )
+ rObject.m_aSize.Width() = pRefDevice->GetOutputSizePixel().Width();
+ if( rObject.m_aSize.Height() > pRefDevice->GetOutputSizePixel().Height() )
+ rObject.m_aSize.Height() = pRefDevice->GetOutputSizePixel().Height();
+ pRefDevice->SetMapMode( MapMode( MAP_PIXEL ) );
+ pRefDevice->DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient );
+
+ Bitmap aSample = pRefDevice->GetBitmap( Point( 0, 0 ), rObject.m_aSize );
+ BitmapReadAccess* pAccess = aSample.AcquireReadAccess();
+ AccessReleaser aReleaser( pAccess );
+
+ Size aSize = aSample.GetSizePixel();
+
+ sal_Int32 nStreamLengthObject = createObject();
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( " PDFWriterImpl::writeGradientFunction" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+ OStringBuffer aLine( 120 );
+ aLine.append( nFunctionObject );
+ aLine.append( " 0 obj\n"
+ "<</FunctionType 0\n"
+ "/Domain[ 0 1 0 1 ]\n"
+ "/Size[ " );
+ aLine.append( (sal_Int32)aSize.Width() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aSize.Height() );
+ aLine.append( " ]\n"
+ "/BitsPerSample 8\n"
+ "/Range[ 0 1 0 1 0 1 ]\n"
+ "/Length " );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 R\n"
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ "/Filter/FlateDecode"
+#endif
+ ">>\n"
+ "stream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ sal_uInt64 nStartStreamPos = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartStreamPos )) );
+
+ checkAndEnableStreamEncryption( nFunctionObject );
+ beginCompression();
+ for( int y = 0; y < aSize.Height(); y++ )
+ {
+ for( int x = 0; x < aSize.Width(); x++ )
+ {
+ sal_uInt8 aCol[3];
+ BitmapColor aColor = pAccess->GetColor( y, x );
+ aCol[0] = aColor.GetRed();
+ aCol[1] = aColor.GetGreen();
+ aCol[2] = aColor.GetBlue();
+ CHECK_RETURN( writeBuffer( aCol, 3 ) );
+ }
+ }
+ endCompression();
+ disableStreamEncryption();
+
+ sal_uInt64 nEndStreamPos = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndStreamPos )) );
+
+ aLine.setLength( 0 );
+ aLine.append( "\nendstream\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ // write stream length
+ CHECK_RETURN( updateObject( nStreamLengthObject ) );
+ aLine.setLength( 0 );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( (sal_Int64)(nEndStreamPos-nStartStreamPos) );
+ aLine.append( "\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ CHECK_RETURN( updateObject( rObject.m_nObject ) );
+ aLine.setLength( 0 );
+ aLine.append( rObject.m_nObject );
+ aLine.append( " 0 obj\n"
+ "<</ShadingType 1\n"
+ "/ColorSpace/DeviceRGB\n"
+ "/AntiAlias true\n"
+ "/Domain[ 0 1 0 1 ]\n"
+ "/Matrix[ " );
+ aLine.append( (sal_Int32)aSize.Width() );
+ aLine.append( " 0 0 " );
+ aLine.append( (sal_Int32)aSize.Height() );
+ aLine.append( " 0 0 ]\n"
+ "/Function " );
+ aLine.append( nFunctionObject );
+ aLine.append( " 0 R\n"
+ ">>\n"
+ "endobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ pRefDevice->Pop();
+
+ return true;
+}
+
+bool PDFWriterImpl::writeJPG( JPGEmit& rObject )
+{
+ CHECK_RETURN( rObject.m_pStream );
+ CHECK_RETURN( updateObject( rObject.m_nObject ) );
+
+ sal_Int32 nLength = 0;
+ rObject.m_pStream->Seek( STREAM_SEEK_TO_END );
+ nLength = rObject.m_pStream->Tell();
+ rObject.m_pStream->Seek( STREAM_SEEK_TO_BEGIN );
+
+ sal_Int32 nMaskObject = 0;
+ if( !!rObject.m_aMask )
+ {
+ if( rObject.m_aMask.GetBitCount() == 1 ||
+ ( rObject.m_aMask.GetBitCount() == 8 && m_aContext.Version >= PDFWriter::PDF_1_4 && !m_bIsPDF_A1 )//i59651
+ )
+ {
+ nMaskObject = createObject();
+ }
+ else if( m_bIsPDF_A1 )
+ m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
+ else if( m_aContext.Version < PDFWriter::PDF_1_4 )
+ m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDF13 );
+
+ }
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( " PDFWriterImpl::writeJPG" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+
+ OStringBuffer aLine(200);
+ aLine.append( rObject.m_nObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/XObject/Subtype/Image/Width " );
+ aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Width() );
+ aLine.append( " /Height " );
+ aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Height() );
+ aLine.append( " /BitsPerComponent 8 " );
+ if( rObject.m_bTrueColor )
+ aLine.append( "/ColorSpace/DeviceRGB" );
+ else
+ aLine.append( "/ColorSpace/DeviceGray" );
+ aLine.append( "/Filter/DCTDecode/Length " );
+ aLine.append( nLength );
+ if( nMaskObject )
+ {
+ aLine.append( rObject.m_aMask.GetBitCount() == 1 ? " /Mask " : " /SMask " );
+ aLine.append( nMaskObject );
+ aLine.append( " 0 R " );
+ }
+ aLine.append( ">>\nstream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ checkAndEnableStreamEncryption( rObject.m_nObject );
+ CHECK_RETURN( writeBuffer( rObject.m_pStream->GetData(), nLength ) );
+ disableStreamEncryption();
+
+ aLine.setLength( 0 );
+ aLine.append( "\nendstream\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ if( nMaskObject )
+ {
+ BitmapEmit aEmit;
+ aEmit.m_nObject = nMaskObject;
+ if( rObject.m_aMask.GetBitCount() == 1 )
+ aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, rObject.m_aMask );
+ else if( rObject.m_aMask.GetBitCount() == 8 )
+ aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, AlphaMask( rObject.m_aMask ) );
+ writeBitmapObject( aEmit, true );
+ }
+
+ return true;
+}
+
+bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask )
+{
+ CHECK_RETURN( updateObject( rObject.m_nObject ) );
+
+ Bitmap aBitmap;
+ Color aTransparentColor( COL_TRANSPARENT );
+ bool bWriteMask = false;
+ if( ! bMask )
+ {
+ aBitmap = rObject.m_aBitmap.GetBitmap();
+ if( rObject.m_aBitmap.IsAlpha() )
+ {
+ if( m_aContext.Version >= PDFWriter::PDF_1_4 )
+ bWriteMask = true;
+ // else draw without alpha channel
+ }
+ else
+ {
+ switch( rObject.m_aBitmap.GetTransparentType() )
+ {
+ case TRANSPARENT_NONE:
+ // comes from drawMask function
+ if( aBitmap.GetBitCount() == 1 && rObject.m_bDrawMask )
+ bMask = true;
+ break;
+ case TRANSPARENT_COLOR:
+ aTransparentColor = rObject.m_aBitmap.GetTransparentColor();
+ break;
+ case TRANSPARENT_BITMAP:
+ bWriteMask = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if( m_aContext.Version < PDFWriter::PDF_1_4 || ! rObject.m_aBitmap.IsAlpha() )
+ {
+ aBitmap = rObject.m_aBitmap.GetMask();
+ aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+ DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
+ }
+ else if( aBitmap.GetBitCount() != 8 )
+ {
+ aBitmap = rObject.m_aBitmap.GetAlpha().GetBitmap();
+ aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
+ DBG_ASSERT( aBitmap.GetBitCount() == 8, "alpha mask conversion failed" );
+ }
+ }
+
+ BitmapReadAccess* pAccess = aBitmap.AcquireReadAccess();
+ AccessReleaser aReleaser( pAccess );
+
+ bool bTrueColor;
+ sal_Int32 nBitsPerComponent;
+ switch( aBitmap.GetBitCount() )
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ bTrueColor = false;
+ nBitsPerComponent = aBitmap.GetBitCount();
+ break;
+ default:
+ bTrueColor = true;
+ nBitsPerComponent = 8;
+ break;
+ }
+
+ sal_Int32 nStreamLengthObject = createObject();
+ sal_Int32 nMaskObject = 0;
+
+#if OSL_DEBUG_LEVEL > 1
+ {
+ OStringBuffer aLine( " PDFWriterImpl::writeBitmapObject" );
+ emitComment( aLine.getStr() );
+ }
+#endif
+ OStringBuffer aLine(1024);
+ aLine.append( rObject.m_nObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/XObject/Subtype/Image/Width " );
+ aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
+ aLine.append( " /Height " );
+ aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() );
+ aLine.append( " /BitsPerComponent " );
+ aLine.append( nBitsPerComponent );
+ aLine.append( " /Length " );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 R\n" );
+#ifndef DEBUG_DISABLE_PDFCOMPRESSION
+ aLine.append( "/Filter/FlateDecode" );
+#endif
+ if( ! bMask )
+ {
+ aLine.append( "/ColorSpace" );
+ if( bTrueColor )
+ aLine.append( "/DeviceRGB\n" );
+ else if( aBitmap.HasGreyPalette() )
+ {
+ aLine.append( "/DeviceGray\n" );
+ if( aBitmap.GetBitCount() == 1 )
+ {
+ // #i47395# 1 bit bitmaps occasionally have an inverted grey palette
+ sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
+ DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
+ if( nBlackIndex == 1 )
+ aLine.append( "/Decode[1 0]\n" );
+ }
+ }
+ else
+ {
+ aLine.append( "[ /Indexed/DeviceRGB " );
+ aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) );
+ aLine.append( "\n<" );
+ if( m_aContext.Encrypt )
+ {
+ enableStringEncryption( rObject.m_nObject );
+ //check encryption buffer size
+ if( checkEncryptionBufferSize( pAccess->GetPaletteEntryCount()*3 ) )
+ {
+ int nChar = 0;
+ //fill the encryption buffer
+ for( USHORT i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
+ {
+ const BitmapColor& rColor = pAccess->GetPaletteColor( i );
+ m_pEncryptionBuffer[nChar++] = rColor.GetRed();
+ m_pEncryptionBuffer[nChar++] = rColor.GetGreen();
+ m_pEncryptionBuffer[nChar++] = rColor.GetBlue();
+ }
+ //encrypt the colorspace lookup table
+ rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChar, m_pEncryptionBuffer, nChar );
+ //now queue the data for output
+ nChar = 0;
+ for( USHORT i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
+ {
+ appendHex(m_pEncryptionBuffer[nChar++], aLine );
+ appendHex(m_pEncryptionBuffer[nChar++], aLine );
+ appendHex(m_pEncryptionBuffer[nChar++], aLine );
+ }
+ }
+ }
+ else //no encryption requested (PDF/A-1a program flow drops here)
+ {
+ for( USHORT i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
+ {
+ const BitmapColor& rColor = pAccess->GetPaletteColor( i );
+ appendHex( rColor.GetRed(), aLine );
+ appendHex( rColor.GetGreen(), aLine );
+ appendHex( rColor.GetBlue(), aLine );
+ }
+ }
+ aLine.append( ">\n]\n" );
+ }
+ }
+ else
+ {
+ if( aBitmap.GetBitCount() == 1 )
+ {
+ aLine.append( " /ImageMask true\n" );
+ sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
+ DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
+ if( nBlackIndex )
+ aLine.append( "/Decode[ 1 0 ]\n" );
+ else
+ aLine.append( "/Decode[ 0 1 ]\n" );
+ }
+ else if( aBitmap.GetBitCount() == 8 )
+ {
+ aLine.append( "/ColorSpace/DeviceGray\n"
+ "/Decode [ 1 0 ]\n" );
+ }
+ }
+
+ if( ! bMask && m_aContext.Version > PDFWriter::PDF_1_2 && !m_bIsPDF_A1 )//i59651
+ {
+ if( bWriteMask )
+ {
+ nMaskObject = createObject();
+ if( rObject.m_aBitmap.IsAlpha() && m_aContext.Version > PDFWriter::PDF_1_3 )
+ aLine.append( "/SMask " );
+ else
+ aLine.append( "/Mask " );
+ aLine.append( nMaskObject );
+ aLine.append( " 0 R\n" );
+ }
+ else if( aTransparentColor != Color( COL_TRANSPARENT ) )
+ {
+ aLine.append( "/Mask[ " );
+ if( bTrueColor )
+ {
+ aLine.append( (sal_Int32)aTransparentColor.GetRed() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetRed() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
+ }
+ else
+ {
+ sal_Int32 nIndex = pAccess->GetBestPaletteIndex( BitmapColor( aTransparentColor ) );
+ aLine.append( nIndex );
+ }
+ aLine.append( " ]\n" );
+ }
+ }
+ else if( m_bIsPDF_A1 && (bWriteMask || aTransparentColor != Color( COL_TRANSPARENT )) )
+ m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
+
+ aLine.append( ">>\n"
+ "stream\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ sal_uInt64 nStartPos = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos )) );
+
+ checkAndEnableStreamEncryption( rObject.m_nObject );
+ beginCompression();
+ if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
+ {
+ const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U );
+
+ for( int i = 0; i < pAccess->Height(); i++ )
+ {
+ CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) );
+ }
+ }
+ else
+ {
+ const int nScanLineBytes = pAccess->Width()*3;
+ boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] );
+ for( int y = 0; y < pAccess->Height(); y++ )
+ {
+ for( int x = 0; x < pAccess->Width(); x++ )
+ {
+ BitmapColor aColor = pAccess->GetColor( y, x );
+ pCol[3*x+0] = aColor.GetRed();
+ pCol[3*x+1] = aColor.GetGreen();
+ pCol[3*x+2] = aColor.GetBlue();
+ }
+ CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) );
+ }
+ }
+ endCompression();
+ disableStreamEncryption();
+
+ sal_uInt64 nEndPos = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos )) );
+ aLine.setLength( 0 );
+ aLine.append( "\nendstream\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ CHECK_RETURN( updateObject( nStreamLengthObject ) );
+ aLine.setLength( 0 );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 obj\n" );
+ aLine.append( (sal_Int64)(nEndPos-nStartPos) );
+ aLine.append( "\nendobj\n\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ if( nMaskObject )
+ {
+ BitmapEmit aEmit;
+ aEmit.m_nObject = nMaskObject;
+ aEmit.m_aBitmap = rObject.m_aBitmap;
+ return writeBitmapObject( aEmit, true );
+ }
+
+ return true;
+}
+
+void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask )
+{
+ MARK( "drawJPGBitmap" );
+
+ OStringBuffer aLine( 80 );
+ updateGraphicsState();
+
+ // #i40055# sanity check
+ if( ! (rTargetArea.GetWidth() && rTargetArea.GetHeight() ) )
+ return;
+ if( ! (rSizePixel.Width() && rSizePixel.Height()) )
+ return;
+
+ SvMemoryStream* pStream = new SvMemoryStream;
+ rDCTData.Seek( 0 );
+ *pStream << rDCTData;
+ pStream->Seek( STREAM_SEEK_TO_END );
+
+ BitmapID aID;
+ aID.m_aPixelSize = rSizePixel;
+ aID.m_nSize = pStream->Tell();
+ pStream->Seek( STREAM_SEEK_TO_BEGIN );
+ aID.m_nChecksum = rtl_crc32( 0, pStream->GetData(), aID.m_nSize );
+ if( ! rMask.IsEmpty() )
+ aID.m_nMaskChecksum = rMask.GetChecksum();
+
+ std::list< JPGEmit >::const_iterator it;
+ for( it = m_aJPGs.begin(); it != m_aJPGs.end() && ! (aID == it->m_aID); ++it )
+ ;
+ if( it == m_aJPGs.end() )
+ {
+ m_aJPGs.push_front( JPGEmit() );
+ JPGEmit& rEmit = m_aJPGs.front();
+ rEmit.m_nObject = createObject();
+ rEmit.m_aID = aID;
+ rEmit.m_pStream = pStream;
+ rEmit.m_bTrueColor = bIsTrueColor;
+ if( !! rMask && rMask.GetSizePixel() == rSizePixel )
+ rEmit.m_aMask = rMask;
+
+ it = m_aJPGs.begin();
+ }
+ else
+ delete pStream;
+
+ aLine.append( "q " );
+ sal_Int32 nCheckWidth = 0;
+ m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetWidth(), aLine, false, &nCheckWidth );
+ aLine.append( " 0 0 " );
+ sal_Int32 nCheckHeight = 0;
+ m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetHeight(), aLine, true, &nCheckHeight );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( rTargetArea.BottomLeft(), aLine );
+ aLine.append( " cm\n/Im" );
+ aLine.append( it->m_nObject );
+ aLine.append( " Do Q\n" );
+ if( nCheckWidth == 0 || nCheckHeight == 0 )
+ {
+ // #i97512# avoid invalid current matrix
+ aLine.setLength( 0 );
+ aLine.append( "\n%jpeg image /Im" );
+ aLine.append( it->m_nObject );
+ aLine.append( " scaled to zero size, omitted\n" );
+ }
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( "Im" );
+ aObjName.append( it->m_nObject );
+ pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
+
+}
+
+void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor )
+{
+ OStringBuffer aLine( 80 );
+ updateGraphicsState();
+
+ aLine.append( "q " );
+ if( rFillColor != Color( COL_TRANSPARENT ) )
+ {
+ appendNonStrokingColor( rFillColor, aLine );
+ aLine.append( ' ' );
+ }
+ sal_Int32 nCheckWidth = 0;
+ m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Width(), aLine, false, &nCheckWidth );
+ aLine.append( " 0 0 " );
+ sal_Int32 nCheckHeight = 0;
+ m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Height(), aLine, true, &nCheckHeight );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine );
+ aLine.append( " cm\n/Im" );
+ aLine.append( rBitmap.m_nObject );
+ aLine.append( " Do Q\n" );
+ if( nCheckWidth == 0 || nCheckHeight == 0 )
+ {
+ // #i97512# avoid invalid current matrix
+ aLine.setLength( 0 );
+ aLine.append( "\n%bitmap image /Im" );
+ aLine.append( rBitmap.m_nObject );
+ aLine.append( " scaled to zero size, omitted\n" );
+ }
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& rBitmap, bool bDrawMask )
+{
+ BitmapID aID;
+ aID.m_aPixelSize = rBitmap.GetSizePixel();
+ aID.m_nSize = rBitmap.GetBitCount();
+ aID.m_nChecksum = rBitmap.GetBitmap().GetChecksum();
+ aID.m_nMaskChecksum = 0;
+ if( rBitmap.IsAlpha() )
+ aID.m_nMaskChecksum = rBitmap.GetAlpha().GetChecksum();
+ else
+ {
+ Bitmap aMask = rBitmap.GetMask();
+ if( ! aMask.IsEmpty() )
+ aID.m_nMaskChecksum = aMask.GetChecksum();
+ }
+ std::list< BitmapEmit >::const_iterator it;
+ for( it = m_aBitmaps.begin(); it != m_aBitmaps.end(); ++it )
+ {
+ if( aID == it->m_aID )
+ break;
+ }
+ if( it == m_aBitmaps.end() )
+ {
+ m_aBitmaps.push_front( BitmapEmit() );
+ m_aBitmaps.front().m_aID = aID;
+ m_aBitmaps.front().m_aBitmap = rBitmap;
+ m_aBitmaps.front().m_nObject = createObject();
+ m_aBitmaps.front().m_bDrawMask = bDrawMask;
+ it = m_aBitmaps.begin();
+ }
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( "Im" );
+ aObjName.append( it->m_nObject );
+ pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
+
+ return *it;
+}
+
+void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap )
+{
+ MARK( "drawBitmap (Bitmap)" );
+
+ // #i40055# sanity check
+ if( ! (rDestSize.Width() && rDestSize.Height()) )
+ return;
+
+ const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( rBitmap ) );
+ drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
+}
+
+void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap )
+{
+ MARK( "drawBitmap (BitmapEx)" );
+
+ // #i40055# sanity check
+ if( ! (rDestSize.Width() && rDestSize.Height()) )
+ return;
+
+ const BitmapEmit& rEmit = createBitmapEmit( rBitmap );
+ drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
+}
+
+void PDFWriterImpl::drawMask( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Color& rFillColor )
+{
+ MARK( "drawMask" );
+
+ // #i40055# sanity check
+ if( ! (rDestSize.Width() && rDestSize.Height()) )
+ return;
+
+ Bitmap aBitmap( rBitmap );
+ if( aBitmap.GetBitCount() > 1 )
+ aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+ DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
+
+ const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ), true );
+ drawBitmap( rDestPoint, rDestSize, rEmit, rFillColor );
+}
+
+sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize )
+{
+ Size aPtSize( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
+ MapMode( MAP_POINT ),
+ getReferenceDevice(),
+ rSize ) );
+ // check if we already have this gradient
+ std::list<GradientEmit>::iterator it;
+ for( it = m_aGradients.begin(); it != m_aGradients.end(); ++it )
+ {
+ if( it->m_aGradient == rGradient )
+ {
+ if( it->m_aSize.Width() < aPtSize.Width() )
+ it->m_aSize.Width() = aPtSize.Width();
+ if( it->m_aSize.Height() <= aPtSize.Height() )
+ it->m_aSize.Height() = aPtSize.Height();
+ break;
+ }
+ }
+ if( it == m_aGradients.end() )
+ {
+ m_aGradients.push_front( GradientEmit() );
+ m_aGradients.front().m_aGradient = rGradient;
+ m_aGradients.front().m_nObject = createObject();
+ m_aGradients.front().m_aSize = aPtSize;
+ it = m_aGradients.begin();
+ }
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( 'P' );
+ aObjName.append( it->m_nObject );
+ pushResource( ResShading, aObjName.makeStringAndClear(), it->m_nObject );
+
+ return it->m_nObject;
+}
+
+void PDFWriterImpl::drawGradient( const Rectangle& rRect, const Gradient& rGradient )
+{
+ MARK( "drawGradient (Rectangle)" );
+
+ if( m_aContext.Version == PDFWriter::PDF_1_2 )
+ {
+ drawRectangle( rRect );
+ return;
+ }
+
+ sal_Int32 nGradient = createGradient( rGradient, rRect.GetSize() );
+
+ Point aTranslate( rRect.BottomLeft() );
+ aTranslate += Point( 0, 1 );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine( 80 );
+ aLine.append( "q 1 0 0 1 " );
+ m_aPages.back().appendPoint( aTranslate, aLine );
+ aLine.append( " cm " );
+ // if a stroke is appended reset the clip region before stroke
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "q " );
+ aLine.append( "0 0 " );
+ m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
+ aLine.append( " re W n\n" );
+
+ aLine.append( "/P" );
+ aLine.append( nGradient );
+ aLine.append( " sh " );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ {
+ aLine.append( "Q 0 0 " );
+ m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
+ aLine.append( " re S " );
+ }
+ aLine.append( "Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
+{
+ MARK( "drawGradient (PolyPolygon)" );
+
+ if( m_aContext.Version == PDFWriter::PDF_1_2 )
+ {
+ drawPolyPolygon( rPolyPoly );
+ return;
+ }
+
+ sal_Int32 nGradient = createGradient( rGradient, rPolyPoly.GetBoundRect().GetSize() );
+
+ updateGraphicsState();
+
+ Rectangle aBoundRect = rPolyPoly.GetBoundRect();
+ Point aTranslate = aBoundRect.BottomLeft() + Point( 0, 1 );
+ int nPolygons = rPolyPoly.Count();
+
+ OStringBuffer aLine( 80*nPolygons );
+ aLine.append( "q " );
+ // set PolyPolygon as clip path
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
+ aLine.append( "W* n\n" );
+ aLine.append( "1 0 0 1 " );
+ m_aPages.back().appendPoint( aTranslate, aLine );
+ aLine.append( " cm\n" );
+ aLine.append( "/P" );
+ aLine.append( nGradient );
+ aLine.append( " sh Q\n" );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ {
+ // and draw the surrounding path
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
+ aLine.append( "S\n" );
+ }
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
+{
+ MARK( "drawHatch" );
+
+ updateGraphicsState();
+
+ if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
+ return;
+ if( rPolyPoly.Count() )
+ {
+ PolyPolygon aPolyPoly( rPolyPoly );
+
+ aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME );
+ push( PUSH_LINECOLOR );
+ setLineColor( rHatch.GetColor() );
+ getReferenceDevice()->ImplDrawHatch( aPolyPoly, rHatch, FALSE );
+ pop();
+ }
+}
+
+void PDFWriterImpl::drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall )
+{
+ MARK( "drawWallpaper" );
+
+ bool bDrawColor = false;
+ bool bDrawGradient = false;
+ bool bDrawBitmap = false;
+
+ BitmapEx aBitmap;
+ Point aBmpPos = rRect.TopLeft();
+ Size aBmpSize;
+ if( rWall.IsBitmap() )
+ {
+ aBitmap = rWall.GetBitmap();
+ aBmpSize = lcl_convert( aBitmap.GetPrefMapMode(),
+ getMapMode(),
+ getReferenceDevice(),
+ aBitmap.GetPrefSize() );
+ Rectangle aRect( rRect );
+ if( rWall.IsRect() )
+ {
+ aRect = rWall.GetRect();
+ aBmpPos = aRect.TopLeft();
+ aBmpSize = aRect.GetSize();
+ }
+ if( rWall.GetStyle() != WALLPAPER_SCALE )
+ {
+ if( rWall.GetStyle() != WALLPAPER_TILE )
+ {
+ bDrawBitmap = true;
+ if( rWall.IsGradient() )
+ bDrawGradient = true;
+ else
+ bDrawColor = true;
+ switch( rWall.GetStyle() )
+ {
+ case WALLPAPER_TOPLEFT:
+ break;
+ case WALLPAPER_TOP:
+ aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
+ break;
+ case WALLPAPER_LEFT:
+ aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
+ break;
+ case WALLPAPER_TOPRIGHT:
+ aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
+ break;
+ case WALLPAPER_CENTER:
+ aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
+ aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
+ break;
+ case WALLPAPER_RIGHT:
+ aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
+ aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
+ break;
+ case WALLPAPER_BOTTOMLEFT:
+ aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
+ break;
+ case WALLPAPER_BOTTOM:
+ aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
+ aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
+ break;
+ case WALLPAPER_BOTTOMRIGHT:
+ aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
+ aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
+ break;
+ default: ;
+ }
+ }
+ else
+ {
+ // push the bitmap
+ const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ) );
+
+ // convert to page coordinates; this needs to be done here
+ // since the emit does not know the page anymore
+ Rectangle aConvertRect( aBmpPos, aBmpSize );
+ m_aPages.back().convertRect( aConvertRect );
+
+ OStringBuffer aNameBuf(16);
+ aNameBuf.append( "Im" );
+ aNameBuf.append( rEmit.m_nObject );
+ OString aImageName( aNameBuf.makeStringAndClear() );
+
+ // push the pattern
+ OStringBuffer aTilingStream( 32 );
+ appendFixedInt( aConvertRect.GetWidth(), aTilingStream );
+ aTilingStream.append( " 0 0 " );
+ appendFixedInt( aConvertRect.GetHeight(), aTilingStream );
+ aTilingStream.append( " 0 0 cm\n/" );
+ aTilingStream.append( aImageName );
+ aTilingStream.append( " Do\n" );
+
+ m_aTilings.push_back( TilingEmit() );
+ m_aTilings.back().m_nObject = createObject();
+ m_aTilings.back().m_aRectangle = Rectangle( Point( 0, 0 ), aConvertRect.GetSize() );
+ m_aTilings.back().m_pTilingStream = new SvMemoryStream();
+ m_aTilings.back().m_pTilingStream->Write( aTilingStream.getStr(), aTilingStream.getLength() );
+ // phase the tiling so wallpaper begins on upper left
+ m_aTilings.back().m_aTransform.matrix[2] = double(aConvertRect.Left() % aConvertRect.GetWidth()) / fDivisor;
+ m_aTilings.back().m_aTransform.matrix[5] = double(aConvertRect.Top() % aConvertRect.GetHeight()) / fDivisor;
+ m_aTilings.back().m_aResources.m_aXObjects[aImageName] = rEmit.m_nObject;
+
+ updateGraphicsState();
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( 'P' );
+ aObjName.append( m_aTilings.back().m_nObject );
+ OString aPatternName( aObjName.makeStringAndClear() );
+ pushResource( ResPattern, aPatternName, m_aTilings.back().m_nObject );
+
+ // fill a rRect with the pattern
+ OStringBuffer aLine( 100 );
+ aLine.append( "q /Pattern cs /" );
+ aLine.append( aPatternName );
+ aLine.append( " scn " );
+ m_aPages.back().appendRect( rRect, aLine );
+ aLine.append( " f Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ }
+ }
+ else
+ {
+ aBmpPos = aRect.TopLeft();
+ aBmpSize = aRect.GetSize();
+ bDrawBitmap = true;
+ }
+
+ if( aBitmap.IsTransparent() )
+ {
+ if( rWall.IsGradient() )
+ bDrawGradient = true;
+ else
+ bDrawColor = true;
+ }
+ }
+ else if( rWall.IsGradient() )
+ bDrawGradient = true;
+ else
+ bDrawColor = true;
+
+ if( bDrawGradient )
+ {
+ drawGradient( rRect, rWall.GetGradient() );
+ }
+ if( bDrawColor )
+ {
+ Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor;
+ Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
+ setLineColor( Color( COL_TRANSPARENT ) );
+ setFillColor( rWall.GetColor() );
+ drawRectangle( rRect );
+ setLineColor( aOldLineColor );
+ setFillColor( aOldFillColor );
+ }
+ if( bDrawBitmap )
+ {
+ // set temporary clip region since aBmpPos and aBmpSize
+ // may be outside rRect
+ OStringBuffer aLine( 20 );
+ aLine.append( "q " );
+ m_aPages.back().appendRect( rRect, aLine );
+ aLine.append( " W n\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ drawBitmap( aBmpPos, aBmpSize, aBitmap );
+ writeBuffer( "Q\n", 2 );
+ }
+}
+
+void PDFWriterImpl::beginPattern( const Rectangle& rCellRect )
+{
+ beginRedirect( new SvMemoryStream(), rCellRect );
+}
+
+sal_Int32 PDFWriterImpl::endPattern( const SvtGraphicFill::Transform& rTransform )
+{
+ Rectangle aConvertRect( getRedirectTargetRect() );
+ DBG_ASSERT( aConvertRect.GetWidth() != 0 && aConvertRect.GetHeight() != 0, "empty cell rectangle in pattern" );
+
+ // get scaling between current mapmode and PDF output
+ Size aScaling( lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), Size( 10000, 10000 ) ) );
+ double fSX = (double(aScaling.Width()) / 10000.0);
+ double fSY = (double(aScaling.Height()) / 10000.0);
+
+ // transform translation part of matrix
+ Size aTranslation( (long)rTransform.matrix[2], (long)rTransform.matrix[5] );
+ aTranslation = lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), aTranslation );
+
+ sal_Int32 nTilingId = m_aTilings.size();
+ m_aTilings.push_back( TilingEmit() );
+ TilingEmit& rTile = m_aTilings.back();
+ rTile.m_nObject = createObject();
+ rTile.m_aResources = m_aOutputStreams.front().m_aResourceDict;
+ rTile.m_aTransform.matrix[0] = rTransform.matrix[0] * fSX;
+ rTile.m_aTransform.matrix[1] = rTransform.matrix[1] * fSY;
+ rTile.m_aTransform.matrix[2] = aTranslation.Width();
+ rTile.m_aTransform.matrix[3] = rTransform.matrix[3] * fSX;
+ rTile.m_aTransform.matrix[4] = rTransform.matrix[4] * fSY;
+ rTile.m_aTransform.matrix[5] = -aTranslation.Height();
+ // caution: endRedirect pops the stream, so do this last
+ rTile.m_pTilingStream = dynamic_cast<SvMemoryStream*>(endRedirect());
+ // FIXME: bound rect will not work with rotated matrix
+ rTile.m_aRectangle = Rectangle( Point(0,0), aConvertRect.GetSize() );
+ rTile.m_aCellSize = aConvertRect.GetSize();
+
+ OStringBuffer aObjName( 16 );
+ aObjName.append( 'P' );
+ aObjName.append( rTile.m_nObject );
+ pushResource( ResPattern, aObjName.makeStringAndClear(), rTile.m_nObject );
+ return nTilingId;
+}
+
+void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly, sal_Int32 nPattern, bool bEOFill )
+{
+ if( nPattern < 0 || nPattern >= (sal_Int32)m_aTilings.size() )
+ return;
+
+ m_aPages.back().endStream();
+ sal_Int32 nXObject = createObject();
+ OStringBuffer aNameBuf( 16 );
+ aNameBuf.append( "Pol" );
+ aNameBuf.append( nXObject );
+ OString aObjName( aNameBuf.makeStringAndClear() );
+ Rectangle aObjRect;
+ if( updateObject( nXObject ) )
+ {
+ // get bounding rect of object
+ PolyPolygon aSubDiv;
+ rPolyPoly.AdaptiveSubdivide( aSubDiv );
+ aObjRect = aSubDiv.GetBoundRect();
+ Rectangle aConvObjRect( aObjRect );
+ m_aPages.back().convertRect( aConvObjRect );
+
+ // move polypolygon to bottom left of page
+ PolyPolygon aLocalPath( rPolyPoly );
+ sal_Int32 nPgWd = getReferenceDevice()->ImplGetDPIX() * m_aPages.back().getWidth() / 72;
+ sal_Int32 nPgHt = getReferenceDevice()->ImplGetDPIY() * m_aPages.back().getHeight() / 72;
+ Size aLogicPgSz = getReferenceDevice()->PixelToLogic( Size( nPgWd, nPgHt ), m_aGraphicsStack.front().m_aMapMode );
+ sal_Int32 nXOff = aObjRect.Left();
+ sal_Int32 nYOff = aLogicPgSz.Height() - aObjRect.Bottom();
+ aLocalPath.Move( -nXOff, nYOff );
+
+ // prepare XObject's content stream
+ OStringBuffer aStream( 512 );
+ aStream.append( "/Pattern cs /P" );
+ aStream.append( m_aTilings[ nPattern ].m_nObject );
+ aStream.append( " scn\n" );
+ m_aPages.back().appendPolyPolygon( aLocalPath, aStream );
+ aStream.append( bEOFill ? "f*" : "f" );
+ SvMemoryStream aMemStream( aStream.getLength() );
+ aMemStream.Write( aStream.getStr(), aStream.getLength() );
+ bool bDeflate = compressStream( &aMemStream );
+ aMemStream.Seek( STREAM_SEEK_TO_END );
+ sal_Int32 nStreamLen = (sal_Int32)aMemStream.Tell();
+ aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
+
+ // add new XObject to global resource dict
+ m_aGlobalResourceDict.m_aXObjects[ aObjName ] = nXObject;
+
+ // write XObject
+ OStringBuffer aLine( 512 );
+ aLine.append( nXObject );
+ aLine.append( " 0 obj\n"
+ "<</Type/XObject/Subtype/Form/BBox[0 0 " );
+ appendFixedInt( aConvObjRect.GetWidth(), aLine );
+ aLine.append( ' ' );
+ appendFixedInt( aConvObjRect.GetHeight(), aLine );
+ aLine.append( "]/Length " );
+ aLine.append( nStreamLen );
+ if( bDeflate )
+ aLine.append( "/Filter/FlateDecode" );
+ aLine.append( ">>\n"
+ "stream\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ checkAndEnableStreamEncryption( nXObject );
+ writeBuffer( aMemStream.GetData(), nStreamLen );
+ disableStreamEncryption();
+ writeBuffer( "\nendstream\nendobj\n\n", 19 );
+ }
+ m_aPages.back().beginStream();
+ OStringBuffer aLine( 80 );
+ aLine.append( "q 1 0 0 1 " );
+ m_aPages.back().appendPoint( aObjRect.BottomLeft(), aLine );
+ aLine.append( " cm/" );
+ aLine.append( aObjName );
+ aLine.append( " Do Q\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::updateGraphicsState()
+{
+ OStringBuffer aLine( 256 );
+ GraphicsState& rNewState = m_aGraphicsStack.front();
+ // first set clip region since it might invalidate everything else
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateClipRegion) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateClipRegion;
+
+ if( m_aCurrentPDFState.m_bClipRegion != rNewState.m_bClipRegion ||
+ ( rNewState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion != rNewState.m_aClipRegion ) )
+ {
+ if( m_aCurrentPDFState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion.count() )
+ {
+ aLine.append( "Q " );
+ // invalidate everything but the clip region
+ m_aCurrentPDFState = GraphicsState();
+ rNewState.m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~GraphicsState::updateClipRegion);
+ }
+ if( rNewState.m_bClipRegion && rNewState.m_aClipRegion.count() )
+ {
+ // clip region is always stored in private PDF mapmode
+ MapMode aNewMapMode = rNewState.m_aMapMode;
+ rNewState.m_aMapMode = m_aMapMode;
+ getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
+ m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
+
+ aLine.append( "q " );
+ m_aPages.back().appendPolyPolygon( rNewState.m_aClipRegion, aLine );
+ aLine.append( "W* n\n" );
+ rNewState.m_aMapMode = aNewMapMode;
+ getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
+ m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
+ }
+ }
+ }
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateMapMode) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateMapMode;
+ getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
+ }
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateFont) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateFont;
+ getReferenceDevice()->SetFont( rNewState.m_aFont );
+ getReferenceDevice()->ImplNewFont();
+ }
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateLayoutMode) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateLayoutMode;
+ getReferenceDevice()->SetLayoutMode( rNewState.m_nLayoutMode );
+ }
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateDigitLanguage) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateDigitLanguage;
+ getReferenceDevice()->SetDigitLanguage( rNewState.m_aDigitLanguage );
+ }
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateLineColor) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateLineColor;
+ if( m_aCurrentPDFState.m_aLineColor != rNewState.m_aLineColor &&
+ rNewState.m_aLineColor != Color( COL_TRANSPARENT ) )
+ {
+ appendStrokingColor( rNewState.m_aLineColor, aLine );
+ aLine.append( "\n" );
+ }
+ }
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateFillColor) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateFillColor;
+ if( m_aCurrentPDFState.m_aFillColor != rNewState.m_aFillColor &&
+ rNewState.m_aFillColor != Color( COL_TRANSPARENT ) )
+ {
+ appendNonStrokingColor( rNewState.m_aFillColor, aLine );
+ aLine.append( "\n" );
+ }
+ }
+
+ if( (rNewState.m_nUpdateFlags & GraphicsState::updateTransparentPercent) )
+ {
+ rNewState.m_nUpdateFlags &= ~GraphicsState::updateTransparentPercent;
+ if( m_aContext.Version >= PDFWriter::PDF_1_4 && m_aCurrentPDFState.m_nTransparentPercent != rNewState.m_nTransparentPercent )
+ {
+ // TODO: switch extended graphicsstate
+ }
+ }
+
+ // everything is up to date now
+ m_aCurrentPDFState = m_aGraphicsStack.front();
+ if( aLine.getLength() )
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+/* #i47544# imitate OutputDevice behaviour:
+* if a font with a nontransparent color is set, it overwrites the current
+* text color. OTOH setting the text color will overwrite the color of the font.
+*/
+void PDFWriterImpl::setFont( const Font& rFont )
+{
+ Color aColor = rFont.GetColor();
+ if( aColor == Color( COL_TRANSPARENT ) )
+ aColor = m_aGraphicsStack.front().m_aFont.GetColor();
+ m_aGraphicsStack.front().m_aFont = rFont;
+ m_aGraphicsStack.front().m_aFont.SetColor( aColor );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
+}
+
+void PDFWriterImpl::push( sal_uInt16 nFlags )
+{
+ OSL_ENSURE( m_aGraphicsStack.size() > 0, "invalid graphics stack" );
+ m_aGraphicsStack.push_front( m_aGraphicsStack.front() );
+ m_aGraphicsStack.front().m_nFlags = nFlags;
+}
+
+void PDFWriterImpl::pop()
+{
+ OSL_ENSURE( m_aGraphicsStack.size() > 1, "pop without push" );
+ if( m_aGraphicsStack.size() < 2 )
+ return;
+
+ GraphicsState aState = m_aGraphicsStack.front();
+ m_aGraphicsStack.pop_front();
+ GraphicsState& rOld = m_aGraphicsStack.front();
+
+ // move those parameters back that were not pushed
+ // in the first place
+ if( ! (aState.m_nFlags & PUSH_LINECOLOR) )
+ setLineColor( aState.m_aLineColor );
+ if( ! (aState.m_nFlags & PUSH_FILLCOLOR) )
+ setFillColor( aState.m_aFillColor );
+ if( ! (aState.m_nFlags & PUSH_FONT) )
+ setFont( aState.m_aFont );
+ if( ! (aState.m_nFlags & PUSH_TEXTCOLOR) )
+ setTextColor( aState.m_aFont.GetColor() );
+ if( ! (aState.m_nFlags & PUSH_MAPMODE) )
+ setMapMode( aState.m_aMapMode );
+ if( ! (aState.m_nFlags & PUSH_CLIPREGION) )
+ {
+ // do not use setClipRegion here
+ // it would convert again assuming the current mapmode
+ rOld.m_aClipRegion = aState.m_aClipRegion;
+ rOld.m_bClipRegion = aState.m_bClipRegion;
+ }
+ if( ! (aState.m_nFlags & PUSH_TEXTLINECOLOR ) )
+ setTextLineColor( aState.m_aTextLineColor );
+ if( ! (aState.m_nFlags & PUSH_OVERLINECOLOR ) )
+ setOverlineColor( aState.m_aOverlineColor );
+ if( ! (aState.m_nFlags & PUSH_TEXTALIGN ) )
+ setTextAlign( aState.m_aFont.GetAlign() );
+ if( ! (aState.m_nFlags & PUSH_TEXTFILLCOLOR) )
+ setTextFillColor( aState.m_aFont.GetFillColor() );
+ if( ! (aState.m_nFlags & PUSH_REFPOINT) )
+ {
+ // what ?
+ }
+ // invalidate graphics state
+ m_aGraphicsStack.front().m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~0U);
+}
+
+void PDFWriterImpl::setMapMode( const MapMode& rMapMode )
+{
+ m_aGraphicsStack.front().m_aMapMode = rMapMode;
+ getReferenceDevice()->SetMapMode( rMapMode );
+ m_aCurrentPDFState.m_aMapMode = rMapMode;
+}
+
+void PDFWriterImpl::setClipRegion( const basegfx::B2DPolyPolygon& rRegion )
+{
+ basegfx::B2DPolyPolygon aRegion = getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode );
+ aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
+ m_aGraphicsStack.front().m_aClipRegion = aRegion;
+ m_aGraphicsStack.front().m_bClipRegion = true;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
+}
+
+void PDFWriterImpl::moveClipRegion( sal_Int32 nX, sal_Int32 nY )
+{
+ if( m_aGraphicsStack.front().m_bClipRegion && m_aGraphicsStack.front().m_aClipRegion.count() )
+ {
+ Point aPoint( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
+ m_aMapMode,
+ getReferenceDevice(),
+ Point( nX, nY ) ) );
+ aPoint -= lcl_convert( m_aGraphicsStack.front().m_aMapMode,
+ m_aMapMode,
+ getReferenceDevice(),
+ Point() );
+ basegfx::B2DHomMatrix aMat;
+ aMat.translate( aPoint.X(), aPoint.Y() );
+ m_aGraphicsStack.front().m_aClipRegion.transform( aMat );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
+ }
+}
+
+bool PDFWriterImpl::intersectClipRegion( const Rectangle& rRect )
+{
+ basegfx::B2DPolyPolygon aRect( basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
+ return intersectClipRegion( aRect );
+}
+
+
+bool PDFWriterImpl::intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion )
+{
+ basegfx::B2DPolyPolygon aRegion( getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ) );
+ aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
+ if( m_aGraphicsStack.front().m_bClipRegion )
+ {
+ basegfx::B2DPolyPolygon aOld( basegfx::tools::prepareForPolygonOperation( m_aGraphicsStack.front().m_aClipRegion ) );
+ aRegion = basegfx::tools::prepareForPolygonOperation( aRegion );
+ m_aGraphicsStack.front().m_aClipRegion = basegfx::tools::solvePolygonOperationAnd( aOld, aRegion );
+ }
+ else
+ {
+ m_aGraphicsStack.front().m_aClipRegion = aRegion;
+ m_aGraphicsStack.front().m_bClipRegion = true;
+ }
+ return true;
+}
+
+void PDFWriterImpl::createNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
+{
+ if( nPageNr < 0 )
+ nPageNr = m_nCurrentPage;
+
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
+ return;
+
+ m_aNotes.push_back( PDFNoteEntry() );
+ m_aNotes.back().m_nObject = createObject();
+ m_aNotes.back().m_aContents = rNote;
+ m_aNotes.back().m_aRect = rRect;
+ // convert to default user space now, since the mapmode may change
+ m_aPages[nPageNr].convertRect( m_aNotes.back().m_aRect );
+
+ // insert note to page's annotation list
+ m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aNotes.back().m_nObject );
+}
+
+sal_Int32 PDFWriterImpl::createLink( const Rectangle& rRect, sal_Int32 nPageNr )
+{
+ if( nPageNr < 0 )
+ nPageNr = m_nCurrentPage;
+
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
+ return -1;
+
+ sal_Int32 nRet = m_aLinks.size();
+
+ m_aLinks.push_back( PDFLink() );
+ m_aLinks.back().m_nObject = createObject();
+ m_aLinks.back().m_nPage = nPageNr;
+ m_aLinks.back().m_aRect = rRect;
+ // convert to default user space now, since the mapmode may change
+ m_aPages[nPageNr].convertRect( m_aLinks.back().m_aRect );
+
+ // insert link to page's annotation list
+ m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aLinks.back().m_nObject );
+
+ return nRet;
+}
+
+//--->i56629
+sal_Int32 PDFWriterImpl::createNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
+{
+ if( nPageNr < 0 )
+ nPageNr = m_nCurrentPage;
+
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
+ return -1;
+
+ sal_Int32 nRet = m_aNamedDests.size();
+
+ m_aNamedDests.push_back( PDFNamedDest() );
+ m_aNamedDests.back().m_aDestName = sDestName;
+ m_aNamedDests.back().m_nPage = nPageNr;
+ m_aNamedDests.back().m_eType = eType;
+ m_aNamedDests.back().m_aRect = rRect;
+ // convert to default user space now, since the mapmode may change
+ m_aPages[nPageNr].convertRect( m_aNamedDests.back().m_aRect );
+
+ return nRet;
+}
+//<---i56629
+
+sal_Int32 PDFWriterImpl::createDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
+{
+ if( nPageNr < 0 )
+ nPageNr = m_nCurrentPage;
+
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
+ return -1;
+
+ sal_Int32 nRet = m_aDests.size();
+
+ m_aDests.push_back( PDFDest() );
+ m_aDests.back().m_nPage = nPageNr;
+ m_aDests.back().m_eType = eType;
+ m_aDests.back().m_aRect = rRect;
+ // convert to default user space now, since the mapmode may change
+ m_aPages[nPageNr].convertRect( m_aDests.back().m_aRect );
+
+ return nRet;
+}
+
+sal_Int32 PDFWriterImpl::setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
+{
+ if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
+ return -1;
+ if( nDestId < 0 || nDestId >= (sal_Int32)m_aDests.size() )
+ return -2;
+
+ m_aLinks[ nLinkId ].m_nDest = nDestId;
+
+ return 0;
+}
+
+sal_Int32 PDFWriterImpl::setLinkURL( sal_Int32 nLinkId, const OUString& rURL )
+{
+ if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
+ return -1;
+
+ m_aLinks[ nLinkId ].m_nDest = -1;
+
+ using namespace ::com::sun::star;
+
+ if (!m_xTrans.is())
+ {
+ uno::Reference< lang::XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
+ if( xFact.is() )
+ {
+ m_xTrans = uno::Reference < util::XURLTransformer >(
+ xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ) ) ), uno::UNO_QUERY );
+ }
+ }
+
+ util::URL aURL;
+ aURL.Complete = rURL;
+
+ if (m_xTrans.is())
+ m_xTrans->parseStrict( aURL );
+
+ m_aLinks[ nLinkId ].m_aURL = aURL.Complete;
+
+ return 0;
+}
+
+void PDFWriterImpl::setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId )
+{
+ m_aLinkPropertyMap[ nPropertyId ] = nLinkId;
+}
+
+sal_Int32 PDFWriterImpl::createOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID )
+{
+ // create new item
+ sal_Int32 nNewItem = m_aOutline.size();
+ m_aOutline.push_back( PDFOutlineEntry() );
+
+ // set item attributes
+ setOutlineItemParent( nNewItem, nParent );
+ setOutlineItemText( nNewItem, rText );
+ setOutlineItemDest( nNewItem, nDestID );
+
+ return nNewItem;
+}
+
+sal_Int32 PDFWriterImpl::setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent )
+{
+ if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
+ return -1;
+
+ int nRet = 0;
+
+ if( nNewParent < 0 || nNewParent >= (sal_Int32)m_aOutline.size() || nNewParent == nItem )
+ {
+ nNewParent = 0;
+ nRet = -2;
+ }
+ // remove item from previous parent
+ sal_Int32 nParentID = m_aOutline[ nItem ].m_nParentID;
+ if( nParentID >= 0 && nParentID < (sal_Int32)m_aOutline.size() )
+ {
+ PDFOutlineEntry& rParent = m_aOutline[ nParentID ];
+
+ for( std::vector<sal_Int32>::iterator it = rParent.m_aChildren.begin();
+ it != rParent.m_aChildren.end(); ++it )
+ {
+ if( *it == nItem )
+ {
+ rParent.m_aChildren.erase( it );
+ break;
+ }
+ }
+ }
+
+ // insert item to new parent's list of children
+ m_aOutline[ nNewParent ].m_aChildren.push_back( nItem );
+
+ return nRet;
+}
+
+sal_Int32 PDFWriterImpl::setOutlineItemText( sal_Int32 nItem, const OUString& rText )
+{
+ if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
+ return -1;
+
+ m_aOutline[ nItem ].m_aTitle = rText;
+ return 0;
+}
+
+sal_Int32 PDFWriterImpl::setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID )
+{
+ if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) // item does not exist
+ return -1;
+ if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() ) // dest does not exist
+ return -2;
+ m_aOutline[nItem].m_nDestID = nDestID;
+ return 0;
+}
+
+const sal_Char* PDFWriterImpl::getStructureTag( PDFWriter::StructElement eType )
+{
+ static std::map< PDFWriter::StructElement, const char* > aTagStrings;
+ if( aTagStrings.empty() )
+ {
+ aTagStrings[ PDFWriter::NonStructElement] = "NonStruct";
+ aTagStrings[ PDFWriter::Document ] = "Document";
+ aTagStrings[ PDFWriter::Part ] = "Part";
+ aTagStrings[ PDFWriter::Article ] = "Art";
+ aTagStrings[ PDFWriter::Section ] = "Sect";
+ aTagStrings[ PDFWriter::Division ] = "Div";
+ aTagStrings[ PDFWriter::BlockQuote ] = "BlockQuote";
+ aTagStrings[ PDFWriter::Caption ] = "Caption";
+ aTagStrings[ PDFWriter::TOC ] = "TOC";
+ aTagStrings[ PDFWriter::TOCI ] = "TOCI";
+ aTagStrings[ PDFWriter::Index ] = "Index";
+ aTagStrings[ PDFWriter::Paragraph ] = "P";
+ aTagStrings[ PDFWriter::Heading ] = "H";
+ aTagStrings[ PDFWriter::H1 ] = "H1";
+ aTagStrings[ PDFWriter::H2 ] = "H2";
+ aTagStrings[ PDFWriter::H3 ] = "H3";
+ aTagStrings[ PDFWriter::H4 ] = "H4";
+ aTagStrings[ PDFWriter::H5 ] = "H5";
+ aTagStrings[ PDFWriter::H6 ] = "H6";
+ aTagStrings[ PDFWriter::List ] = "L";
+ aTagStrings[ PDFWriter::ListItem ] = "LI";
+ aTagStrings[ PDFWriter::LILabel ] = "Lbl";
+ aTagStrings[ PDFWriter::LIBody ] = "LBody";
+ aTagStrings[ PDFWriter::Table ] = "Table";
+ aTagStrings[ PDFWriter::TableRow ] = "TR";
+ aTagStrings[ PDFWriter::TableHeader ] = "TH";
+ aTagStrings[ PDFWriter::TableData ] = "TD";
+ aTagStrings[ PDFWriter::Span ] = "Span";
+ aTagStrings[ PDFWriter::Quote ] = "Quote";
+ aTagStrings[ PDFWriter::Note ] = "Note";
+ aTagStrings[ PDFWriter::Reference ] = "Reference";
+ aTagStrings[ PDFWriter::BibEntry ] = "BibEntry";
+ aTagStrings[ PDFWriter::Code ] = "Code";
+ aTagStrings[ PDFWriter::Link ] = "Link";
+ aTagStrings[ PDFWriter::Figure ] = "Figure";
+ aTagStrings[ PDFWriter::Formula ] = "Formula";
+ aTagStrings[ PDFWriter::Form ] = "Form";
+ }
+
+ std::map< PDFWriter::StructElement, const char* >::const_iterator it = aTagStrings.find( eType );
+
+ return it != aTagStrings.end() ? it->second : "Div";
+}
+
+void PDFWriterImpl::beginStructureElementMCSeq()
+{
+ if( m_bEmitStructure &&
+ m_nCurrentStructElement > 0 && // StructTreeRoot
+ ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
+ )
+ {
+ PDFStructureElement& rEle = m_aStructure[ m_nCurrentStructElement ];
+ OStringBuffer aLine( 128 );
+ sal_Int32 nMCID = m_aPages[ m_nCurrentPage ].m_aMCIDParents.size();
+ aLine.append( "/" );
+ if( rEle.m_aAlias.getLength() > 0 )
+ aLine.append( rEle.m_aAlias );
+ else
+ aLine.append( getStructureTag( rEle.m_eType ) );
+ aLine.append( "<</MCID " );
+ aLine.append( nMCID );
+ aLine.append( ">>BDC\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ // update the element's content list
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "beginning marked content id %" SAL_PRIdINT32 " on page object %" SAL_PRIdINT32 ", structure first page = %" SAL_PRIdINT32 "\n",
+ nMCID,
+ m_aPages[ m_nCurrentPage ].m_nPageObject,
+ rEle.m_nFirstPageObject );
+#endif
+ rEle.m_aKids.push_back( PDFStructureElementKid( nMCID, m_aPages[m_nCurrentPage].m_nPageObject ) );
+ // update the page's mcid parent list
+ m_aPages[ m_nCurrentPage ].m_aMCIDParents.push_back( rEle.m_nObject );
+ // mark element MC sequence as open
+ rEle.m_bOpenMCSeq = true;
+ }
+ // handle artifacts
+ else if( ! m_bEmitStructure && m_aContext.Tagged &&
+ m_nCurrentStructElement > 0 &&
+ m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement &&
+ ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
+ )
+ {
+ OStringBuffer aLine( 128 );
+ aLine.append( "/Artifact BMC\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ // mark element MC sequence as open
+ m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = true;
+ }
+}
+
+void PDFWriterImpl::endStructureElementMCSeq()
+{
+ if( m_nCurrentStructElement > 0 && // StructTreeRoot
+ ( m_bEmitStructure || m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement ) &&
+ m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // must have an opened MC sequence
+ )
+ {
+ writeBuffer( "EMC\n", 4 );
+ m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = false;
+ }
+}
+
+bool PDFWriterImpl::checkEmitStructure()
+{
+ bool bEmit = false;
+ if( m_aContext.Tagged )
+ {
+ bEmit = true;
+ sal_Int32 nEle = m_nCurrentStructElement;
+ while( nEle > 0 && nEle < sal_Int32(m_aStructure.size()) )
+ {
+ if( m_aStructure[ nEle ].m_eType == PDFWriter::NonStructElement )
+ {
+ bEmit = false;
+ break;
+ }
+ nEle = m_aStructure[ nEle ].m_nParentElement;
+ }
+ }
+ return bEmit;
+}
+
+sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias )
+{
+ if( m_nCurrentPage < 0 )
+ return -1;
+
+ if( ! m_aContext.Tagged )
+ return -1;
+
+ // close eventual current MC sequence
+ endStructureElementMCSeq();
+
+ if( m_nCurrentStructElement == 0 &&
+ eType != PDFWriter::Document && eType != PDFWriter::NonStructElement )
+ {
+ // struct tree root hit, but not beginning document
+ // this might happen with setCurrentStructureElement
+ // silently insert structure into document again if one properly exists
+ if( ! m_aStructure[ 0 ].m_aChildren.empty() )
+ {
+ PDFWriter::StructElement childType = PDFWriter::NonStructElement;
+ sal_Int32 nNewCurElement = 0;
+ const std::list< sal_Int32 >& rRootChildren = m_aStructure[0].m_aChildren;
+ for( std::list< sal_Int32 >::const_iterator it = rRootChildren.begin();
+ childType != PDFWriter::Document && it != rRootChildren.end(); ++it )
+ {
+ nNewCurElement = *it;
+ childType = m_aStructure[ nNewCurElement ].m_eType;
+ }
+ if( childType == PDFWriter::Document )
+ {
+ m_nCurrentStructElement = nNewCurElement;
+ DBG_ASSERT( 0, "Structure element inserted to StructTreeRoot that is not a document" );
+ }
+ else {
+ DBG_ERROR( "document structure in disorder !" );
+ }
+ }
+ else {
+ DBG_ERROR( "PDF document structure MUST be contained in a Document element" );
+ }
+ }
+
+ sal_Int32 nNewId = sal_Int32(m_aStructure.size());
+ m_aStructure.push_back( PDFStructureElement() );
+ PDFStructureElement& rEle = m_aStructure.back();
+ rEle.m_eType = eType;
+ rEle.m_nOwnElement = nNewId;
+ rEle.m_nParentElement = m_nCurrentStructElement;
+ rEle.m_nFirstPageObject = m_aPages[ m_nCurrentPage ].m_nPageObject;
+ m_aStructure[ m_nCurrentStructElement ].m_aChildren.push_back( nNewId );
+ m_nCurrentStructElement = nNewId;
+
+ // handle alias names
+ if( rAlias.getLength() && eType != PDFWriter::NonStructElement )
+ {
+ OStringBuffer aNameBuf( rAlias.getLength() );
+ appendName( rAlias, aNameBuf );
+ OString aAliasName( aNameBuf.makeStringAndClear() );
+ rEle.m_aAlias = aAliasName;
+ m_aRoleMap[ aAliasName ] = getStructureTag( eType );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OStringBuffer aLine( "beginStructureElement " );
+ aLine.append( m_nCurrentStructElement );
+ aLine.append( ": " );
+ aLine.append( getStructureTag( eType ) );
+ if( rEle.m_aAlias.getLength() )
+ {
+ aLine.append( " aliased as \"" );
+ aLine.append( rEle.m_aAlias );
+ aLine.append( '\"' );
+ }
+ emitComment( aLine.getStr() );
+#endif
+
+ // check whether to emit structure henceforth
+ m_bEmitStructure = checkEmitStructure();
+
+ if( m_bEmitStructure ) // don't create nonexistant objects
+ {
+ rEle.m_nObject = createObject();
+ // update parent's kids list
+ m_aStructure[ rEle.m_nParentElement ].m_aKids.push_back( rEle.m_nObject );
+ }
+ return nNewId;
+}
+
+void PDFWriterImpl::endStructureElement()
+{
+ if( m_nCurrentPage < 0 )
+ return;
+
+ if( ! m_aContext.Tagged )
+ return;
+
+ if( m_nCurrentStructElement == 0 )
+ {
+ // hit the struct tree root, that means there is an endStructureElement
+ // without corresponding beginStructureElement
+ return;
+ }
+
+ // end the marked content sequence
+ endStructureElementMCSeq();
+
+#if OSL_DEBUG_LEVEL > 1
+ OStringBuffer aLine( "endStructureElement " );
+ aLine.append( m_nCurrentStructElement );
+ aLine.append( ": " );
+ aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
+ if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() )
+ {
+ aLine.append( " aliased as \"" );
+ aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
+ aLine.append( '\"' );
+ }
+#endif
+
+ // "end" the structure element, the parent becomes current element
+ m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement ].m_nParentElement;
+
+ // check whether to emit structure henceforth
+ m_bEmitStructure = checkEmitStructure();
+
+#if OSL_DEBUG_LEVEL > 1
+ if( m_bEmitStructure )
+ emitComment( aLine.getStr() );
+#endif
+}
+
+//---> i94258
+/*
+ * This function adds an internal structure list container to overcome the 8191 elements array limitation
+ * in kids element emission.
+ * Recursive function
+ *
+ */
+void PDFWriterImpl::addInternalStructureContainer( PDFStructureElement& rEle )
+{
+ if( rEle.m_eType == PDFWriter::NonStructElement &&
+ rEle.m_nOwnElement != rEle.m_nParentElement )
+ return;
+
+ for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
+ {
+ if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
+ {
+ PDFStructureElement& rChild = m_aStructure[ *it ];
+ if( rChild.m_eType != PDFWriter::NonStructElement )
+ {
+ //triggered when a child of the rEle element is found
+ if( rChild.m_nParentElement == rEle.m_nOwnElement )
+ addInternalStructureContainer( rChild );//examine the child
+ else
+ {
+ DBG_ERROR( "PDFWriterImpl::addInternalStructureContainer: invalid child structure element" );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
+#endif
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure id" );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
+#endif
+ }
+ }
+
+ if( rEle.m_nOwnElement != rEle.m_nParentElement )
+ {
+ if( !rEle.m_aKids.empty() )
+ {
+ if( rEle.m_aKids.size() > ncMaxPDFArraySize ) {
+ //then we need to add the containers for the kids elements
+ // a list to be used for the new kid element
+ std::list< PDFStructureElementKid > aNewKids;
+ std::list< sal_Int32 > aNewChildren;
+
+ // add Div in RoleMap, in case no one else did (TODO: is it needed? Is it dangerous?)
+ OStringBuffer aNameBuf( "Div" );
+ OString aAliasName( aNameBuf.makeStringAndClear() );
+ m_aRoleMap[ aAliasName ] = getStructureTag( PDFWriter::Division );
+
+ while( rEle.m_aKids.size() > ncMaxPDFArraySize )
+ {
+ sal_Int32 nCurrentStructElement = rEle.m_nOwnElement;
+ sal_Int32 nNewId = sal_Int32(m_aStructure.size());
+ m_aStructure.push_back( PDFStructureElement() );
+ PDFStructureElement& rEleNew = m_aStructure.back();
+ rEleNew.m_aAlias = aAliasName;
+ rEleNew.m_eType = PDFWriter::Division; // a new Div type container
+ rEleNew.m_nOwnElement = nNewId;
+ rEleNew.m_nParentElement = nCurrentStructElement;
+ //inherit the same page as the first child to be reparented
+ rEleNew.m_nFirstPageObject = m_aStructure[ rEle.m_aChildren.front() ].m_nFirstPageObject;
+ rEleNew.m_nObject = createObject();//assign a PDF object number
+ //add the object to the kid list of the parent
+ aNewKids.push_back( PDFStructureElementKid( rEleNew.m_nObject ) );
+ aNewChildren.push_back( nNewId );
+
+ std::list< sal_Int32 >::iterator aChildEndIt( rEle.m_aChildren.begin() );
+ std::list< PDFStructureElementKid >::iterator aKidEndIt( rEle.m_aKids.begin() );
+ advance( aChildEndIt, ncMaxPDFArraySize );
+ advance( aKidEndIt, ncMaxPDFArraySize );
+
+ rEleNew.m_aKids.splice( rEleNew.m_aKids.begin(),
+ rEle.m_aKids,
+ rEle.m_aKids.begin(),
+ aKidEndIt );
+ rEleNew.m_aChildren.splice( rEleNew.m_aChildren.begin(),
+ rEle.m_aChildren,
+ rEle.m_aChildren.begin(),
+ aChildEndIt );
+ // set the kid's new parent
+ for( std::list< sal_Int32 >::const_iterator it = rEleNew.m_aChildren.begin();
+ it != rEleNew.m_aChildren.end(); ++it )
+ {
+ m_aStructure[ *it ].m_nParentElement = nNewId;
+ }
+ }
+ //finally add the new kids resulting from the container added
+ rEle.m_aKids.insert( rEle.m_aKids.begin(), aNewKids.begin(), aNewKids.end() );
+ rEle.m_aChildren.insert( rEle.m_aChildren.begin(), aNewChildren.begin(), aNewChildren.end() );
+ }
+ }
+ }
+}
+//<--- i94258
+
+bool PDFWriterImpl::setCurrentStructureElement( sal_Int32 nEle )
+{
+ bool bSuccess = false;
+
+ if( m_aContext.Tagged && nEle >= 0 && nEle < sal_Int32(m_aStructure.size()) )
+ {
+ // end eventual previous marked content sequence
+ endStructureElementMCSeq();
+
+ m_nCurrentStructElement = nEle;
+ m_bEmitStructure = checkEmitStructure();
+#if OSL_DEBUG_LEVEL > 1
+ OStringBuffer aLine( "setCurrentStructureElement " );
+ aLine.append( m_nCurrentStructElement );
+ aLine.append( ": " );
+ aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
+ if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() )
+ {
+ aLine.append( " aliased as \"" );
+ aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
+ aLine.append( '\"' );
+ }
+ if( ! m_bEmitStructure )
+ aLine.append( " (inside NonStruct)" );
+ emitComment( aLine.getStr() );
+#endif
+ bSuccess = true;
+ }
+
+ return bSuccess;
+}
+
+sal_Int32 PDFWriterImpl::getCurrentStructureElement()
+{
+ return m_nCurrentStructElement;
+}
+
+bool PDFWriterImpl::setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal )
+{
+ if( !m_aContext.Tagged )
+ return false;
+
+ bool bInsert = false;
+ if( m_nCurrentStructElement > 0 && m_bEmitStructure )
+ {
+ PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
+ switch( eAttr )
+ {
+ case PDFWriter::Placement:
+ if( eVal == PDFWriter::Block ||
+ eVal == PDFWriter::Inline ||
+ eVal == PDFWriter::Before ||
+ eVal == PDFWriter::Start ||
+ eVal == PDFWriter::End )
+ bInsert = true;
+ break;
+ case PDFWriter::WritingMode:
+ if( eVal == PDFWriter::LrTb ||
+ eVal == PDFWriter::RlTb ||
+ eVal == PDFWriter::TbRl )
+ {
+ bInsert = true;
+ }
+ break;
+ case PDFWriter::TextAlign:
+ if( eVal == PDFWriter::Start ||
+ eVal == PDFWriter::Center ||
+ eVal == PDFWriter::End ||
+ eVal == PDFWriter::Justify )
+ {
+ if( eType == PDFWriter::Paragraph ||
+ eType == PDFWriter::Heading ||
+ eType == PDFWriter::H1 ||
+ eType == PDFWriter::H2 ||
+ eType == PDFWriter::H3 ||
+ eType == PDFWriter::H4 ||
+ eType == PDFWriter::H5 ||
+ eType == PDFWriter::H6 ||
+ eType == PDFWriter::List ||
+ eType == PDFWriter::ListItem ||
+ eType == PDFWriter::LILabel ||
+ eType == PDFWriter::LIBody ||
+ eType == PDFWriter::Table ||
+ eType == PDFWriter::TableRow ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ }
+ break;
+ case PDFWriter::Width:
+ case PDFWriter::Height:
+ if( eVal == PDFWriter::Auto )
+ {
+ if( eType == PDFWriter::Figure ||
+ eType == PDFWriter::Formula ||
+ eType == PDFWriter::Form ||
+ eType == PDFWriter::Table ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ }
+ break;
+ case PDFWriter::BlockAlign:
+ if( eVal == PDFWriter::Before ||
+ eVal == PDFWriter::Middle ||
+ eVal == PDFWriter::After ||
+ eVal == PDFWriter::Justify )
+ {
+ if( eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ }
+ break;
+ case PDFWriter::InlineAlign:
+ if( eVal == PDFWriter::Start ||
+ eVal == PDFWriter::Center ||
+ eVal == PDFWriter::End )
+ {
+ if( eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ }
+ break;
+ case PDFWriter::LineHeight:
+ if( eVal == PDFWriter::Normal ||
+ eVal == PDFWriter::Auto )
+ {
+ // only for ILSE and BLSE
+ if( eType == PDFWriter::Paragraph ||
+ eType == PDFWriter::Heading ||
+ eType == PDFWriter::H1 ||
+ eType == PDFWriter::H2 ||
+ eType == PDFWriter::H3 ||
+ eType == PDFWriter::H4 ||
+ eType == PDFWriter::H5 ||
+ eType == PDFWriter::H6 ||
+ eType == PDFWriter::List ||
+ eType == PDFWriter::ListItem ||
+ eType == PDFWriter::LILabel ||
+ eType == PDFWriter::LIBody ||
+ eType == PDFWriter::Table ||
+ eType == PDFWriter::TableRow ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData ||
+ eType == PDFWriter::Span ||
+ eType == PDFWriter::Quote ||
+ eType == PDFWriter::Note ||
+ eType == PDFWriter::Reference ||
+ eType == PDFWriter::BibEntry ||
+ eType == PDFWriter::Code ||
+ eType == PDFWriter::Link )
+ {
+ bInsert = true;
+ }
+ }
+ break;
+ case PDFWriter::TextDecorationType:
+ if( eVal == PDFWriter::NONE ||
+ eVal == PDFWriter::Underline ||
+ eVal == PDFWriter::Overline ||
+ eVal == PDFWriter::LineThrough )
+ {
+ // only for ILSE and BLSE
+ if( eType == PDFWriter::Paragraph ||
+ eType == PDFWriter::Heading ||
+ eType == PDFWriter::H1 ||
+ eType == PDFWriter::H2 ||
+ eType == PDFWriter::H3 ||
+ eType == PDFWriter::H4 ||
+ eType == PDFWriter::H5 ||
+ eType == PDFWriter::H6 ||
+ eType == PDFWriter::List ||
+ eType == PDFWriter::ListItem ||
+ eType == PDFWriter::LILabel ||
+ eType == PDFWriter::LIBody ||
+ eType == PDFWriter::Table ||
+ eType == PDFWriter::TableRow ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData ||
+ eType == PDFWriter::Span ||
+ eType == PDFWriter::Quote ||
+ eType == PDFWriter::Note ||
+ eType == PDFWriter::Reference ||
+ eType == PDFWriter::BibEntry ||
+ eType == PDFWriter::Code ||
+ eType == PDFWriter::Link )
+ {
+ bInsert = true;
+ }
+ }
+ break;
+ case PDFWriter::ListNumbering:
+ if( eVal == PDFWriter::NONE ||
+ eVal == PDFWriter::Disc ||
+ eVal == PDFWriter::Circle ||
+ eVal == PDFWriter::Square ||
+ eVal == PDFWriter::Decimal ||
+ eVal == PDFWriter::UpperRoman ||
+ eVal == PDFWriter::LowerRoman ||
+ eVal == PDFWriter::UpperAlpha ||
+ eVal == PDFWriter::LowerAlpha )
+ {
+ if( eType == PDFWriter::List )
+ bInsert = true;
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if( bInsert )
+ m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( eVal );
+#if OSL_DEBUG_LEVEL > 1
+ else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
+ fprintf( stderr, "rejecting setStructureAttribute( %s, %s ) on %s (%s) element\n",
+ getAttributeTag( eAttr ),
+ getAttributeValueTag( eVal ),
+ getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
+ m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr()
+ );
+#endif
+
+ return bInsert;
+}
+
+bool PDFWriterImpl::setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue )
+{
+ if( ! m_aContext.Tagged )
+ return false;
+
+ bool bInsert = false;
+ if( m_nCurrentStructElement > 0 && m_bEmitStructure )
+ {
+ if( eAttr == PDFWriter::Language )
+ {
+ m_aStructure[ m_nCurrentStructElement ].m_aLocale = MsLangId::convertLanguageToLocale( (LanguageType)nValue );
+ return true;
+ }
+
+ PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
+ switch( eAttr )
+ {
+ case PDFWriter::SpaceBefore:
+ case PDFWriter::SpaceAfter:
+ case PDFWriter::StartIndent:
+ case PDFWriter::EndIndent:
+ // just for BLSE
+ if( eType == PDFWriter::Paragraph ||
+ eType == PDFWriter::Heading ||
+ eType == PDFWriter::H1 ||
+ eType == PDFWriter::H2 ||
+ eType == PDFWriter::H3 ||
+ eType == PDFWriter::H4 ||
+ eType == PDFWriter::H5 ||
+ eType == PDFWriter::H6 ||
+ eType == PDFWriter::List ||
+ eType == PDFWriter::ListItem ||
+ eType == PDFWriter::LILabel ||
+ eType == PDFWriter::LIBody ||
+ eType == PDFWriter::Table ||
+ eType == PDFWriter::TableRow ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ break;
+ case PDFWriter::TextIndent:
+ // paragraph like BLSE and additional elements
+ if( eType == PDFWriter::Paragraph ||
+ eType == PDFWriter::Heading ||
+ eType == PDFWriter::H1 ||
+ eType == PDFWriter::H2 ||
+ eType == PDFWriter::H3 ||
+ eType == PDFWriter::H4 ||
+ eType == PDFWriter::H5 ||
+ eType == PDFWriter::H6 ||
+ eType == PDFWriter::LILabel ||
+ eType == PDFWriter::LIBody ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ break;
+ case PDFWriter::Width:
+ case PDFWriter::Height:
+ if( eType == PDFWriter::Figure ||
+ eType == PDFWriter::Formula ||
+ eType == PDFWriter::Form ||
+ eType == PDFWriter::Table ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ break;
+ case PDFWriter::LineHeight:
+ case PDFWriter::BaselineShift:
+ // only for ILSE and BLSE
+ if( eType == PDFWriter::Paragraph ||
+ eType == PDFWriter::Heading ||
+ eType == PDFWriter::H1 ||
+ eType == PDFWriter::H2 ||
+ eType == PDFWriter::H3 ||
+ eType == PDFWriter::H4 ||
+ eType == PDFWriter::H5 ||
+ eType == PDFWriter::H6 ||
+ eType == PDFWriter::List ||
+ eType == PDFWriter::ListItem ||
+ eType == PDFWriter::LILabel ||
+ eType == PDFWriter::LIBody ||
+ eType == PDFWriter::Table ||
+ eType == PDFWriter::TableRow ||
+ eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData ||
+ eType == PDFWriter::Span ||
+ eType == PDFWriter::Quote ||
+ eType == PDFWriter::Note ||
+ eType == PDFWriter::Reference ||
+ eType == PDFWriter::BibEntry ||
+ eType == PDFWriter::Code ||
+ eType == PDFWriter::Link )
+ {
+ bInsert = true;
+ }
+ break;
+ case PDFWriter::RowSpan:
+ case PDFWriter::ColSpan:
+ // only for table cells
+ if( eType == PDFWriter::TableHeader ||
+ eType == PDFWriter::TableData )
+ {
+ bInsert = true;
+ }
+ break;
+ case PDFWriter::LinkAnnotation:
+ if( eType == PDFWriter::Link )
+ bInsert = true;
+ break;
+ default: break;
+ }
+ }
+
+ if( bInsert )
+ m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( nValue );
+#if OSL_DEBUG_LEVEL > 1
+ else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
+ fprintf( stderr, "rejecting setStructureAttributeNumerical( %s, %d ) on %s (%s) element\n",
+ getAttributeTag( eAttr ),
+ (int)nValue,
+ getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
+ m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr() );
+#endif
+
+ return bInsert;
+}
+
+void PDFWriterImpl::setStructureBoundingBox( const Rectangle& rRect )
+{
+ sal_Int32 nPageNr = m_nCurrentPage;
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() || !m_aContext.Tagged )
+ return;
+
+
+ if( m_nCurrentStructElement > 0 && m_bEmitStructure )
+ {
+ PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
+ if( eType == PDFWriter::Figure ||
+ eType == PDFWriter::Formula ||
+ eType == PDFWriter::Form ||
+ eType == PDFWriter::Table )
+ {
+ m_aStructure[ m_nCurrentStructElement ].m_aBBox = rRect;
+ // convert to default user space now, since the mapmode may change
+ m_aPages[nPageNr].convertRect( m_aStructure[ m_nCurrentStructElement ].m_aBBox );
+ }
+ }
+}
+
+void PDFWriterImpl::setActualText( const String& rText )
+{
+ if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
+ {
+ m_aStructure[ m_nCurrentStructElement ].m_aActualText = rText;
+ }
+}
+
+void PDFWriterImpl::setAlternateText( const String& rText )
+{
+ if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
+ {
+ m_aStructure[ m_nCurrentStructElement ].m_aAltText = rText;
+ }
+}
+
+void PDFWriterImpl::setAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr )
+{
+ if( nPageNr < 0 )
+ nPageNr = m_nCurrentPage;
+
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
+ return;
+
+ m_aPages[ nPageNr ].m_nDuration = nSeconds;
+}
+
+void PDFWriterImpl::setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr )
+{
+ if( nPageNr < 0 )
+ nPageNr = m_nCurrentPage;
+
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
+ return;
+
+ m_aPages[ nPageNr ].m_eTransition = eType;
+ m_aPages[ nPageNr ].m_nTransTime = nMilliSec;
+}
+
+void PDFWriterImpl::ensureUniqueRadioOnValues()
+{
+ // loop over radio groups
+ for( std::map<sal_Int32,sal_Int32>::const_iterator group = m_aRadioGroupWidgets.begin();
+ group != m_aRadioGroupWidgets.end(); ++group )
+ {
+ PDFWidget& rGroupWidget = m_aWidgets[ group->second ];
+ // check whether all kids have a unique OnValue
+ std::hash_map< OUString, sal_Int32, OUStringHash > aOnValues;
+ int nChildren = rGroupWidget.m_aKidsIndex.size();
+ bool bIsUnique = true;
+ for( int nKid = 0; nKid < nChildren && bIsUnique; nKid++ )
+ {
+ int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
+ const OUString& rVal = m_aWidgets[nKidIndex].m_aOnValue;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "OnValue: %s\n", OUStringToOString( rVal, RTL_TEXTENCODING_UTF8 ).getStr() );
+ #endif
+ if( aOnValues.find( rVal ) == aOnValues.end() )
+ {
+ aOnValues[ rVal ] = 1;
+ }
+ else
+ {
+ bIsUnique = false;
+ }
+ }
+ if( ! bIsUnique )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "enforcing unique OnValues\n" );
+ #endif
+ // make unique by using ascending OnValues
+ for( int nKid = 0; nKid < nChildren; nKid++ )
+ {
+ int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
+ PDFWidget& rKid = m_aWidgets[nKidIndex];
+ rKid.m_aOnValue = OUString::valueOf( sal_Int32(nKid+1) );
+ if( ! rKid.m_aValue.equalsAscii( "Off" ) )
+ rKid.m_aValue = rKid.m_aOnValue;
+ }
+ }
+ // finally move the "Yes" appearance to the OnValue appearance
+ for( int nKid = 0; nKid < nChildren; nKid++ )
+ {
+ int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
+ PDFWidget& rKid = m_aWidgets[nKidIndex];
+ PDFAppearanceMap::iterator app_it = rKid.m_aAppearances.find( "N" );
+ if( app_it != rKid.m_aAppearances.end() )
+ {
+ PDFAppearanceStreams::iterator stream_it = app_it->second.find( "Yes" );
+ if( stream_it != app_it->second.end() )
+ {
+ SvMemoryStream* pStream = stream_it->second;
+ app_it->second.erase( stream_it );
+ OStringBuffer aBuf( rKid.m_aOnValue.getLength()*2 );
+ appendName( rKid.m_aOnValue, aBuf );
+ (app_it->second)[ aBuf.makeStringAndClear() ] = pStream;
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "error: RadioButton without \"Yes\" stream\n" );
+ #endif
+ }
+ // update selected radio button
+ if( ! rKid.m_aValue.equalsAscii( "Off" ) )
+ {
+ rGroupWidget.m_aValue = rKid.m_aValue;
+ }
+ }
+ }
+}
+
+sal_Int32 PDFWriterImpl::findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rBtn )
+{
+ sal_Int32 nRadioGroupWidget = -1;
+
+ std::map< sal_Int32, sal_Int32 >::const_iterator it = m_aRadioGroupWidgets.find( rBtn.RadioGroup );
+
+ if( it == m_aRadioGroupWidgets.end() )
+ {
+ m_aRadioGroupWidgets[ rBtn.RadioGroup ] = nRadioGroupWidget =
+ sal_Int32(m_aWidgets.size());
+
+ // new group, insert the radiobutton
+ m_aWidgets.push_back( PDFWidget() );
+ m_aWidgets.back().m_nObject = createObject();
+ m_aWidgets.back().m_nPage = m_nCurrentPage;
+ m_aWidgets.back().m_eType = PDFWriter::RadioButton;
+ m_aWidgets.back().m_nRadioGroup = rBtn.RadioGroup;
+ m_aWidgets.back().m_nFlags |= 0x0000C000; // NoToggleToOff and Radio bits
+
+ createWidgetFieldName( sal_Int32(m_aWidgets.size()-1), rBtn );
+ }
+ else
+ nRadioGroupWidget = it->second;
+
+ return nRadioGroupWidget;
+}
+
+sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr )
+{
+ if( nPageNr < 0 )
+ nPageNr = m_nCurrentPage;
+
+ if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
+ return -1;
+
+ sal_Int32 nNewWidget = m_aWidgets.size();
+ m_aWidgets.push_back( PDFWidget() );
+
+ m_aWidgets.back().m_nObject = createObject();
+ m_aWidgets.back().m_aRect = rControl.Location;
+ m_aWidgets.back().m_nPage = nPageNr;
+ m_aWidgets.back().m_eType = rControl.getType();
+
+ sal_Int32 nRadioGroupWidget = -1;
+ // for unknown reasons the radio buttons of a radio group must not have a
+ // field name, else the buttons are in fact check boxes -
+ // that is multiple buttons of the radio group can be selected
+ if( rControl.getType() == PDFWriter::RadioButton )
+ nRadioGroupWidget = findRadioGroupWidget( static_cast<const PDFWriter::RadioButtonWidget&>(rControl) );
+ else
+ {
+ createWidgetFieldName( nNewWidget, rControl );
+ }
+
+ // caution: m_aWidgets must not be changed after here or rNewWidget may be invalid
+ PDFWidget& rNewWidget = m_aWidgets[nNewWidget];
+ rNewWidget.m_aDescription = rControl.Description;
+ rNewWidget.m_aText = rControl.Text;
+ rNewWidget.m_nTextStyle = rControl.TextStyle &
+ ( TEXT_DRAW_LEFT | TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT | TEXT_DRAW_TOP |
+ TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM |
+ TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
+ rNewWidget.m_nTabOrder = rControl.TabOrder;
+
+ // various properties are set via the flags (/Ff) property of the field dict
+ if( rControl.ReadOnly )
+ rNewWidget.m_nFlags |= 1;
+ if( rControl.getType() == PDFWriter::PushButton )
+ {
+ const PDFWriter::PushButtonWidget& rBtn = static_cast<const PDFWriter::PushButtonWidget&>(rControl);
+ if( rNewWidget.m_nTextStyle == 0 )
+ rNewWidget.m_nTextStyle =
+ TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER |
+ TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
+
+ rNewWidget.m_nFlags |= 0x00010000;
+ if( rBtn.URL.getLength() )
+ rNewWidget.m_aListEntries.push_back( rBtn.URL );
+ rNewWidget.m_bSubmit = rBtn.Submit;
+ rNewWidget.m_bSubmitGet = rBtn.SubmitGet;
+ rNewWidget.m_nDest = rBtn.Dest;
+ createDefaultPushButtonAppearance( rNewWidget, rBtn );
+ }
+ else if( rControl.getType() == PDFWriter::RadioButton )
+ {
+ const PDFWriter::RadioButtonWidget& rBtn = static_cast<const PDFWriter::RadioButtonWidget&>(rControl);
+ if( rNewWidget.m_nTextStyle == 0 )
+ rNewWidget.m_nTextStyle =
+ TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
+ /* PDF sees a RadioButton group as one radio button with
+ * children which are in turn check boxes
+ *
+ * so we need to create a radio button on demand for a new group
+ * and insert a checkbox for each RadioButtonWidget as its child
+ */
+ rNewWidget.m_eType = PDFWriter::CheckBox;
+ rNewWidget.m_nRadioGroup = rBtn.RadioGroup;
+
+ DBG_ASSERT( nRadioGroupWidget >= 0 && nRadioGroupWidget < (sal_Int32)m_aWidgets.size(), "no radio group parent" );
+
+ PDFWidget& rRadioButton = m_aWidgets[nRadioGroupWidget];
+ rRadioButton.m_aKids.push_back( rNewWidget.m_nObject );
+ rRadioButton.m_aKidsIndex.push_back( nNewWidget );
+ rNewWidget.m_nParent = rRadioButton.m_nObject;
+
+ rNewWidget.m_aValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "Off" ) );
+ rNewWidget.m_aOnValue = rBtn.OnValue;
+ if( ! rRadioButton.m_aValue.getLength() && rBtn.Selected )
+ {
+ rNewWidget.m_aValue = rNewWidget.m_aOnValue;
+ rRadioButton.m_aValue = rNewWidget.m_aOnValue;
+ }
+ createDefaultRadioButtonAppearance( rNewWidget, rBtn );
+
+ // union rect of radio group
+ Rectangle aRect = rNewWidget.m_aRect;
+ m_aPages[ nPageNr ].convertRect( aRect );
+ rRadioButton.m_aRect.Union( aRect );
+ }
+ else if( rControl.getType() == PDFWriter::CheckBox )
+ {
+ const PDFWriter::CheckBoxWidget& rBox = static_cast<const PDFWriter::CheckBoxWidget&>(rControl);
+ if( rNewWidget.m_nTextStyle == 0 )
+ rNewWidget.m_nTextStyle =
+ TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
+
+ rNewWidget.m_aValue = OUString::createFromAscii( rBox.Checked ? "Yes" : "Off" );
+ // create default appearance before m_aRect gets transformed
+ createDefaultCheckBoxAppearance( rNewWidget, rBox );
+ }
+ else if( rControl.getType() == PDFWriter::ListBox )
+ {
+ if( rNewWidget.m_nTextStyle == 0 )
+ rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
+
+ const PDFWriter::ListBoxWidget& rLstBox = static_cast<const PDFWriter::ListBoxWidget&>(rControl);
+ rNewWidget.m_aListEntries = rLstBox.Entries;
+ rNewWidget.m_aSelectedEntries = rLstBox.SelectedEntries;
+ rNewWidget.m_aValue = rLstBox.Text;
+ if( rLstBox.DropDown )
+ rNewWidget.m_nFlags |= 0x00020000;
+ if( rLstBox.Sort )
+ rNewWidget.m_nFlags |= 0x00080000;
+ if( rLstBox.MultiSelect && !rLstBox.DropDown && (int)m_aContext.Version > (int)PDFWriter::PDF_1_3 )
+ rNewWidget.m_nFlags |= 0x00200000;
+
+ createDefaultListBoxAppearance( rNewWidget, rLstBox );
+ }
+ else if( rControl.getType() == PDFWriter::ComboBox )
+ {
+ if( rNewWidget.m_nTextStyle == 0 )
+ rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
+
+ const PDFWriter::ComboBoxWidget& rBox = static_cast<const PDFWriter::ComboBoxWidget&>(rControl);
+ rNewWidget.m_aValue = rBox.Text;
+ rNewWidget.m_aListEntries = rBox.Entries;
+ rNewWidget.m_nFlags |= 0x00060000; // combo and edit flag
+ if( rBox.Sort )
+ rNewWidget.m_nFlags |= 0x00080000;
+
+ PDFWriter::ListBoxWidget aLBox;
+ aLBox.Name = rBox.Name;
+ aLBox.Description = rBox.Description;
+ aLBox.Text = rBox.Text;
+ aLBox.TextStyle = rBox.TextStyle;
+ aLBox.ReadOnly = rBox.ReadOnly;
+ aLBox.Border = rBox.Border;
+ aLBox.BorderColor = rBox.BorderColor;
+ aLBox.Background = rBox.Background;
+ aLBox.BackgroundColor = rBox.BackgroundColor;
+ aLBox.TextFont = rBox.TextFont;
+ aLBox.TextColor = rBox.TextColor;
+ aLBox.DropDown = true;
+ aLBox.Sort = rBox.Sort;
+ aLBox.MultiSelect = false;
+ aLBox.Entries = rBox.Entries;
+
+ createDefaultListBoxAppearance( rNewWidget, aLBox );
+ }
+ else if( rControl.getType() == PDFWriter::Edit )
+ {
+ if( rNewWidget.m_nTextStyle == 0 )
+ rNewWidget.m_nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER;
+
+ const PDFWriter::EditWidget& rEdit = static_cast<const PDFWriter::EditWidget&>(rControl);
+ if( rEdit.MultiLine )
+ {
+ rNewWidget.m_nFlags |= 0x00001000;
+ rNewWidget.m_nTextStyle |= TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
+ }
+ if( rEdit.Password )
+ rNewWidget.m_nFlags |= 0x00002000;
+ if( rEdit.FileSelect && m_aContext.Version > PDFWriter::PDF_1_3 )
+ rNewWidget.m_nFlags |= 0x00100000;
+ rNewWidget.m_nMaxLen = rEdit.MaxLen;
+ rNewWidget.m_aValue = rEdit.Text;
+
+ createDefaultEditAppearance( rNewWidget, rEdit );
+ }
+
+ // convert to default user space now, since the mapmode may change
+ // note: create default appearances before m_aRect gets transformed
+ m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect );
+
+ // insert widget to page's annotation list
+ m_aPages[ nPageNr ].m_aAnnotations.push_back( rNewWidget.m_nObject );
+
+ // mark page as having widgets
+ m_aPages[ nPageNr ].m_bHasWidgets = true;
+
+ return nNewWidget;
+}
+
+void PDFWriterImpl::beginControlAppearance( sal_Int32 nControl )
+{
+ if( nControl < 0 || nControl >= (sal_Int32)m_aWidgets.size() )
+ return;
+
+ PDFWidget& rWidget = m_aWidgets[ nControl ];
+ m_nCurrentControl = nControl;
+
+ SvMemoryStream* pControlStream = new SvMemoryStream( 1024, 1024 );
+ // back conversion of control rect to current MapMode; necessary because
+ // MapMode between createControl and beginControlAppearance
+ // could have changed; therefore the widget rectangle is
+ // already converted
+ Rectangle aBack( Point( rWidget.m_aRect.Left(), pointToPixel(m_aPages[m_nCurrentPage].getHeight()) - rWidget.m_aRect.Top() - rWidget.m_aRect.GetHeight() ),
+ rWidget.m_aRect.GetSize() );
+ aBack = lcl_convert( m_aMapMode,
+ m_aGraphicsStack.front().m_aMapMode,
+ getReferenceDevice(),
+ aBack );
+ beginRedirect( pControlStream, aBack );
+ writeBuffer( "/Tx BMC\n", 8 );
+}
+
+bool PDFWriterImpl::endControlAppearance( PDFWriter::WidgetState eState )
+{
+ bool bRet = false;
+ if( ! m_aOutputStreams.empty() )
+ writeBuffer( "\nEMC\n", 5 );
+ SvMemoryStream* pAppearance = static_cast<SvMemoryStream*>(endRedirect());
+ if( pAppearance && m_nCurrentControl >= 0 && m_nCurrentControl < (sal_Int32)m_aWidgets.size() )
+ {
+ PDFWidget& rWidget = m_aWidgets[ m_nCurrentControl ];
+ OString aState, aStyle;
+ switch( rWidget.m_eType )
+ {
+ case PDFWriter::PushButton:
+ if( eState == PDFWriter::Up || eState == PDFWriter::Down )
+ {
+ aState = (eState == PDFWriter::Up) ? "N" : "D";
+ aStyle = "Standard";
+ }
+ break;
+ case PDFWriter::CheckBox:
+ if( eState == PDFWriter::Up || eState == PDFWriter::Down )
+ {
+ aState = "N";
+ aStyle = (eState == PDFWriter::Up) ? "Off" : "Yes";
+ /* cf PDFReference 3rd ed. V1.4 p539:
+ recommended name for on state is "Yes",
+ recommended name for off state is "Off"
+ */
+ }
+ break;
+ case PDFWriter::RadioButton:
+ if( eState == PDFWriter::Up || eState == PDFWriter::Down )
+ {
+ aState = "N";
+ if( eState == PDFWriter::Up )
+ aStyle = "Off";
+ else
+ {
+ OStringBuffer aBuf( rWidget.m_aOnValue.getLength()*2 );
+ appendName( rWidget.m_aOnValue, aBuf );
+ aStyle = aBuf.makeStringAndClear();
+ }
+ }
+ break;
+ case PDFWriter::Edit:
+ aState = "N";
+ aStyle = "Standard";
+ break;
+ case PDFWriter::ListBox:
+ case PDFWriter::ComboBox:
+ case PDFWriter::Hierarchy:
+ break;
+ }
+ if( aState.getLength() && aStyle.getLength() )
+ {
+ // delete eventual existing stream
+ PDFAppearanceStreams::iterator it =
+ rWidget.m_aAppearances[ aState ].find( aStyle );
+ if( it != rWidget.m_aAppearances[ aState ].end() )
+ delete it->second;
+ rWidget.m_aAppearances[ aState ][ aStyle ] = pAppearance;
+ bRet = true;
+ }
+ }
+
+ if( ! bRet )
+ delete pAppearance;
+
+ m_nCurrentControl = -1;
+
+ return bRet;
+}
+
+void PDFWriterImpl::addStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress )
+{
+ if( pStream )
+ {
+ m_aAdditionalStreams.push_back( PDFAddStream() );
+ PDFAddStream& rStream = m_aAdditionalStreams.back();
+ rStream.m_aMimeType = rMimeType.Len()
+ ? OUString( rMimeType )
+ : OUString( RTL_CONSTASCII_USTRINGPARAM( "application/octet-stream" ) );
+ rStream.m_pStream = pStream;
+ rStream.m_bCompress = bCompress;
+ }
+}
+
+/*************************************************************
+begin i12626 methods
+
+Implements Algorithm 3.2, step 1 only
+*/
+void PDFWriterImpl::padPassword( rtl::OUString aPassword, sal_uInt8 *paPasswordTarget )
+{
+// get ansi-1252 version of the password string CHECKIT ! i12626
+ rtl::OString aString = rtl::OUStringToOString( aPassword, RTL_TEXTENCODING_MS_1252 );
+
+//copy the string to the target
+ sal_Int32 nToCopy = ( aString.getLength() < 32 ) ? aString.getLength() : 32;
+ sal_Int32 nCurrentChar;
+
+ for( nCurrentChar = 0; nCurrentChar < nToCopy; nCurrentChar++ )
+ paPasswordTarget[nCurrentChar] = (sal_uInt8)( aString.getStr()[nCurrentChar] );
+
+//pad it
+ if( nCurrentChar < 32 )
+ {//fill with standard byte string
+ sal_Int32 i,y;
+ for( i = nCurrentChar, y = 0 ; i < 32; i++, y++ )
+ paPasswordTarget[i] = m_nPadString[y];
+ }
+}
+
+/**********************************
+Algorithm 3.2 Compute the encryption key used
+
+step 1 should already be done before calling, the paThePaddedPassword parameter should contain
+the padded password and must be 32 byte long, the encryption key is returned into the paEncryptionKey parameter,
+it will be 16 byte long for 128 bit security; for 40 bit security only the first 5 bytes are used
+
+TODO: in pdf ver 1.5 and 1.6 the step 6 is different, should be implemented. See spec.
+
+*/
+void PDFWriterImpl::computeEncryptionKey(sal_uInt8 *paThePaddedPassword, sal_uInt8 *paEncryptionKey )
+{
+//step 2
+ if( m_aDigest )
+ {
+ rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, paThePaddedPassword, ENCRYPTED_PWD_SIZE );
+//step 3
+ if( nError == rtl_Digest_E_None )
+ nError = rtl_digest_updateMD5( m_aDigest, m_nEncryptedOwnerPassword , sizeof( m_nEncryptedOwnerPassword ) );
+//Step 4
+ sal_uInt8 nPerm[4];
+
+ nPerm[0] = (sal_uInt8)m_nAccessPermissions;
+ nPerm[1] = (sal_uInt8)( m_nAccessPermissions >> 8 );
+ nPerm[2] = (sal_uInt8)( m_nAccessPermissions >> 16 );
+ nPerm[3] = (sal_uInt8)( m_nAccessPermissions >> 24 );
+
+ if( nError == rtl_Digest_E_None )
+ nError = rtl_digest_updateMD5( m_aDigest, nPerm , sizeof( nPerm ) );
+
+//step 5, get the document ID, binary form
+ if( nError == rtl_Digest_E_None )
+ nError = rtl_digest_updateMD5( m_aDigest, m_nDocID , sizeof( m_nDocID ) );
+//get the digest
+ sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
+ if( nError == rtl_Digest_E_None )
+ {
+ rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) );
+
+//step 6, only if 128 bit
+ if( m_aContext.Security128bit )
+ {
+ for( sal_Int32 i = 0; i < 50; i++ )
+ {
+ nError = rtl_digest_updateMD5( m_aDigest, &nMD5Sum, sizeof( nMD5Sum ) );
+ if( nError != rtl_Digest_E_None )
+ break;
+ rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) );
+ }
+ }
+ }
+//Step 7
+ for( sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++ )
+ paEncryptionKey[i] = nMD5Sum[i];
+ }
+}
+
+/**********************************
+Algorithm 3.3 Compute the encryption dictionary /O value, save into the class data member
+the step numbers down here correspond to the ones in PDF v.1.4 specfication
+*/
+void PDFWriterImpl::computeODictionaryValue()
+{
+//step 1 already done, data is in m_nPaddedOwnerPassword
+//step 2
+ if( m_aDigest )
+ {
+ rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, &m_nPaddedOwnerPassword, sizeof( m_nPaddedOwnerPassword ) );
+ if( nError == rtl_Digest_E_None )
+ {
+ sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
+
+ rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof(nMD5Sum) );
+//step 3, only if 128 bit
+ if( m_aContext.Security128bit )
+ {
+ sal_Int32 i;
+ for( i = 0; i < 50; i++ )
+ {
+ nError = rtl_digest_updateMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) );
+ if( nError != rtl_Digest_E_None )
+ break;
+ rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) );
+ }
+ }
+//Step 4, the key is in nMD5Sum
+//step 5 already done, data is in m_nPaddedUserPassword
+//step 6
+ rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode,
+ nMD5Sum, m_nKeyLength , NULL, 0 );
+// encrypt the user password using the key set above
+ rtl_cipher_encodeARCFOUR( m_aCipher, m_nPaddedUserPassword, sizeof( m_nPaddedUserPassword ), // the data to be encrypted
+ m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ) ); //encrypted data, stored in class data member
+//Step 7, only if 128 bit
+ if( m_aContext.Security128bit )
+ {
+ sal_uInt32 i, y;
+ sal_uInt8 nLocalKey[ SECUR_128BIT_KEY ]; // 16 = 128 bit key
+
+ for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1
+ {
+ for( y = 0; y < sizeof( nLocalKey ); y++ )
+ nLocalKey[y] = (sal_uInt8)( nMD5Sum[y] ^ i );
+
+ rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode,
+ nLocalKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area, on init can be NULL
+ rtl_cipher_encodeARCFOUR( m_aCipher, m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ), // the data to be encrypted
+ m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ) ); // encrypted data, can be the same as the input, encrypt "in place"
+//step 8, store in class data member
+ }
+ }
+ }
+ }
+}
+
+/**********************************
+Algorithms 3.4 and 3.5 Compute the encryption dictionary /U value, save into the class data member, revision 2 (40 bit) or 3 (128 bit)
+*/
+void PDFWriterImpl::computeUDictionaryValue()
+{
+//step 1, common to both 3.4 and 3.5
+ computeEncryptionKey( m_nPaddedUserPassword , m_nEncryptionKey );
+
+ if( m_aContext.Security128bit == false )
+ {
+//3.4
+//step 2 and 3
+ rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode,
+ m_nEncryptionKey, 5 , // key and key length
+ NULL, 0 ); //destination data area
+// encrypt the user password using the key set above, save for later use
+ rtl_cipher_encodeARCFOUR( m_aCipher, m_nPadString, sizeof( m_nPadString ), // the data to be encrypted
+ m_nEncryptedUserPassword, sizeof( m_nEncryptedUserPassword ) ); //encrypted data, stored in class data member
+ }
+ else
+ {
+//or 3.5, for 128 bit security
+//step6, initilize the last 16 bytes of the encrypted user password to 0
+ for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sizeof( m_nEncryptedUserPassword ); i++)
+ m_nEncryptedUserPassword[i] = 0;
+//step 2
+ if( m_aDigest )
+ {
+ rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, m_nPadString, sizeof( m_nPadString ) );
+//step 3
+ if( nError == rtl_Digest_E_None )
+ nError = rtl_digest_updateMD5( m_aDigest, m_nDocID , sizeof(m_nDocID) );
+
+ sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
+ rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof(nMD5Sum) );
+//Step 4
+ rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode,
+ m_nEncryptionKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area
+ rtl_cipher_encodeARCFOUR( m_aCipher, nMD5Sum, sizeof( nMD5Sum ), // the data to be encrypted
+ m_nEncryptedUserPassword, sizeof( nMD5Sum ) ); //encrypted data, stored in class data member
+//step 5
+ sal_uInt32 i, y;
+ sal_uInt8 nLocalKey[SECUR_128BIT_KEY];
+
+ for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1
+ {
+ for( y = 0; y < sizeof( nLocalKey ) ; y++ )
+ nLocalKey[y] = (sal_uInt8)( m_nEncryptionKey[y] ^ i );
+
+ rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode,
+ nLocalKey, SECUR_128BIT_KEY, // key and key length
+ NULL, 0 ); //destination data area, on init can be NULL
+ rtl_cipher_encodeARCFOUR( m_aCipher, m_nEncryptedUserPassword, SECUR_128BIT_KEY, // the data to be encrypted
+ m_nEncryptedUserPassword, SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place"
+ }
+ }
+ }
+}
+
+/* init the encryption engine
+1. init the document id, used both for building the document id and for building the encryption key(s)
+2. build the encryption key following algorithms described in the PDF specification
+ */
+void PDFWriterImpl::initEncryption()
+{
+ m_aOwnerPassword = m_aContext.OwnerPassword;
+ m_aUserPassword = m_aContext.UserPassword;
+/* password stuff computing, before sending out anything */
+ DBG_ASSERT( m_aCipher != NULL, "PDFWriterImpl::initEncryption: a cipher (ARCFOUR) object is not available !" );
+ DBG_ASSERT( m_aDigest != NULL, "PDFWriterImpl::initEncryption: a digest (MD5) object is not available !" );
+
+ if( m_aCipher && m_aDigest )
+ {
+//if there is no owner password, force it to the user password
+ if( m_aOwnerPassword.getLength() == 0 )
+ m_aOwnerPassword = m_aUserPassword;
+
+ initPadString();
+/*
+1) pad passwords
+*/
+ padPassword( m_aOwnerPassword, m_nPaddedOwnerPassword );
+ padPassword( m_aUserPassword, m_nPaddedUserPassword );
+/*
+2) compute the access permissions, in numerical form
+
+the default value depends on the revision 2 (40 bit) or 3 (128 bit security):
+- for 40 bit security the unused bit must be set to 1, since they are not used
+- for 128 bit security the same bit must be preset to 0 and set later if needed
+according to the table 3.15, pdf v 1.4 */
+ m_nAccessPermissions = ( m_aContext.Security128bit ) ? 0xfffff0c0 : 0xffffffc0 ;
+
+/* check permissions for 40 bit security case */
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanPrintTheDocument ) ? 1 << 2 : 0;
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanModifyTheContent ) ? 1 << 3 : 0;
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanCopyOrExtract ) ? 1 << 4 : 0;
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanAddOrModify ) ? 1 << 5 : 0;
+ m_nKeyLength = SECUR_40BIT_KEY;
+ m_nRC4KeyLength = SECUR_40BIT_KEY+5; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 5
+
+ if( m_aContext.Security128bit )
+ {
+ m_nKeyLength = SECUR_128BIT_KEY;
+ m_nRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16, thus maximum
+ // permitted value is 16
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanFillInteractive ) ? 1 << 8 : 0;
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanExtractForAccessibility ) ? 1 << 9 : 0;
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanAssemble ) ? 1 << 10 : 0;
+ m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanPrintFull ) ? 1 << 11 : 0;
+ }
+ computeODictionaryValue();
+ computeUDictionaryValue();
+
+//clear out exceding key values, prepares for generation number default to 0 as well
+// see checkAndEnableStreamEncryption in pdfwriter_impl.hxx
+ sal_Int32 i, y;
+ for( i = m_nKeyLength, y = 0; y < 5 ; y++ )
+ m_nEncryptionKey[i++] = 0;
+ }
+ else //either no cipher or no digest or both, something is wrong with memory or something else
+ m_aContext.Encrypt = false; //then turn the encryption off
+}
+/* end i12626 methods */
+
diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx
new file mode 100644
index 000000000000..2eacdc215dd8
--- /dev/null
+++ b/vcl/source/gdi/pdfwriter_impl.hxx
@@ -0,0 +1,1375 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef _VCL_PDFWRITER_IMPL_HXX
+#define _VCL_PDFWRITER_IMPL_HXX
+
+#include "vcl/pdfwriter.hxx"
+#include "rtl/ustring.hxx"
+#include "osl/file.h"
+#include "tools/gen.hxx"
+#include "tools/stream.hxx"
+#include "vcl/outdev.hxx"
+#include "vcl/bitmapex.hxx"
+#include "vcl/gradient.hxx"
+#include "vcl/hatch.hxx"
+#include "vcl/wall.hxx"
+#include "vcl/outdata.hxx"
+#include "rtl/strbuf.hxx"
+#include "rtl/cipher.h"
+#include "rtl/digest.h"
+#include "com/sun/star/util/XURLTransformer.hpp"
+#include "com/sun/star/lang/Locale.hpp"
+
+#include <vcl/sallayout.hxx>
+#include "pdffontcache.hxx"
+
+#include <vector>
+#include <map>
+#include <hash_map>
+#include <list>
+
+#include <boost/shared_array.hpp>
+
+class ImplFontSelectData;
+class ImplFontMetricData;
+class FontSubsetInfo;
+class ZCodec;
+
+// the maximum password length
+#define ENCRYPTED_PWD_SIZE 32
+#define MD5_DIGEST_SIZE 16
+#define SECUR_40BIT_KEY 5
+// security 128 bit
+#define SECUR_128BIT_KEY 16
+// maximum length of MD5 digest input, in step 2 of algorithm 3.1
+// PDF spec ver. 1.4: see there for details
+#define MAXIMUM_RC4_KEY_LENGTH (SECUR_128BIT_KEY+3+2)
+
+namespace vcl
+{
+
+class PDFSalLayout;
+class PDFStreamIf;
+class Matrix3;
+
+class PDFWriterImpl
+{
+ friend class PDFSalLayout;
+ friend class PDFStreamIf;
+public:
+ // definition of structs
+ struct BuiltinFont
+ {
+ const char * m_pName; // Name
+ const char * m_pStyleName; // StyleName
+ const char * m_pPSName; // PSName
+ int m_nAscent;
+ int m_nDescent;
+ FontFamily m_eFamily; // Family
+ CharSet m_eCharSet; // CharSet
+ FontPitch m_ePitch; // Pitch
+ FontWidth m_eWidthType; // WidthType
+ FontWeight m_eWeight; // Weight
+ FontItalic m_eItalic; // Italic
+ int m_aWidths[256]; // character metrics
+
+ rtl::OString getNameObject() const;
+ };
+
+
+ enum ResourceKind { ResXObject, ResExtGState, ResShading, ResPattern };
+ typedef std::map< rtl::OString, sal_Int32 > ResourceMap;
+ struct ResourceDict
+ {
+ // note: handle fonts globally for performance
+ ResourceMap m_aXObjects;
+ ResourceMap m_aExtGStates;
+ ResourceMap m_aShadings;
+ ResourceMap m_aPatterns;
+
+ void append( rtl::OStringBuffer&, sal_Int32 nFontDictObject );
+ };
+
+ struct PDFPage
+ {
+ PDFWriterImpl* m_pWriter;
+ sal_Int32 m_nPageWidth; // in inch/72
+ sal_Int32 m_nPageHeight; // in inch/72
+ PDFWriter::Orientation m_eOrientation;
+ sal_Int32 m_nPageObject;
+ sal_Int32 m_nPageIndex;
+ std::vector<sal_Int32> m_aStreamObjects;
+ sal_Int32 m_nStreamLengthObject;
+ sal_uInt64 m_nBeginStreamPos;
+ std::vector<sal_Int32> m_aAnnotations;
+ std::vector<sal_Int32> m_aMCIDParents;
+ PDFWriter::PageTransition m_eTransition;
+ sal_uInt32 m_nTransTime;
+ sal_uInt32 m_nDuration;
+ bool m_bHasWidgets;
+
+ PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation );
+ ~PDFPage();
+
+ void beginStream();
+ void endStream();
+ bool emit( sal_Int32 nParentPage );
+
+ // converts point from ref device coordinates to
+ // page coordinates and appends the point to the buffer
+ // if bNeg is true, the coordinates are inverted AFTER transformation
+ // to page (useful for transformation matrices
+ // if pOutPoint is set it will be updated to the emitted point
+ // (in PDF map mode, that is 10th of point)
+ void appendPoint( const Point& rPoint, rtl::OStringBuffer& rBuffer, bool bNeg = false, Point* pOutPoint = NULL ) const;
+ // appends a B2DPoint without further transformation
+ void appendPixelPoint( const basegfx::B2DPoint& rPoint, rtl::OStringBuffer& rBuffer ) const;
+ // appends a rectangle
+ void appendRect( const Rectangle& rRect, rtl::OStringBuffer& rBuffer ) const;
+ // converts a rectangle to 10th points page space
+ void convertRect( Rectangle& rRect ) const;
+ // appends a polygon optionally closing it
+ void appendPolygon( const Polygon& rPoly, rtl::OStringBuffer& rBuffer, bool bClose = true ) const;
+ // appends a polygon optionally closing it
+ void appendPolygon( const basegfx::B2DPolygon& rPoly, rtl::OStringBuffer& rBuffer, bool bClose = true ) const;
+ // appends a polypolygon optionally closing the subpaths
+ void appendPolyPolygon( const PolyPolygon& rPolyPoly, rtl::OStringBuffer& rBuffer, bool bClose = true ) const;
+ // appends a polypolygon optionally closing the subpaths
+ void appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, rtl::OStringBuffer& rBuffer, bool bClose = true ) const;
+ // converts a length (either vertical or horizontal; this
+ // can be important if the source MapMode is not
+ // symmetrical) to page length and appends it to the buffer
+ // if pOutLength is set it will be updated to the emitted length
+ // (in PDF map mode, that is 10th of point)
+ void appendMappedLength( sal_Int32 nLength, rtl::OStringBuffer& rBuffer, bool bVertical = true, sal_Int32* pOutLength = NULL ) const;
+ // the same for double values
+ void appendMappedLength( double fLength, rtl::OStringBuffer& rBuffer, bool bVertical = true, sal_Int32* pOutLength = NULL, sal_Int32 nPrecision = 5 ) const;
+ // appends LineInfo
+ // returns false if too many dash array entry were created for
+ // the implementation limits of some PDF readers
+ bool appendLineInfo( const LineInfo& rInfo, rtl::OStringBuffer& rBuffer ) const;
+ // appends a horizontal waveline with vertical offset (helper for drawWaveLine)
+ void appendWaveLine( sal_Int32 nLength, sal_Int32 nYOffset, sal_Int32 nDelta, rtl::OStringBuffer& rBuffer ) const;
+
+ sal_Int32 getWidth() const { return m_nPageWidth ? m_nPageWidth : m_pWriter->m_nInheritedPageWidth; }
+ sal_Int32 getHeight() const { return m_nPageHeight ? m_nPageHeight : m_pWriter->m_nInheritedPageHeight; }
+ };
+
+ friend struct PDFPage;
+
+ struct BitmapID
+ {
+ Size m_aPixelSize;
+ sal_Int32 m_nSize;
+ sal_Int32 m_nChecksum;
+ sal_Int32 m_nMaskChecksum;
+
+ BitmapID() : m_nSize( 0 ), m_nChecksum( 0 ), m_nMaskChecksum( 0 ) {}
+
+ BitmapID& operator=( const BitmapID& rCopy )
+ {
+ m_aPixelSize = rCopy.m_aPixelSize;
+ m_nSize = rCopy.m_nSize;
+ m_nChecksum = rCopy.m_nChecksum;
+ m_nMaskChecksum = rCopy.m_nMaskChecksum;
+ return *this;
+ }
+
+ bool operator==( const BitmapID& rComp )
+ {
+ return (m_aPixelSize == rComp.m_aPixelSize &&
+ m_nSize == rComp.m_nSize &&
+ m_nChecksum == rComp.m_nChecksum &&
+ m_nMaskChecksum == rComp.m_nMaskChecksum );
+ }
+ };
+
+ struct BitmapEmit
+ {
+ BitmapID m_aID;
+ BitmapEx m_aBitmap;
+ sal_Int32 m_nObject;
+ bool m_bDrawMask;
+
+ BitmapEmit() : m_bDrawMask( false ) {}
+ };
+
+ struct JPGEmit
+ {
+ BitmapID m_aID;
+ SvMemoryStream* m_pStream;
+ Bitmap m_aMask;
+ sal_Int32 m_nObject;
+ bool m_bTrueColor;
+
+ JPGEmit() : m_pStream( NULL ) {}
+ ~JPGEmit() { delete m_pStream; }
+ };
+
+ struct GradientEmit
+ {
+ Gradient m_aGradient;
+ Size m_aSize;
+ sal_Int32 m_nObject;
+ };
+
+ // for tilings (drawWallpaper, begin/endPattern)
+ struct TilingEmit
+ {
+ sal_Int32 m_nObject;
+ Rectangle m_aRectangle;
+ Size m_aCellSize;
+ SvtGraphicFill::Transform m_aTransform;
+ ResourceDict m_aResources;
+ SvMemoryStream* m_pTilingStream;
+
+ TilingEmit()
+ : m_nObject( 0 ),
+ m_pTilingStream( NULL )
+ {}
+ };
+
+ // for transparency group XObjects
+ struct TransparencyEmit
+ {
+ sal_Int32 m_nObject;
+ sal_Int32 m_nExtGStateObject;
+ double m_fAlpha;
+ Rectangle m_aBoundRect;
+ SvMemoryStream* m_pContentStream;
+ SvMemoryStream* m_pSoftMaskStream;
+
+ TransparencyEmit()
+ : m_nObject( 0 ),
+ m_nExtGStateObject( -1 ),
+ m_fAlpha( 0.0 ),
+ m_pContentStream( NULL ),
+ m_pSoftMaskStream( NULL )
+ {}
+ ~TransparencyEmit()
+ {
+ delete m_pContentStream;
+ delete m_pSoftMaskStream;
+ }
+ };
+
+ // font subsets
+ class GlyphEmit
+ {
+ // performance: actually this should probably a vector;
+ sal_Ucs m_aBufferedUnicodes[3];
+ sal_Int32 m_nUnicodes;
+ sal_Int32 m_nMaxUnicodes;
+ boost::shared_array<sal_Ucs> m_pUnicodes;
+ sal_uInt8 m_nSubsetGlyphID;
+
+ public:
+ GlyphEmit() : m_nUnicodes(0), m_nSubsetGlyphID(0)
+ {
+ rtl_zeroMemory( m_aBufferedUnicodes, sizeof( m_aBufferedUnicodes ) );
+ m_nMaxUnicodes = sizeof(m_aBufferedUnicodes)/sizeof(m_aBufferedUnicodes[0]);
+ }
+ ~GlyphEmit()
+ {
+ }
+
+ void setGlyphId( sal_uInt8 i_nId ) { m_nSubsetGlyphID = i_nId; }
+ sal_uInt8 getGlyphId() const { return m_nSubsetGlyphID; }
+
+ void addCode( sal_Ucs i_cCode )
+ {
+ if( m_nUnicodes == m_nMaxUnicodes )
+ {
+ sal_Ucs* pNew = new sal_Ucs[ 2 * m_nMaxUnicodes];
+ if( m_pUnicodes.get() )
+ rtl_copyMemory( pNew, m_pUnicodes.get(), m_nMaxUnicodes * sizeof(sal_Ucs) );
+ else
+ rtl_copyMemory( pNew, m_aBufferedUnicodes, m_nMaxUnicodes * sizeof(sal_Ucs) );
+ m_pUnicodes.reset( pNew );
+ m_nMaxUnicodes *= 2;
+ }
+ if( m_pUnicodes.get() )
+ m_pUnicodes[ m_nUnicodes++ ] = i_cCode;
+ else
+ m_aBufferedUnicodes[ m_nUnicodes++ ] = i_cCode;
+ }
+ sal_Int32 countCodes() const { return m_nUnicodes; }
+ sal_Ucs getCode( sal_Int32 i_nIndex ) const
+ {
+ sal_Ucs nRet = 0;
+ if( i_nIndex < m_nUnicodes )
+ nRet = m_pUnicodes.get() ? m_pUnicodes[ i_nIndex ] : m_aBufferedUnicodes[ i_nIndex ];
+ return nRet;
+ }
+ };
+ typedef std::map< sal_GlyphId, GlyphEmit > FontEmitMapping;
+ struct FontEmit
+ {
+ sal_Int32 m_nFontID;
+ FontEmitMapping m_aMapping;
+
+ FontEmit( sal_Int32 nID ) : m_nFontID( nID ) {}
+ };
+ typedef std::list< FontEmit > FontEmitList;
+ struct Glyph
+ {
+ sal_Int32 m_nFontID;
+ sal_uInt8 m_nSubsetGlyphID;
+ };
+ typedef std::map< sal_GlyphId, Glyph > FontMapping;
+ struct FontSubset
+ {
+ FontEmitList m_aSubsets;
+ FontMapping m_aMapping;
+ };
+ typedef std::map< const ImplFontData*, FontSubset > FontSubsetData;
+ struct EmbedCode
+ {
+ sal_Ucs m_aUnicode;
+ rtl::OString m_aName;
+ };
+ struct EmbedEncoding
+ {
+ sal_Int32 m_nFontID;
+ std::vector< EmbedCode > m_aEncVector;
+ std::map< sal_Ucs, sal_Int8 > m_aCMap;
+ };
+ struct EmbedFont
+ {
+ sal_Int32 m_nNormalFontID;
+ std::list< EmbedEncoding > m_aExtendedEncodings;
+
+ EmbedFont() : m_nNormalFontID( 0 ) {}
+ };
+ typedef std::map< const ImplFontData*, EmbedFont > FontEmbedData;
+
+ struct PDFDest
+ {
+ sal_Int32 m_nPage;
+ PDFWriter::DestAreaType m_eType;
+ Rectangle m_aRect;
+ };
+
+//--->i56629
+ struct PDFNamedDest
+ {
+ rtl::OUString m_aDestName;
+ sal_Int32 m_nPage;
+ PDFWriter::DestAreaType m_eType;
+ Rectangle m_aRect;
+ };
+//<---
+
+ struct PDFOutlineEntry
+ {
+ sal_Int32 m_nParentID;
+ sal_Int32 m_nObject;
+ sal_Int32 m_nParentObject;
+ sal_Int32 m_nNextObject;
+ sal_Int32 m_nPrevObject;
+ std::vector< sal_Int32 > m_aChildren;
+ rtl::OUString m_aTitle;
+ sal_Int32 m_nDestID;
+
+ PDFOutlineEntry()
+ : m_nParentID( -1 ),
+ m_nObject( 0 ),
+ m_nParentObject( 0 ),
+ m_nNextObject( 0 ),
+ m_nPrevObject( 0 ),
+ m_nDestID( -1 )
+ {}
+ };
+
+ struct PDFAnnotation
+ {
+ sal_Int32 m_nObject;
+ Rectangle m_aRect;
+ sal_Int32 m_nPage;
+
+ PDFAnnotation()
+ : m_nObject( -1 ),
+ m_nPage( -1 )
+ {}
+ };
+
+ struct PDFLink : public PDFAnnotation
+ {
+ sal_Int32 m_nDest; // set to -1 for URL, to a dest else
+ rtl::OUString m_aURL;
+ sal_Int32 m_nStructParent; // struct parent entry
+
+ PDFLink()
+ : m_nDest( -1 ),
+ m_nStructParent( -1 )
+ {}
+ };
+
+ struct PDFNoteEntry : public PDFAnnotation
+ {
+ PDFNote m_aContents;
+
+ PDFNoteEntry()
+ {}
+ };
+
+ typedef std::hash_map< rtl::OString, SvMemoryStream*, rtl::OStringHash > PDFAppearanceStreams;
+ typedef std::hash_map< rtl::OString, PDFAppearanceStreams, rtl::OStringHash > PDFAppearanceMap;
+
+ struct PDFWidget : public PDFAnnotation
+ {
+ PDFWriter::WidgetType m_eType;
+ rtl::OString m_aName;
+ rtl::OUString m_aDescription;
+ rtl::OUString m_aText;
+ USHORT m_nTextStyle;
+ rtl::OUString m_aValue;
+ rtl::OString m_aDAString;
+ rtl::OString m_aDRDict;
+ rtl::OString m_aMKDict;
+ rtl::OString m_aMKDictCAString; // i12626, added to be able to encrypt the /CA text string
+ // since the object number is not known at the moment
+ // of filling m_aMKDict, the string will be encrypted when emitted.
+ // the /CA string MUST BE the last added to m_aMKDict
+ // see code for details
+ sal_Int32 m_nFlags;
+ sal_Int32 m_nParent; // if not 0, parent's object number
+ std::vector<sal_Int32> m_aKids; // widget children, contains object numbers
+ std::vector<sal_Int32> m_aKidsIndex; // widget children, contains index to m_aWidgets
+ rtl::OUString m_aOnValue;
+ sal_Int32 m_nTabOrder; // lowest number gets first in tab order
+ sal_Int32 m_nRadioGroup;
+ sal_Int32 m_nMaxLen;
+ bool m_bSubmit;
+ bool m_bSubmitGet;
+ sal_Int32 m_nDest;
+ std::vector<rtl::OUString> m_aListEntries;
+ std::vector<sal_Int32> m_aSelectedEntries;
+ PDFAppearanceMap m_aAppearances;
+ PDFWidget()
+ : m_eType( PDFWriter::PushButton ),
+ m_nTextStyle( 0 ),
+ m_nFlags( 0 ),
+ m_nParent( 0 ),
+ m_nRadioGroup( -1 ),
+ m_nMaxLen( 0 ),
+ m_bSubmit( false ),
+ m_bSubmitGet( false ),
+ m_nDest( -1 )
+ {}
+ };
+
+ struct PDFStructureAttribute
+ {
+ PDFWriter::StructAttributeValue eValue;
+ sal_Int32 nValue;
+
+ PDFStructureAttribute()
+ : eValue( PDFWriter::Invalid ),
+ nValue( 0 )
+ {}
+
+ PDFStructureAttribute( PDFWriter::StructAttributeValue eVal )
+ : eValue( eVal ),
+ nValue( 0 )
+ {}
+
+ PDFStructureAttribute( sal_Int32 nVal )
+ : eValue( PDFWriter::Invalid ),
+ nValue( nVal )
+ {}
+ };
+
+ typedef std::map<PDFWriter::StructAttribute, PDFStructureAttribute > PDFStructAttributes;
+
+ struct PDFStructureElementKid // for Kids entries
+ {
+ sal_Int32 nObject; // an object number if nMCID is -1,
+ // else the page object relevant to MCID
+ sal_Int32 nMCID; // an MCID if >= 0
+
+ PDFStructureElementKid( sal_Int32 nObj ) : nObject( nObj ), nMCID( -1 ) {}
+ PDFStructureElementKid( sal_Int32 MCID, sal_Int32 nPage ) : nObject( nPage ), nMCID( MCID ) {}
+ };
+
+ struct PDFStructureElement
+ {
+ sal_Int32 m_nObject;
+ PDFWriter::StructElement m_eType;
+ rtl::OString m_aAlias;
+ sal_Int32 m_nOwnElement; // index into structure vector
+ sal_Int32 m_nParentElement; // index into structure vector
+ sal_Int32 m_nFirstPageObject;
+ bool m_bOpenMCSeq;
+ std::list< sal_Int32 > m_aChildren; // indexes into structure vector
+ std::list< PDFStructureElementKid > m_aKids;
+ PDFStructAttributes m_aAttributes;
+ Rectangle m_aBBox;
+ rtl::OUString m_aActualText;
+ rtl::OUString m_aAltText;
+ com::sun::star::lang::Locale m_aLocale;
+
+ // m_aContents contains the element's marked content sequence
+ // as pairs of (page nr, MCID)
+
+ PDFStructureElement()
+ : m_nObject( 0 ),
+ m_eType( PDFWriter::NonStructElement ),
+ m_nOwnElement( -1 ),
+ m_nParentElement( -1 ),
+ m_nFirstPageObject( 0 ),
+ m_bOpenMCSeq( false )
+ {
+ }
+
+ };
+
+ struct PDFAddStream
+ {
+ rtl::OUString m_aMimeType;
+ PDFOutputStream* m_pStream;
+ sal_Int32 m_nStreamObject;
+ bool m_bCompress;
+
+ PDFAddStream() : m_pStream( NULL ), m_nStreamObject( 0 ), m_bCompress( true ) {}
+ };
+
+
+ // helper structure for drawLayout and friends
+ struct PDFGlyph
+ {
+ Point m_aPos;
+ sal_Int32 m_nNativeWidth;
+ sal_Int32 m_nGlyphId;
+ sal_Int32 m_nMappedFontId;
+ sal_uInt8 m_nMappedGlyphId;
+
+ PDFGlyph( const Point& rPos,
+ sal_Int32 nNativeWidth,
+ sal_Int32 nGlyphId,
+ sal_Int32 nFontId,
+ sal_uInt8 nMappedGlyphId )
+ : m_aPos( rPos ), m_nNativeWidth( nNativeWidth ), m_nGlyphId( nGlyphId ),
+ m_nMappedFontId( nFontId ), m_nMappedGlyphId( nMappedGlyphId )
+ {}
+ };
+
+
+ static const sal_Char* getStructureTag( PDFWriter::StructElement );
+ static const sal_Char* getAttributeTag( PDFWriter::StructAttribute eAtr );
+ static const sal_Char* getAttributeValueTag( PDFWriter::StructAttributeValue eVal );
+
+ // returns true if compression was done
+ // else false
+ static bool compressStream( SvMemoryStream* );
+
+ static void convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut );
+private:
+ static const BuiltinFont m_aBuiltinFonts[14];
+
+ OutputDevice* m_pReferenceDevice;
+
+ MapMode m_aMapMode; // PDFWriterImpl scaled units
+ std::vector< PDFPage > m_aPages;
+ PDFDocInfo m_aDocInfo;
+ /* maps object numbers to file offsets (needed for xref) */
+ std::vector< sal_uInt64 > m_aObjects;
+ /* contains Bitmaps until they are written to the
+ * file stream as XObjects*/
+ std::list< BitmapEmit > m_aBitmaps;
+ /* contains JPG streams until written to file */
+ std::list<JPGEmit> m_aJPGs;
+ /*--->i56629 contains all named destinations ever set during the PDF creation,
+ destination id is always the destination's position in this vector
+ */
+ std::vector<PDFNamedDest> m_aNamedDests;
+ //<---
+ /* contains all dests ever set during the PDF creation,
+ dest id is always the dest's position in this vector
+ */
+ std::vector<PDFDest> m_aDests;
+ /* contains all links ever set during PDF creation,
+ link id is always the link's position in this vector
+ */
+ std::vector<PDFLink> m_aLinks;
+ /* makes correctly encoded for export to PDF URLS
+ */
+ com::sun::star::uno::Reference< com::sun::star::util::XURLTransformer > m_xTrans;
+ /* maps arbitrary link ids for structure attributes to real link ids
+ (for setLinkPropertyId)
+ */
+ std::map<sal_Int32, sal_Int32> m_aLinkPropertyMap;
+ /* contains all outline items,
+ object 0 is the outline root
+ */
+ std::vector<PDFOutlineEntry> m_aOutline;
+ /* contains all notes set during PDF creation
+ */
+ std::vector<PDFNoteEntry> m_aNotes;
+ /* the root of the structure tree
+ */
+ std::vector<PDFStructureElement> m_aStructure;
+ /* current object in the structure hierarchy
+ */
+ sal_Int32 m_nCurrentStructElement;
+ /* structure parent tree */
+ std::vector< rtl::OString > m_aStructParentTree;
+ /* emit strucure marks currently (aka. NonStructElement or not)
+ */
+ bool m_bEmitStructure;
+ bool m_bNewMCID;
+ /* role map of struct tree root */
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >
+ m_aRoleMap;
+
+ /* contains all widgets used in the PDF
+ */
+ std::vector<PDFWidget> m_aWidgets;
+ /* maps radio group id to index of radio group control in m_aWidgets */
+ std::map< sal_Int32, sal_Int32 > m_aRadioGroupWidgets;
+ /* used to store control id during beginControlAppearance/endControlAppearance */
+ sal_Int32 m_nCurrentControl;
+ /* hash_map for field names, used to ensure unique field names */
+ std::hash_map< rtl::OString, sal_Int32, rtl::OStringHash > m_aFieldNameMap;
+
+ /* contains Bitmaps for gradient functions until they are written
+ * to the file stream */
+ std::list< GradientEmit > m_aGradients;
+ /* contains bitmap tiling patterns */
+ std::vector< TilingEmit > m_aTilings;
+ std::list< TransparencyEmit > m_aTransparentObjects;
+ /* contains all font subsets in use */
+ FontSubsetData m_aSubsets;
+ bool m_bEmbedStandardFonts;
+ FontEmbedData m_aEmbeddedFonts;
+ FontEmbedData m_aSystemFonts;
+ sal_Int32 m_nNextFID;
+ PDFFontCache m_aFontCache;
+
+ sal_Int32 m_nInheritedPageWidth; // in inch/72
+ sal_Int32 m_nInheritedPageHeight; // in inch/72
+ PDFWriter::Orientation m_eInheritedOrientation;
+ sal_Int32 m_nCurrentPage;
+
+ sal_Int32 m_nCatalogObject;
+ sal_Int32 m_nResourceDict;
+ ResourceDict m_aGlobalResourceDict;
+ sal_Int32 m_nFontDictObject;
+ std::map< sal_Int32, sal_Int32 > m_aBuiltinFontToObjectMap;
+
+ PDFWriter::PDFWriterContext m_aContext;
+ oslFileHandle m_aFile;
+ bool m_bOpen;
+
+
+ /* output redirection; e.g. to accumulate content streams for
+ XObjects
+ */
+ struct StreamRedirect
+ {
+ SvStream* m_pStream;
+ MapMode m_aMapMode;
+ Rectangle m_aTargetRect;
+ ResourceDict m_aResourceDict;
+ };
+ std::list< StreamRedirect > m_aOutputStreams;
+
+ // graphics state
+ struct GraphicsState
+ {
+ Font m_aFont;
+ MapMode m_aMapMode;
+ Color m_aLineColor;
+ Color m_aFillColor;
+ Color m_aTextLineColor;
+ Color m_aOverlineColor;
+ basegfx::B2DPolyPolygon m_aClipRegion;
+ bool m_bClipRegion;
+ sal_Int32 m_nAntiAlias;
+ sal_Int32 m_nLayoutMode;
+ LanguageType m_aDigitLanguage;
+ sal_Int32 m_nTransparentPercent;
+ sal_uInt16 m_nFlags;
+ sal_uInt16 m_nUpdateFlags;
+
+ static const sal_uInt16 updateFont = 0x0001;
+ static const sal_uInt16 updateMapMode = 0x0002;
+ static const sal_uInt16 updateLineColor = 0x0004;
+ static const sal_uInt16 updateFillColor = 0x0008;
+ static const sal_uInt16 updateTextLineColor = 0x0010;
+ static const sal_uInt16 updateOverlineColor = 0x0020;
+ static const sal_uInt16 updateClipRegion = 0x0040;
+ static const sal_uInt16 updateAntiAlias = 0x0080;
+ static const sal_uInt16 updateLayoutMode = 0x0100;
+ static const sal_uInt16 updateTransparentPercent = 0x0200;
+ static const sal_uInt16 updateDigitLanguage = 0x0400;
+
+ GraphicsState() :
+ m_aLineColor( COL_TRANSPARENT ),
+ m_aFillColor( COL_TRANSPARENT ),
+ m_aTextLineColor( COL_TRANSPARENT ),
+ m_aOverlineColor( COL_TRANSPARENT ),
+ m_bClipRegion( false ),
+ m_nAntiAlias( 1 ),
+ m_nLayoutMode( 0 ),
+ m_aDigitLanguage( 0 ),
+ m_nTransparentPercent( 0 ),
+ m_nFlags( 0xffff ),
+ m_nUpdateFlags( 0xffff )
+ {}
+ GraphicsState( const GraphicsState& rState ) :
+ m_aFont( rState.m_aFont ),
+ m_aMapMode( rState.m_aMapMode ),
+ m_aLineColor( rState.m_aLineColor ),
+ m_aFillColor( rState.m_aFillColor ),
+ m_aTextLineColor( rState.m_aTextLineColor ),
+ m_aOverlineColor( rState.m_aOverlineColor ),
+ m_aClipRegion( rState.m_aClipRegion ),
+ m_bClipRegion( rState.m_bClipRegion ),
+ m_nAntiAlias( rState.m_nAntiAlias ),
+ m_nLayoutMode( rState.m_nLayoutMode ),
+ m_aDigitLanguage( rState.m_aDigitLanguage ),
+ m_nTransparentPercent( rState.m_nTransparentPercent ),
+ m_nFlags( rState.m_nFlags ),
+ m_nUpdateFlags( rState.m_nUpdateFlags )
+ {
+ }
+
+ GraphicsState& operator=(const GraphicsState& rState )
+ {
+ m_aFont = rState.m_aFont;
+ m_aMapMode = rState.m_aMapMode;
+ m_aLineColor = rState.m_aLineColor;
+ m_aFillColor = rState.m_aFillColor;
+ m_aTextLineColor = rState.m_aTextLineColor;
+ m_aOverlineColor = rState.m_aOverlineColor;
+ m_aClipRegion = rState.m_aClipRegion;
+ m_bClipRegion = rState.m_bClipRegion;
+ m_nAntiAlias = rState.m_nAntiAlias;
+ m_nLayoutMode = rState.m_nLayoutMode;
+ m_aDigitLanguage = rState.m_aDigitLanguage;
+ m_nTransparentPercent = rState.m_nTransparentPercent;
+ m_nFlags = rState.m_nFlags;
+ m_nUpdateFlags = rState.m_nUpdateFlags;
+ return *this;
+ }
+ };
+ std::list< GraphicsState > m_aGraphicsStack;
+ GraphicsState m_aCurrentPDFState;
+
+ ZCodec* m_pCodec;
+ SvMemoryStream* m_pMemStream;
+
+ std::vector< PDFAddStream > m_aAdditionalStreams;
+ std::set< PDFWriter::ErrorCode > m_aErrors;
+
+ rtlDigest m_aDocDigest;
+
+/*
+variables for PDF security
+i12626
+*/
+/* used to cipher the stream data and for password management */
+ rtlCipher m_aCipher;
+ rtlDigest m_aDigest;
+/* pad string used for password in Standard security handler */
+ sal_uInt8 m_nPadString[ENCRYPTED_PWD_SIZE];
+/* the owner password, in clear text */
+ rtl::OUString m_aOwnerPassword;
+/* the padded owner password */
+ sal_uInt8 m_nPaddedOwnerPassword[ENCRYPTED_PWD_SIZE];
+/* the encryption dictionary owner password, according to algorithm 3.3 */
+ sal_uInt8 m_nEncryptedOwnerPassword[ENCRYPTED_PWD_SIZE];
+/* the user password, in clear text */
+ rtl::OUString m_aUserPassword;
+/* the padded user password */
+ sal_uInt8 m_nPaddedUserPassword[ENCRYPTED_PWD_SIZE];
+/* the encryption dictionary user password, according to algorithm 3.4 or 3.5 depending on the
+ security handler revision */
+ sal_uInt8 m_nEncryptedUserPassword[ENCRYPTED_PWD_SIZE];
+
+/* the encryption key, formed with the user password according to algorithm 3.2, maximum length is 16 bytes + 3 + 2
+ for 128 bit security */
+ sal_uInt8 m_nEncryptionKey[MAXIMUM_RC4_KEY_LENGTH];
+ sal_Int32 m_nKeyLength; // key length, 16 or 5
+ sal_Int32 m_nRC4KeyLength; // key length, 16 or 10, to be input to the algorith 3.1
+
+/* set to true if the following stream must be encrypted, used inside writeBuffer() */
+ sal_Bool m_bEncryptThisStream;
+
+/* the numerical value of the access permissions, according to PDF spec, must be signed */
+ sal_Int32 m_nAccessPermissions;
+/* the document ID, the raw MD5 hash */
+ sal_uInt8 m_nDocID[MD5_DIGEST_SIZE];
+/* string buffer to hold document ID, this is the output string */
+ rtl::OStringBuffer m_aDocID;
+/* string to hold the PDF creation date */
+ rtl::OStringBuffer m_aCreationDateString;
+/* string to hold the PDF creation date, for PDF/A metadata */
+ rtl::OStringBuffer m_aCreationMetaDateString;
+/* the buffer where the data are encrypted, dynamically allocated */
+ sal_uInt8 *m_pEncryptionBuffer;
+/* size of the buffer */
+ sal_Int32 m_nEncryptionBufferSize;
+
+/* check and reallocate the buffer for encryption */
+ sal_Bool checkEncryptionBufferSize( register sal_Int32 newSize )
+ {
+ if( m_nEncryptionBufferSize < newSize )
+ {
+/* reallocate the buffer, the used function allocate as rtl_allocateMemory
+ if the pointer parameter is NULL */
+ m_pEncryptionBuffer = (sal_uInt8*)rtl_reallocateMemory( m_pEncryptionBuffer, newSize );
+ if( m_pEncryptionBuffer )
+ m_nEncryptionBufferSize = newSize;
+ else
+ m_nEncryptionBufferSize = 0;
+ }
+ return ( m_nEncryptionBufferSize != 0 );
+ }
+/* init the internal pad string */
+ void initPadString()
+ {
+ static const sal_uInt8 nPadString[32] =
+ {
+ 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
+ 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
+ };
+
+ for(sal_uInt32 i = 0; i < sizeof( nPadString ); i++ )
+ m_nPadString[i] = nPadString[i];
+
+ };
+/* initialize the encryption engine */
+ void initEncryption();
+
+/* this function implements part of the PDF spec algorithm 3.1 in encryption, the rest (the actual encryption) is in PDFWriterImpl::writeBuffer */
+ void checkAndEnableStreamEncryption( register sal_Int32 nObject )
+ {
+ if( m_aContext.Encrypt )
+ {
+ m_bEncryptThisStream = true;
+ register sal_Int32 i = m_nKeyLength;
+ m_nEncryptionKey[i++] = (sal_uInt8)nObject;
+ m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 8 );
+ m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 16 );
+//the other location of m_nEncryptionKey are already set to 0, our fixed generation number
+// do the MD5 hash
+ sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
+ // the i+2 to take into account the generation number, always zero
+ rtl_digest_MD5( &m_nEncryptionKey, i+2, nMD5Sum, sizeof(nMD5Sum) );
+// initialize the RC4 with the key
+// key legth: see algoritm 3.1, step 4: (N+5) max 16
+ rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 );
+ }
+ };
+
+ void disableStreamEncryption() { m_bEncryptThisStream = false; };
+
+/* */
+ void enableStringEncryption( register sal_Int32 nObject )
+ {
+ register sal_Int32 i = m_nKeyLength;
+ m_nEncryptionKey[i++] = (sal_uInt8)nObject;
+ m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 8 );
+ m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 16 );
+//the other location of m_nEncryptionKey are already set to 0, our fixed generation number
+// do the MD5 hash
+ sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
+ // the i+2 to take into account the generation number, always zero
+ rtl_digest_MD5( &m_nEncryptionKey, i+2, nMD5Sum, sizeof(nMD5Sum) );
+// initialize the RC4 with the key
+// key legth: see algoritm 3.1, step 4: (N+5) max 16
+ rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 );
+ };
+
+// test if the encryption is active, if yes than encrypt the unicode string and add to the OStringBuffer parameter
+ void appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer );
+
+ void appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer );
+ void appendLiteralStringEncrypt( const rtl::OString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer );
+ void appendLiteralStringEncrypt( rtl::OStringBuffer& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer );
+
+ /* creates fonts and subsets that will be emitted later */
+ void registerGlyphs( int nGlyphs, sal_GlyphId* pGlyphs, sal_Int32* pGlpyhWidths, sal_Ucs* pUnicodes, sal_Int32* pUnicodesPerGlyph, sal_uInt8* pMappedGlyphs, sal_Int32* pMappedFontObjects, const ImplFontData* pFallbackFonts[] );
+
+ /* emits a text object according to the passed layout */
+ /* TODO: remove rText as soon as SalLayout will change so that rText is not necessary anymore */
+ void drawVerticalGlyphs( const std::vector<PDFGlyph>& rGlyphs, rtl::OStringBuffer& rLine, const Point& rAlignOffset, const Matrix3& rRotScale, double fAngle, double fXScale, double fSkew, sal_Int32 nFontHeight );
+ void drawHorizontalGlyphs( const std::vector<PDFGlyph>& rGlyphs, rtl::OStringBuffer& rLine, const Point& rAlignOffset, double fAngle, double fXScale, double fSkew, sal_Int32 nFontHeight, sal_Int32 nPixelFontHeight );
+ void drawLayout( SalLayout& rLayout, const String& rText, bool bTextLines );
+ void drawRelief( SalLayout& rLayout, const String& rText, bool bTextLines );
+ void drawShadow( SalLayout& rLayout, const String& rText, bool bTextLines );
+
+ /* writes differences between graphics stack and current real PDF
+ * state to the file
+ */
+ void updateGraphicsState();
+
+ /* writes a transparency group object */
+ bool writeTransparentObject( TransparencyEmit& rObject );
+
+ /* writes an XObject of type image, may create
+ a second for the mask
+ */
+ bool writeBitmapObject( BitmapEmit& rObject, bool bMask = false );
+
+ bool writeJPG( JPGEmit& rEmit );
+
+ /* tries to find the bitmap by its id and returns its emit data if exists,
+ else creates a new emit data block */
+ const BitmapEmit& createBitmapEmit( const BitmapEx& rBitmapEx, bool bDrawMask = false );
+
+ /* writes the Do operation inside the content stream */
+ void drawBitmap( const Point& rDestPt, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor );
+ /* write the function object for a Gradient */
+ bool writeGradientFunction( GradientEmit& rObject );
+ /* creates a GradientEmit and returns its object number */
+ sal_Int32 createGradient( const Gradient& rGradient, const Size& rSize );
+
+ /* writes all tilings */
+ bool emitTilings();
+ /* writes all gradient patterns */
+ bool emitGradients();
+ /* writes a builtin font object and returns its objectid (or 0 in case of failure ) */
+ sal_Int32 emitBuiltinFont( const ImplFontData*, sal_Int32 nObject = -1 );
+ /* writes a type1 embedded font object and returns its mapping from font ids to object ids (or 0 in case of failure ) */
+ std::map< sal_Int32, sal_Int32 > emitEmbeddedFont( const ImplFontData*, EmbedFont& );
+ /* writes a type1 system font object and returns its mapping from font ids to object ids (or 0 in case of failure ) */
+ std::map< sal_Int32, sal_Int32 > emitSystemFont( const ImplFontData*, EmbedFont& );
+ /* writes a font descriptor and returns its object id (or 0) */
+ sal_Int32 emitFontDescriptor( const ImplFontData*, FontSubsetInfo&, sal_Int32 nSubsetID, sal_Int32 nStream );
+ /* writes a ToUnicode cmap, returns the corresponding stream object */
+ sal_Int32 createToUnicodeCMap( sal_uInt8* pEncoding, sal_Ucs* pUnicodes, sal_Int32* pUnicodesPerGlyph, sal_Int32* pEncToUnicodeIndex, int nGlyphs );
+
+ /* get resource dict object number */
+ sal_Int32 getResourceDictObj()
+ {
+ if( m_nResourceDict <= 0 )
+ m_nResourceDict = createObject();
+ return m_nResourceDict;
+ }
+ /* get the font dict object */
+ sal_Int32 getFontDictObject()
+ {
+ if( m_nFontDictObject <= 0 )
+ m_nFontDictObject = createObject();
+ return m_nFontDictObject;
+ }
+ /* push resource into current (redirected) resource dict */
+ void pushResource( ResourceKind eKind, const rtl::OString& rResource, sal_Int32 nObject );
+
+ void appendBuiltinFontsToDict( rtl::OStringBuffer& rDict ) const;
+ /* writes a the font dictionary and emits all font objects
+ * returns object id of font directory (or 0 on error)
+ */
+ bool emitFonts();
+ /* writes the Resource dictionary;
+ * returns dict object id (or 0 on error)
+ */
+ sal_Int32 emitResources();
+ // appends a dest
+ bool appendDest( sal_Int32 nDestID, rtl::OStringBuffer& rBuffer );
+ // write all links
+ bool emitLinkAnnotations();
+ // write all notes
+ bool emitNoteAnnotations();
+ // write the appearance streams of a widget
+ bool emitAppearances( PDFWidget& rWidget, rtl::OStringBuffer& rAnnotDict );
+ // clean up radio button "On" values
+ void ensureUniqueRadioOnValues();
+ // write all widgets
+ bool emitWidgetAnnotations();
+ // writes all annotation objects
+ bool emitAnnotations();
+ // writes the dest dict for the catalog
+ sal_Int32 emitDestDict();
+ //write the named destination stuff
+ sal_Int32 emitNamedDestinations();//i56629
+ // writes outline dict and tree
+ sal_Int32 emitOutline();
+ // puts the attribute objects of a structure element into the returned string,
+ // helper for emitStructure
+ rtl::OString emitStructureAttributes( PDFStructureElement& rEle );
+ //--->i94258
+ // the maximum array elements allowed for PDF array object
+ static const sal_uInt32 ncMaxPDFArraySize = 8191;
+ //check if internal dummy container are needed in the structure elements
+ void addInternalStructureContainer( PDFStructureElement& rEle );
+ //<---i94258
+ // writes document structure
+ sal_Int32 emitStructure( PDFStructureElement& rEle );
+ // writes structure parent tree
+ sal_Int32 emitStructParentTree( sal_Int32 nTreeObject );
+ // writes page tree and catalog
+ bool emitCatalog();
+ // writes xref and trailer
+ bool emitTrailer();
+ // emit additional streams collected; also create there object numbers
+ bool emitAdditionalStreams();
+ // emits info dict (if applicable)
+ sal_Int32 emitInfoDict( );
+
+ // acrobat reader 5 and 6 use the order of the annotations
+ // as their tab order; since PDF1.5 one can make the
+ // tab order explicit by using the structure tree
+ void sortWidgets();
+
+ // updates the count numbers of outline items
+ sal_Int32 updateOutlineItemCount( std::vector< sal_Int32 >& rCounts,
+ sal_Int32 nItemLevel,
+ sal_Int32 nCurrentItemId );
+ // default appearences for widgets
+ sal_Int32 findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rRadio );
+ Font replaceFont( const Font& rControlFont, const Font& rAppSetFont );
+ sal_Int32 getBestBuiltinFont( const Font& rFont );
+ sal_Int32 getSystemFont( const Font& i_rFont );
+
+ // used for edit and listbox
+ Font drawFieldBorder( PDFWidget&, const PDFWriter::AnyWidget&, const StyleSettings& );
+
+ void createDefaultPushButtonAppearance( PDFWidget&, const PDFWriter::PushButtonWidget& rWidget );
+ void createDefaultCheckBoxAppearance( PDFWidget&, const PDFWriter::CheckBoxWidget& rWidget );
+ void createDefaultRadioButtonAppearance( PDFWidget&, const PDFWriter::RadioButtonWidget& rWidget );
+ void createDefaultEditAppearance( PDFWidget&, const PDFWriter::EditWidget& rWidget );
+ void createDefaultListBoxAppearance( PDFWidget&, const PDFWriter::ListBoxWidget& rWidget );
+
+ /* ensure proper escapement and uniqueness of field names */
+ void createWidgetFieldName( sal_Int32 i_nWidgetsIndex, const PDFWriter::AnyWidget& i_rInWidget );
+ /* adds an entry to m_aObjects and returns its index+1,
+ * sets the offset to ~0
+ */
+ sal_Int32 createObject();
+ /* sets the offset of object n to the current position of output file+1
+ */
+ bool updateObject( sal_Int32 n );
+
+ bool writeBuffer( const void* pBuffer, sal_uInt64 nBytes );
+ void beginCompression();
+ void endCompression();
+ void beginRedirect( SvStream* pStream, const Rectangle& );
+ // returns an empty rect if no redirection is happending
+ Rectangle getRedirectTargetRect() const;
+ SvStream* endRedirect();
+
+ void endPage();
+
+ void beginStructureElementMCSeq();
+ void endStructureElementMCSeq();
+ /** checks whether a non struct element lies in the ancestor hierarchy
+ of the current structure element
+
+ @returns
+ <true/> if no NonStructElement was found in ancestor path and tagged
+ PDF output is enabled
+ <false/> else
+ */
+ bool checkEmitStructure();
+
+ /* draws an emphasis mark */
+ void drawEmphasisMark( long nX, long nY, const PolyPolygon& rPolyPoly, BOOL bPolyLine, const Rectangle& rRect1, const Rectangle& rRect2 );
+
+ /* true if PDF/A-1a or PDF/A-1b is output */
+ sal_Bool m_bIsPDF_A1;
+
+/*
+i12626
+methods for PDF security
+
+ pad a password according algorithm 3.2, step 1 */
+ void padPassword( const rtl::OUString aPassword, sal_uInt8 *paPasswordTarget );
+/* algorithm 3.2: compute an encryption key */
+ void computeEncryptionKey( sal_uInt8 *paThePaddedPassword, sal_uInt8 *paEncryptionKey );
+/* algorithm 3.3: computing the encryption dictionary'ss owner password value ( /O ) */
+ void computeODictionaryValue();
+/* algorithm 3.4 or 3.5: computing the encryption dictionary's user password value ( /U ) revision 2 or 3 of the standard security handler */
+ void computeUDictionaryValue();
+
+public:
+ PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext );
+ ~PDFWriterImpl();
+
+ /* for OutputDevice so the reference device can have a list
+ * that contains only suitable fonts (subsettable or builtin)
+ * produces a new font list
+ */
+ ImplDevFontList* filterDevFontList( ImplDevFontList* pFontList );
+ /* for OutputDevice: get layout for builtin fonts
+ */
+ bool isBuiltinFont( const ImplFontData* ) const;
+ SalLayout* GetTextLayout( ImplLayoutArgs& rArgs, ImplFontSelectData* pFont );
+ void getFontMetric( ImplFontSelectData* pFont, ImplFontMetricData* pMetric ) const;
+
+
+ /* for documentation of public functions please see pdfwriter.hxx */
+
+ OutputDevice* getReferenceDevice();
+
+ /* document structure */
+ sal_Int32 newPage( sal_Int32 nPageWidth , sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation );
+ bool emit();
+ std::set< PDFWriter::ErrorCode > getErrors();
+ void insertError( PDFWriter::ErrorCode eErr ) { m_aErrors.insert( eErr ); }
+
+ Size getCurPageSize() const
+ {
+ Size aSize;
+ if( m_nCurrentPage >= 0 && m_nCurrentPage < (sal_Int32)m_aPages.size() )
+ aSize = Size( m_aPages[ m_nCurrentPage ].m_nPageWidth, m_aPages[ m_nCurrentPage ].m_nPageHeight );
+ return aSize;
+ }
+
+ PDFWriter::PDFVersion getVersion() const { return m_aContext.Version; }
+ void setDocInfo( const PDFDocInfo& rInfo );
+ const PDFDocInfo& getDocInfo() const { return m_aDocInfo; }
+
+ void setDocumentLocale( const com::sun::star::lang::Locale& rLoc )
+ { m_aContext.DocumentLocale = rLoc; }
+
+
+ /* graphics state */
+ void push( sal_uInt16 nFlags );
+ void pop();
+
+ void setFont( const Font& rFont );
+
+ void setMapMode( const MapMode& rMapMode );
+ void setMapMode() { setMapMode( m_aMapMode ); }
+
+
+ const MapMode& getMapMode() { return m_aGraphicsStack.front().m_aMapMode; }
+
+ void setLineColor( const Color& rColor )
+ {
+ m_aGraphicsStack.front().m_aLineColor = ImplIsColorTransparent(rColor) ? Color( COL_TRANSPARENT ) : rColor;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateLineColor;
+ }
+
+ void setFillColor( const Color& rColor )
+ {
+ m_aGraphicsStack.front().m_aFillColor = ImplIsColorTransparent(rColor) ? Color( COL_TRANSPARENT ) : rColor;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFillColor;
+ }
+
+ void setTextLineColor()
+ {
+ m_aGraphicsStack.front().m_aTextLineColor = Color( COL_TRANSPARENT );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateTextLineColor;
+ }
+
+ void setTextLineColor( const Color& rColor )
+ {
+ m_aGraphicsStack.front().m_aTextLineColor = rColor;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateTextLineColor;
+ }
+
+ void setOverlineColor()
+ {
+ m_aGraphicsStack.front().m_aOverlineColor = Color( COL_TRANSPARENT );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateOverlineColor;
+ }
+
+ void setOverlineColor( const Color& rColor )
+ {
+ m_aGraphicsStack.front().m_aOverlineColor = rColor;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateOverlineColor;
+ }
+
+ void setTextFillColor( const Color& rColor )
+ {
+ m_aGraphicsStack.front().m_aFont.SetFillColor( rColor );
+ m_aGraphicsStack.front().m_aFont.SetTransparent( ImplIsColorTransparent( rColor ) ? TRUE : FALSE );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
+ }
+ void setTextFillColor()
+ {
+ m_aGraphicsStack.front().m_aFont.SetFillColor( Color( COL_TRANSPARENT ) );
+ m_aGraphicsStack.front().m_aFont.SetTransparent( TRUE );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
+ }
+ void setTextColor( const Color& rColor )
+ {
+ m_aGraphicsStack.front().m_aFont.SetColor( rColor );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
+ }
+
+ void clearClipRegion()
+ {
+ m_aGraphicsStack.front().m_aClipRegion.clear();
+ m_aGraphicsStack.front().m_bClipRegion = false;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
+ }
+
+ void setClipRegion( const basegfx::B2DPolyPolygon& rRegion );
+
+ void moveClipRegion( sal_Int32 nX, sal_Int32 nY );
+
+ bool intersectClipRegion( const Rectangle& rRect );
+
+ bool intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion );
+
+ void setLayoutMode( sal_Int32 nLayoutMode )
+ {
+ m_aGraphicsStack.front().m_nLayoutMode = nLayoutMode;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateLayoutMode;
+ }
+
+ void setDigitLanguage( LanguageType eLang )
+ {
+ m_aGraphicsStack.front().m_aDigitLanguage = eLang;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateDigitLanguage;
+ }
+
+ void setTextAlign( TextAlign eAlign )
+ {
+ m_aGraphicsStack.front().m_aFont.SetAlign( eAlign );
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
+ }
+
+ void setAntiAlias( sal_Int32 nAntiAlias )
+ {
+ m_aGraphicsStack.front().m_nAntiAlias = nAntiAlias;
+ m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateAntiAlias;
+ }
+
+ /* actual drawing functions */
+ void drawText( const Point& rPos, const String& rText, xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN, bool bTextLines = true );
+ void drawTextArray( const Point& rPos, const String& rText, const sal_Int32* pDXArray = NULL, xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN, bool bTextLines = true );
+ void drawStretchText( const Point& rPos, ULONG nWidth, const String& rText,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN,
+ bool bTextLines = true );
+ void drawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle, bool bTextLines = true );
+ void drawTextLine( const Point& rPos, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bUnderlineAbove );
+ void drawWaveTextLine( rtl::OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove );
+ void drawStraightTextLine( rtl::OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove );
+ void drawStrikeoutLine( rtl::OStringBuffer& aLine, long nWidth, FontStrikeout eStrikeout, Color aColor );
+ void drawStrikeoutChar( const Point& rPos, long nWidth, FontStrikeout eStrikeout );
+
+ void drawLine( const Point& rStart, const Point& rStop );
+ void drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo );
+ void drawPolygon( const Polygon& rPoly );
+ void drawPolyPolygon( const PolyPolygon& rPolyPoly );
+ void drawPolyLine( const Polygon& rPoly );
+ void drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo );
+ void drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo );
+ void drawWaveLine( const Point& rStart, const Point& rStop, sal_Int32 nDelta, sal_Int32 nLineWidth );
+
+ void drawPixel( const Point& rPt, const Color& rColor );
+ void drawPixel( const Polygon& rPts, const Color* pColors = NULL );
+
+ void drawRectangle( const Rectangle& rRect );
+ void drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound );
+ void drawEllipse( const Rectangle& rRect );
+ void drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWidthChord );
+
+ void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap );
+ void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap );
+ void drawMask( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Color& rFillColor );
+ void drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask );
+
+ void drawGradient( const Rectangle& rRect, const Gradient& rGradient );
+ void drawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient );
+ void drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch );
+ void drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall );
+ void drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent );
+ void beginTransparencyGroup();
+ void endTransparencyGroup( const Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent );
+ void endTransparencyGroup( const Rectangle& rBoundingBox, const Bitmap& rAlphaMask );
+ void beginPattern( const Rectangle& rCell );
+ sal_Int32 endPattern( const SvtGraphicFill::Transform& rTransform );
+ void drawPolyPolygon( const PolyPolygon& rPolyPoly, sal_Int32 nPattern, bool bEOFill );
+
+ void emitComment( const char* pComment );
+
+ //--->i56629 named destinations
+ sal_Int32 createNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr = -1, PDFWriter::DestAreaType eType = PDFWriter::XYZ );
+
+ //--->i59651
+ //emits output intent
+ sal_Int32 emitOutputIntent();
+
+ //emits the document metadata
+ sal_Int32 emitDocumentMetadata();
+
+ // links
+ sal_Int32 createLink( const Rectangle& rRect, sal_Int32 nPageNr = -1 );
+ sal_Int32 createDest( const Rectangle& rRect, sal_Int32 nPageNr = -1, PDFWriter::DestAreaType eType = PDFWriter::XYZ );
+ sal_Int32 setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId );
+ sal_Int32 setLinkURL( sal_Int32 nLinkId, const rtl::OUString& rURL );
+ void setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId );
+
+ // outline
+ sal_Int32 createOutlineItem( sal_Int32 nParent = 0, const rtl::OUString& rText = rtl::OUString(), sal_Int32 nDestID = -1 );
+ sal_Int32 setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent );
+ sal_Int32 setOutlineItemText( sal_Int32 nItem, const rtl::OUString& rText );
+ sal_Int32 setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID );
+
+ // notes
+ void createNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr = -1 );
+ // structure elements
+ sal_Int32 beginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias );
+ void endStructureElement();
+ bool setCurrentStructureElement( sal_Int32 nElement );
+ sal_Int32 getCurrentStructureElement();
+ bool setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal );
+ bool setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue );
+ void setStructureBoundingBox( const Rectangle& rRect );
+ void setActualText( const String& rText );
+ void setAlternateText( const String& rText );
+
+ // transitional effects
+ void setAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr = -1 );
+ void setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr = -1 );
+
+ // controls
+ sal_Int32 createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr = -1 );
+ void beginControlAppearance( sal_Int32 nControl );
+ bool endControlAppearance( PDFWriter::WidgetState eState );
+
+ // additional streams
+ void addStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress );
+
+ // helper: eventually begin marked content sequence and
+ // emit a comment in debug case
+ void MARK( const char*
+#if OSL_DEBUG_LEVEL > 1
+ pString
+#endif
+ )
+ {
+ beginStructureElementMCSeq();
+#if OSL_DEBUG_LEVEL > 1
+ emitComment( pString );
+#endif
+ }
+};
+
+}
+
+#endif //_VCL_PDFEXPORT_HXX
+
+
diff --git a/vcl/source/gdi/pngread.cxx b/vcl/source/gdi/pngread.cxx
new file mode 100644
index 000000000000..11971db34378
--- /dev/null
+++ b/vcl/source/gdi/pngread.cxx
@@ -0,0 +1,1579 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/pngread.hxx>
+
+#include <cmath>
+#include <rtl/crc.h>
+#include <rtl/memory.h>
+#include <rtl/alloc.h>
+#include <tools/zcodec.hxx>
+#include <tools/stream.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/alpha.hxx>
+#include <osl/endian.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define PNGCHUNK_IHDR 0x49484452
+#define PNGCHUNK_PLTE 0x504c5445
+#define PNGCHUNK_IDAT 0x49444154
+#define PNGCHUNK_IEND 0x49454e44
+#define PNGCHUNK_bKGD 0x624b4744
+#define PNGCHUNK_cHRM 0x6348524d
+#define PNGCHUNK_gAMA 0x67414d41
+#define PNGCHUNK_hIST 0x68495354
+#define PNGCHUNK_pHYs 0x70485973
+#define PNGCHUNK_sBIT 0x73425420
+#define PNGCHUNK_tIME 0x74494d45
+#define PNGCHUNK_tEXt 0x74455874
+#define PNGCHUNK_tRNS 0x74524e53
+#define PNGCHUNK_zTXt 0x7a545874
+#define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
+
+#define VIEWING_GAMMA 2.35
+#define DISPLAY_GAMMA 1.0
+
+namespace vcl
+{
+// -----------
+// - statics -
+// -----------
+
+// ------------------------------------------------------------------------------
+
+static const BYTE mpDefaultColorTable[ 256 ] =
+{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+// -------------
+// - PNGReaderImpl -
+// -------------
+
+class PNGReaderImpl
+{
+private:
+ SvStream& mrPNGStream;
+ sal_uInt16 mnOrigStreamMode;
+
+ std::vector< vcl::PNGReader::ChunkData > maChunkSeq;
+ std::vector< vcl::PNGReader::ChunkData >::iterator maChunkIter;
+ std::vector< sal_uInt8 >::iterator maDataIter;
+
+ Bitmap* mpBmp;
+ BitmapWriteAccess* mpAcc;
+ Bitmap* mpMaskBmp;
+ AlphaMask* mpAlphaMask;
+ BitmapWriteAccess* mpMaskAcc;
+ ZCodec* mpZCodec;
+ BYTE* mpInflateInBuf; // as big as the size of a scanline + alphachannel + 1
+ BYTE* mpScanPrior; // pointer to the latest scanline
+ BYTE* mpTransTab; // for transparency in images with palette colortype
+ BYTE* mpScanCurrent; // pointer into the current scanline
+ BYTE* mpColorTable; //
+ sal_Size mnStreamSize; // estimate of PNG file size
+ sal_uInt32 mnChunkType; // Type of current PNG chunk
+ sal_Int32 mnChunkLen; // Length of current PNG chunk
+ Size maOrigSize; // pixel size of the full image
+ Size maTargetSize; // pixel size of the result image
+ Size maPhysSize; // prefered size in MAP_100TH_MM units
+ sal_uInt32 mnBPP; // number of bytes per pixel
+ sal_uInt32 mnScansize; // max size of scanline
+ sal_uInt32 mnYpos; // latest y position in full image
+ int mnPass; // if interlaced the latest pass ( 1..7 ) else 7
+ sal_uInt32 mnXStart; // the starting X for the current pass
+ sal_uInt32 mnXAdd; // the increment for input images X coords for the current pass
+ sal_uInt32 mnYAdd; // the increment for input images Y coords for the current pass
+ int mnPreviewShift; // shift to convert orig image coords into preview image coords
+ int mnPreviewMask; // == ((1 << mnPreviewShift) - 1)
+ USHORT mnIStmOldMode;
+ USHORT mnTargetDepth; // pixel depth of target bitmap
+ BYTE mnTransRed;
+ BYTE mnTransGreen;
+ BYTE mnTransBlue;
+ BYTE mnPngDepth; // pixel depth of PNG data
+ BYTE mnColorType;
+ BYTE mnCompressionType;
+ BYTE mnFilterType;
+ BYTE mnInterlaceType;
+ BitmapColor mcTranspColor; // transparency mask's transparency "color"
+ BitmapColor mcOpaqueColor; // transparency mask's opaque "color"
+ BOOL mbTransparent; // graphic includes an tRNS Chunk or an alpha Channel
+ BOOL mbAlphaChannel; // is true for ColorType 4 and 6
+ BOOL mbRGBTriple;
+ BOOL mbPalette; // FALSE if we need a Palette
+ BOOL mbGrayScale;
+ BOOL mbzCodecInUse;
+ BOOL mbStatus;
+ BOOL mbIDAT; // TRUE if finished with enough IDAT chunks
+ BOOL mbGamma; // TRUE if Gamma Correction available
+ BOOL mbpHYs; // TRUE if pysical size of pixel available
+ sal_Bool mbIgnoreGammaChunk;
+
+ bool ReadNextChunk();
+ void ReadRemainingChunks();
+ void SkipRemainingChunks();
+
+ void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor & );
+ void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, BYTE nPalIndex );
+ void ImplSetTranspPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, BOOL bTrans );
+ void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, BYTE nPalIndex, BYTE nAlpha );
+ void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor&, BYTE nAlpha );
+ void ImplReadIDAT();
+ bool ImplPreparePass();
+ void ImplApplyFilter();
+ void ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd );
+ BOOL ImplReadTransparent();
+ void ImplGetGamma();
+ void ImplGetBackground();
+ BYTE ImplScaleColor();
+ BOOL ImplReadHeader( const Size& rPreviewSizeHint );
+ BOOL ImplReadPalette();
+ void ImplGetGrayPalette( sal_uInt16 );
+ sal_uInt32 ImplReadsal_uInt32();
+
+public:
+
+ PNGReaderImpl( SvStream& );
+ ~PNGReaderImpl();
+
+ BitmapEx GetBitmapEx( const Size& rPreviewSizeHint );
+ const std::vector< PNGReader::ChunkData >& GetAllChunks();
+ void SetIgnoreGammaChunk( sal_Bool bIgnore ){ mbIgnoreGammaChunk = bIgnore; };
+};
+
+// ------------------------------------------------------------------------------
+
+PNGReaderImpl::PNGReaderImpl( SvStream& rPNGStream )
+: mrPNGStream( rPNGStream ),
+ mpBmp ( NULL ),
+ mpAcc ( NULL ),
+ mpMaskBmp ( NULL ),
+ mpAlphaMask ( NULL ),
+ mpMaskAcc ( NULL ),
+ mpZCodec ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
+ mpInflateInBuf ( NULL ),
+ mpScanPrior ( NULL ),
+ mpTransTab ( NULL ),
+ mpColorTable ( (sal_uInt8*) mpDefaultColorTable ),
+ mbzCodecInUse ( sal_False ),
+ mbStatus( TRUE),
+ mbIDAT( FALSE ),
+ mbGamma ( sal_False ),
+ mbpHYs ( sal_False ),
+ mbIgnoreGammaChunk ( sal_False )
+{
+ // prepare the PNG data stream
+ mnOrigStreamMode = mrPNGStream.GetNumberFormatInt();
+ mrPNGStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
+
+ // prepare the chunk reader
+ maChunkSeq.reserve( 16 );
+ maChunkIter = maChunkSeq.begin();
+
+ // estimate PNG file size (to allow sanity checks)
+ const sal_Size nStreamPos = mrPNGStream.Tell();
+ mrPNGStream.Seek( STREAM_SEEK_TO_END );
+ mnStreamSize = mrPNGStream.Tell();
+ mrPNGStream.Seek( nStreamPos );
+
+ // check the PNG header magic
+ sal_uInt32 nDummy = 0;
+ mrPNGStream >> nDummy;
+ mbStatus = (nDummy == 0x89504e47);
+ mrPNGStream >> nDummy;
+ mbStatus &= (nDummy == 0x0d0a1a0a);
+
+ mnPreviewShift = 0;
+ mnPreviewMask = (1 << mnPreviewShift) - 1;
+}
+
+// ------------------------------------------------------------------------
+
+PNGReaderImpl::~PNGReaderImpl()
+{
+ mrPNGStream.SetNumberFormatInt( mnOrigStreamMode );
+
+ if ( mbzCodecInUse )
+ mpZCodec->EndCompression();
+
+ if( mpColorTable != mpDefaultColorTable )
+ delete[] mpColorTable;
+
+ delete mpBmp;
+ delete mpAlphaMask;
+ delete mpMaskBmp;
+ delete[] mpTransTab;
+ delete[] mpInflateInBuf;
+ delete[] mpScanPrior;
+ delete mpZCodec;
+}
+
+// ------------------------------------------------------------------------
+
+bool PNGReaderImpl::ReadNextChunk()
+{
+ if( maChunkIter == maChunkSeq.end() )
+ {
+ // get the next chunk from the stream
+
+ // unless we are at the end of the PNG stream
+ if( mrPNGStream.IsEof() || (mrPNGStream.GetError() != ERRCODE_NONE) )
+ return false;
+ if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
+ return false;
+
+ PNGReader::ChunkData aDummyChunk;
+ maChunkIter = maChunkSeq.insert( maChunkSeq.end(), aDummyChunk );
+ PNGReader::ChunkData& rChunkData = *maChunkIter;
+
+ // read the chunk header
+ mrPNGStream >> mnChunkLen >> mnChunkType;
+ rChunkData.nType = mnChunkType;
+
+ // #128377#/#149343# sanity check for chunk length
+ if( mnChunkLen < 0 )
+ return false;
+ const sal_Size nStreamPos = mrPNGStream.Tell();
+ if( nStreamPos + mnChunkLen >= mnStreamSize )
+ return false;
+
+ // calculate chunktype CRC (swap it back to original byte order)
+ sal_uInt32 nChunkType = mnChunkType;;
+ #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
+ nChunkType = SWAPLONG( nChunkType );
+ #endif
+ sal_uInt32 nCRC32 = rtl_crc32( 0, &nChunkType, 4 );
+
+ // read the chunk data and check the CRC
+ if( mnChunkLen && !mrPNGStream.IsEof() )
+ {
+ rChunkData.aData.resize( mnChunkLen );
+
+ sal_Int32 nBytesRead = 0;
+ do {
+ sal_uInt8* pPtr = &rChunkData.aData[ nBytesRead ];
+ nBytesRead += mrPNGStream.Read( pPtr, mnChunkLen - nBytesRead );
+ } while ( ( nBytesRead < mnChunkLen ) && ( mrPNGStream.GetError() == ERRCODE_NONE ) );
+
+ nCRC32 = rtl_crc32( nCRC32, &rChunkData.aData[ 0 ], mnChunkLen );
+ maDataIter = rChunkData.aData.begin();
+ }
+ sal_uInt32 nCheck;
+ mrPNGStream >> nCheck;
+ if( nCRC32 != nCheck )
+ return false;
+ }
+ else
+ {
+ // the next chunk was already read
+ mnChunkType = (*maChunkIter).nType;
+ mnChunkLen = (*maChunkIter).aData.size();
+ maDataIter = (*maChunkIter).aData.begin();
+ }
+
+ ++maChunkIter;
+ if( mnChunkType == PNGCHUNK_IEND )
+ return false;
+ return true;
+}
+
+// ------------------------------------------------------------------------
+
+// read the remaining chunks from mrPNGStream
+void PNGReaderImpl::ReadRemainingChunks()
+{
+ while( ReadNextChunk() ) ;
+}
+
+// ------------------------------------------------------------------------
+
+// move position of mrPNGStream to the end of the file
+void PNGReaderImpl::SkipRemainingChunks()
+{
+ // nothing to skip if the last chunk was read
+ if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
+ return;
+
+ // read from the stream until the IEND chunk is found
+ const sal_Size nStreamPos = mrPNGStream.Tell();
+ while( !mrPNGStream.IsEof() && (mrPNGStream.GetError() == ERRCODE_NONE) )
+ {
+ mrPNGStream >> mnChunkLen >> mnChunkType;
+ if( mnChunkLen < 0 )
+ break;
+ if( nStreamPos + mnChunkLen >= mnStreamSize )
+ break;
+ mrPNGStream.SeekRel( mnChunkLen + 4 ); // skip data + CRC
+ if( mnChunkType == PNGCHUNK_IEND )
+ break;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks()
+{
+ ReadRemainingChunks();
+ return maChunkSeq;
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx PNGReaderImpl::GetBitmapEx( const Size& rPreviewSizeHint )
+{
+ // reset to the first chunk
+ maChunkIter = maChunkSeq.begin();
+
+ // parse the chunks
+ while( mbStatus && !mbIDAT && ReadNextChunk() )
+ {
+ switch( mnChunkType )
+ {
+ case PNGCHUNK_IHDR :
+ {
+ mbStatus = ImplReadHeader( rPreviewSizeHint );
+ }
+ break;
+
+ case PNGCHUNK_gAMA : // the gamma chunk must precede
+ { // the 'IDAT' and also the 'PLTE'(if available )
+ if ( !mbIgnoreGammaChunk && ( mbIDAT == FALSE ) )
+ ImplGetGamma();
+ }
+ break;
+
+ case PNGCHUNK_PLTE :
+ {
+ if ( !mbPalette )
+ mbStatus = ImplReadPalette();
+ }
+ break;
+
+ case PNGCHUNK_tRNS :
+ {
+ if ( !mbIDAT ) // the tRNS chunk must precede the IDAT
+ mbStatus = ImplReadTransparent();
+ }
+ break;
+
+ case PNGCHUNK_bKGD : // the background chunk must appear
+ {
+ if ( ( mbIDAT == FALSE ) && mbPalette ) // before the 'IDAT' and after the
+ ImplGetBackground(); // PLTE(if available ) chunk.
+ }
+ break;
+
+ case PNGCHUNK_IDAT :
+ {
+ if ( !mbIDAT ) // the gfx is finished, but there may be left a zlibCRC of about 4Bytes
+ ImplReadIDAT();
+ }
+ break;
+
+ case PNGCHUNK_pHYs :
+ {
+ if ( !mbIDAT && mnChunkLen == 9 )
+ {
+ sal_uInt32 nXPixelPerMeter = ImplReadsal_uInt32();
+ sal_uInt32 nYPixelPerMeter = ImplReadsal_uInt32();
+
+ sal_uInt8 nUnitSpecifier = *maDataIter++;
+ if( (nUnitSpecifier == 1) && nXPixelPerMeter && nXPixelPerMeter )
+ {
+ mbpHYs = sal_True;
+
+ // convert into MAP_100TH_MM
+ maPhysSize.Width() = (sal_Int32)( (100000.0 * maOrigSize.Width()) / nXPixelPerMeter );
+ maPhysSize.Height() = (sal_Int32)( (100000.0 * maOrigSize.Height()) / nYPixelPerMeter );
+ }
+ }
+ }
+ break;
+
+ case PNGCHUNK_IEND:
+ mbStatus = mbIDAT; // there is a problem if the image is not complete yet
+ break;
+ }
+ }
+
+ // release write access of the bitmaps
+ if ( mpAcc )
+ mpBmp->ReleaseAccess( mpAcc ), mpAcc = NULL;
+
+ if ( mpMaskAcc )
+ {
+ if ( mpAlphaMask )
+ mpAlphaMask->ReleaseAccess( mpMaskAcc );
+ else if ( mpMaskBmp )
+ mpMaskBmp->ReleaseAccess( mpMaskAcc );
+
+ mpMaskAcc = NULL;
+ }
+
+ // return the resulting BitmapEx
+ BitmapEx aRet;
+
+ if( !mbStatus || !mbIDAT )
+ aRet.Clear();
+ else
+ {
+ if ( mpAlphaMask )
+ aRet = BitmapEx( *mpBmp, *mpAlphaMask );
+ else if ( mpMaskBmp )
+ aRet = BitmapEx( *mpBmp, *mpMaskBmp );
+ else
+ aRet = *mpBmp;
+
+ if ( mbpHYs && maPhysSize.Width() && maPhysSize.Height() )
+ {
+ aRet.SetPrefMapMode( MAP_100TH_MM );
+ aRet.SetPrefSize( maPhysSize );
+ }
+
+#if 0
+ // TODO: make sure nobody depends on the stream being after the IEND chunks
+ // => let them do ReadChunks before
+ ReadRemainingChunks();
+#endif
+ }
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL PNGReaderImpl::ImplReadHeader( const Size& rPreviewSizeHint )
+{
+ if( mnChunkLen < 13 )
+ return FALSE;
+
+ maOrigSize.Width() = ImplReadsal_uInt32();
+ maOrigSize.Height() = ImplReadsal_uInt32();
+
+ if ( !maOrigSize.Width() || !maOrigSize.Height() )
+ return FALSE;
+
+ mnPngDepth = *(maDataIter++);
+ mnColorType = *(maDataIter++);
+
+ mnCompressionType = *(maDataIter++);
+ if( mnCompressionType != 0 ) // unknown compression type
+ return FALSE;
+
+ mnFilterType = *(maDataIter++);
+ if( mnFilterType != 0 ) // unknown filter type
+ return FALSE;
+
+ mnInterlaceType = *(maDataIter++);
+ switch ( mnInterlaceType ) // filter type valid ?
+ {
+ case 0 : // progressive image
+ mnPass = 7;
+ break;
+ case 1 : // Adam7-interlaced image
+ mnPass = 0;
+ break;
+ default:
+ return FALSE;
+ }
+
+ mbPalette = TRUE;
+ mbIDAT = mbAlphaChannel = mbTransparent = FALSE;
+ mbGrayScale = mbRGBTriple = FALSE;
+ mnTargetDepth = mnPngDepth;
+ mnScansize = ( ( maOrigSize.Width() * mnPngDepth ) + 7 ) >> 3;
+
+ // valid color types are 0,2,3,4 & 6
+ switch ( mnColorType )
+ {
+ case 0 : // each pixel is a grayscale
+ {
+ switch ( mnPngDepth )
+ {
+ case 2 : // 2bit target not available -> use four bits
+ mnTargetDepth = 4; // we have to expand the bitmap
+ mbGrayScale = TRUE;
+ break;
+ case 16 :
+ mnTargetDepth = 8; // we have to reduce the bitmap
+ // fall through
+ case 1 :
+ case 4 :
+ case 8 :
+ mbGrayScale = TRUE;
+ break;
+ default :
+ return FALSE;
+ }
+ }
+ break;
+
+ case 2 : // each pixel is an RGB triple
+ {
+ mbRGBTriple = TRUE;
+ mnScansize *= 3;
+ switch ( mnPngDepth )
+ {
+ case 16 : // we have to reduce the bitmap
+ case 8 :
+ mnTargetDepth = 24;
+ break;
+ default :
+ return FALSE;
+ }
+ }
+ break;
+
+ case 3 : // each pixel is a palette index
+ {
+ switch ( mnPngDepth )
+ {
+ case 2 :
+ mnTargetDepth = 4; // we have to expand the bitmap
+ // fall through
+ case 1 :
+ case 4 :
+ case 8 :
+ mbPalette = FALSE;
+ break;
+ default :
+ return FALSE;
+ }
+ }
+ break;
+
+ case 4 : // each pixel is a grayscale sample followed by an alpha sample
+ {
+ mnScansize *= 2;
+ mbAlphaChannel = TRUE;
+ switch ( mnPngDepth )
+ {
+ case 16 :
+ mnTargetDepth = 8; // we have to reduce the bitmap
+ case 8 :
+ mbGrayScale = TRUE;
+ break;
+ default :
+ return FALSE;
+ }
+ }
+ break;
+
+ case 6 : // each pixel is an RGB triple followed by an alpha sample
+ {
+ mbRGBTriple = TRUE;
+ mnScansize *= 4;
+ mbAlphaChannel = TRUE;
+ switch (mnPngDepth )
+ {
+ case 16 : // we have to reduce the bitmap
+ case 8 :
+ mnTargetDepth = 24;
+ break;
+ default :
+ return FALSE;
+ }
+ }
+ break;
+
+ default :
+ return FALSE;
+ }
+
+ mnBPP = mnScansize / maOrigSize.Width();
+ if ( !mnBPP )
+ mnBPP = 1;
+
+ mnScansize++; // each scanline includes one filterbyte
+
+ // TODO: switch between both scanlines instead of copying
+ mpInflateInBuf = new BYTE[ mnScansize ];
+ mpScanCurrent = mpInflateInBuf;
+ mpScanPrior = new BYTE[ mnScansize ];
+
+ // calculate target size from original size and the preview hint
+ if( rPreviewSizeHint.Width() || rPreviewSizeHint.Height() )
+ {
+ Size aPreviewSize( rPreviewSizeHint.Width(), rPreviewSizeHint.Height() );
+ maTargetSize = maOrigSize;
+
+ if( aPreviewSize.Width() == 0 ) {
+ aPreviewSize.setWidth( ( maOrigSize.Width()*aPreviewSize.Height() )/maOrigSize.Height() );
+ if( aPreviewSize.Width() <= 0 )
+ aPreviewSize.setWidth( 1 );
+ } else if( aPreviewSize.Height() == 0 ) {
+ aPreviewSize.setHeight( ( maOrigSize.Height()*aPreviewSize.Width() )/maOrigSize.Width() );
+ if( aPreviewSize.Height() <= 0 )
+ aPreviewSize.setHeight( 1 );
+ }
+
+ if( aPreviewSize.Width() < maOrigSize.Width() && aPreviewSize.Height() < maOrigSize.Height() ) {
+ OSL_TRACE("preview size %dx%d", aPreviewSize.Width(), aPreviewSize.Height() );
+
+ for( int i = 1; i < 5; ++i )
+ {
+ if( (maTargetSize.Width() >> i) < aPreviewSize.Width() )
+ break;
+ if( (maTargetSize.Height() >> i) < aPreviewSize.Height() )
+ break;
+ mnPreviewShift = i;
+ }
+ mnPreviewMask = (1 << mnPreviewShift) - 1;
+ }
+ }
+
+ maTargetSize.Width() = (maOrigSize.Width() + mnPreviewMask) >> mnPreviewShift;
+ maTargetSize.Height() = (maOrigSize.Height() + mnPreviewMask) >> mnPreviewShift;
+
+ mpBmp = new Bitmap( maTargetSize, mnTargetDepth );
+ mpAcc = mpBmp->AcquireWriteAccess();
+ if( !mpAcc )
+ return FALSE;
+
+ mpBmp->SetSourceSizePixel( maOrigSize );
+
+ if ( mbAlphaChannel )
+ {
+ mpAlphaMask = new AlphaMask( maTargetSize );
+ mpAlphaMask->Erase( 128 );
+ mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
+ if( !mpMaskAcc )
+ return FALSE;
+ }
+
+ if ( mbGrayScale )
+ ImplGetGrayPalette( mnPngDepth );
+
+ ImplPreparePass();
+
+ return TRUE;
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
+{
+ if( nBitDepth > 8 )
+ nBitDepth = 8;
+
+ sal_uInt16 nPaletteEntryCount = 1 << nBitDepth;
+ sal_uInt32 nAdd = nBitDepth ? 256 / (nPaletteEntryCount - 1) : 0;
+
+ // no bitdepth==2 available
+ // but bitdepth==4 with two unused bits is close enough
+ if( nBitDepth == 2 )
+ nPaletteEntryCount = 16;
+
+ mpAcc->SetPaletteEntryCount( nPaletteEntryCount );
+ for ( sal_uInt32 i = 0, nStart = 0; nStart < 256; i++, nStart += nAdd )
+ mpAcc->SetPaletteColor( (USHORT)i, BitmapColor( mpColorTable[ nStart ],
+ mpColorTable[ nStart ], mpColorTable[ nStart ] ) );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL PNGReaderImpl::ImplReadPalette()
+{
+ sal_uInt16 nCount = static_cast<sal_uInt16>( mnChunkLen / 3 );
+
+ if ( ( ( mnChunkLen % 3 ) == 0 ) && ( ( 0 < nCount ) && ( nCount <= 256 ) ) && mpAcc )
+ {
+ mbPalette = TRUE;
+ mpAcc->SetPaletteEntryCount( (USHORT) nCount );
+
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ BYTE nRed = mpColorTable[ *maDataIter++ ];
+ BYTE nGreen = mpColorTable[ *maDataIter++ ];
+ BYTE nBlue = mpColorTable[ *maDataIter++ ];
+ mpAcc->SetPaletteColor( i, Color( nRed, nGreen, nBlue ) );
+ }
+ }
+ else
+ mbStatus = FALSE;
+
+ return mbStatus;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL PNGReaderImpl::ImplReadTransparent()
+{
+ bool bNeedAlpha = false;
+
+ if ( mpTransTab == NULL )
+ {
+ switch ( mnColorType )
+ {
+ case 0 :
+ {
+ if ( mnChunkLen == 2 )
+ {
+ mpTransTab = new sal_uInt8[ 256 ];
+ rtl_fillMemory( mpTransTab, 256, 0xff );
+ // color type 0 and 4 is always greyscale,
+ // so the return value can be used as index
+ sal_uInt8 nIndex = ImplScaleColor();
+ mpTransTab[ nIndex ] = 0;
+ mbTransparent = true;
+ }
+ }
+ break;
+
+ case 2 :
+ {
+ if ( mnChunkLen == 6 )
+ {
+ mnTransRed = ImplScaleColor();
+ mnTransGreen = ImplScaleColor();
+ mnTransBlue = ImplScaleColor();
+ mbTransparent = true;
+ }
+ }
+ break;
+
+ case 3 :
+ {
+ if ( mnChunkLen <= 256 )
+ {
+ mpTransTab = new BYTE [ 256 ];
+ rtl_fillMemory( mpTransTab, 256, 0xff );
+ rtl_copyMemory( mpTransTab, &(*maDataIter), mnChunkLen );
+ maDataIter += mnChunkLen;
+ mbTransparent = true;
+ // need alpha transparency if not on/off masking
+ for( int i = 0; i < mnChunkLen; ++i )
+ bNeedAlpha |= (mpTransTab[i]!=0x00) && (mpTransTab[i]!=0xFF);
+ }
+ }
+ break;
+ }
+ }
+
+ if( mbTransparent && !mbAlphaChannel && !mpMaskBmp )
+ {
+ if( bNeedAlpha)
+ {
+ mpAlphaMask = new AlphaMask( maTargetSize );
+ mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
+ }
+ else
+ {
+ mpMaskBmp = new Bitmap( maTargetSize, 1 );
+ mpMaskAcc = mpMaskBmp->AcquireWriteAccess();
+ }
+ mbTransparent = (mpMaskAcc != NULL);
+ if( !mbTransparent )
+ return FALSE;
+ mcOpaqueColor = BitmapColor( 0x00 );
+ mcTranspColor = BitmapColor( 0xFF );
+ mpMaskAcc->Erase( 0x00 );
+ }
+
+ return TRUE;
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplGetGamma()
+{
+ if( mnChunkLen < 4 )
+ return;
+
+ sal_uInt32 nGammaValue = ImplReadsal_uInt32();
+ double fGamma = ( ( VIEWING_GAMMA / DISPLAY_GAMMA ) * ( (double)nGammaValue / 100000 ) );
+ double fInvGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
+
+ if ( fInvGamma != 1.0 )
+ {
+ mbGamma = TRUE;
+
+ if ( mpColorTable == mpDefaultColorTable )
+ mpColorTable = new sal_uInt8[ 256 ];
+
+ for ( sal_Int32 i = 0; i < 256; i++ )
+ mpColorTable[ i ] = (sal_uInt8)(pow((double)i/255.0, fInvGamma) * 255.0 + 0.5);
+
+ if ( mbGrayScale )
+ ImplGetGrayPalette( mnPngDepth );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplGetBackground()
+{
+ switch ( mnColorType )
+ {
+ case 3 :
+ {
+ if ( mnChunkLen == 1 )
+ {
+ UINT16 nCol = *maDataIter++;
+ if ( nCol < mpAcc->GetPaletteEntryCount() )
+ {
+ mpAcc->Erase( mpAcc->GetPaletteColor( (BYTE)nCol ) );
+ break;
+ }
+ }
+ }
+ break;
+
+ case 0 :
+ case 4 :
+ {
+ if ( mnChunkLen == 2 )
+ {
+ // the color type 0 and 4 is always greyscale,
+ // so the return value can be used as index
+ sal_uInt8 nIndex = ImplScaleColor();
+ mpAcc->Erase( mpAcc->GetPaletteColor( nIndex ) );
+ }
+ }
+ break;
+
+ case 2 :
+ case 6 :
+ {
+ if ( mnChunkLen == 6 )
+ {
+ sal_uInt8 nRed = ImplScaleColor();
+ sal_uInt8 nGreen = ImplScaleColor();
+ sal_uInt8 nBlue = ImplScaleColor();
+ mpAcc->Erase( Color( nRed, nGreen, nBlue ) );
+ }
+ }
+ break;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+// for color type 0 and 4 (greyscale) the return value is always index to the color
+// 2 and 6 (RGB) the return value is always the 8 bit color component
+sal_uInt8 PNGReaderImpl::ImplScaleColor()
+{
+ sal_uInt32 nMask = ( ( 1 << mnPngDepth ) - 1 );
+ sal_uInt16 nCol = ( *maDataIter++ << 8 );
+
+ nCol += *maDataIter++ & (sal_uInt16)nMask;
+
+ if ( mnPngDepth > 8 ) // convert 16bit graphics to 8
+ nCol >>= 8;
+
+ return (sal_uInt8) nCol;
+}
+
+// ------------------------------------------------------------------------
+// ImplReadIDAT reads as much image data as needed
+
+void PNGReaderImpl::ImplReadIDAT()
+{
+ if( mnChunkLen > 0 )
+ {
+ if ( mbzCodecInUse == FALSE )
+ {
+ mbzCodecInUse = TRUE;
+ mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT );
+ }
+ mpZCodec->SetBreak( mnChunkLen );
+ SvMemoryStream aIStrm( &(*maDataIter), mnChunkLen, STREAM_READ );
+
+ while ( ( mpZCodec->GetBreak() ) )
+ {
+ // get bytes needed to fill the current scanline
+ sal_Int32 nToRead = mnScansize - (mpScanCurrent - mpInflateInBuf);
+ sal_Int32 nRead = mpZCodec->ReadAsynchron( aIStrm, mpScanCurrent, nToRead );
+ if ( nRead < 0 )
+ {
+ mbStatus = FALSE;
+ break;
+ }
+ if ( nRead < nToRead )
+ {
+ mpScanCurrent += nRead; // more ZStream data in the next IDAT chunk
+ break;
+ }
+ else // this scanline is Finished
+ {
+ mpScanCurrent = mpInflateInBuf;
+ ImplApplyFilter();
+
+ ImplDrawScanline( mnXStart, mnXAdd );
+ mnYpos += mnYAdd;
+ }
+
+ if ( mnYpos >= (sal_uInt32)maOrigSize.Height() )
+ {
+ if( (mnPass < 7) && mnInterlaceType )
+ if( ImplPreparePass() )
+ continue;
+ mbIDAT = true;
+ break;
+ }
+ }
+ }
+
+ if( mbIDAT )
+ {
+ mpZCodec->EndCompression();
+ mbzCodecInUse = FALSE;
+ }
+}
+
+// ---------------------------------------------------------------------------------------------------
+
+bool PNGReaderImpl::ImplPreparePass()
+{
+ struct InterlaceParams{ int mnXStart, mnYStart, mnXAdd, mnYAdd; };
+ static const InterlaceParams aInterlaceParams[8] =
+ {
+ // non-interlaced
+ { 0, 0, 1, 1 },
+ // Adam7-interlaced
+ { 0, 0, 8, 8 }, // pass 1
+ { 4, 0, 8, 8 }, // pass 2
+ { 0, 4, 4, 8 }, // pass 3
+ { 2, 0, 4, 4 }, // pass 4
+ { 0, 2, 2, 4 }, // pass 5
+ { 1, 0, 2, 2 }, // pass 6
+ { 0, 1, 1, 2 } // pass 7
+ };
+
+ const InterlaceParams* pParam = &aInterlaceParams[ 0 ];
+ if( mnInterlaceType )
+ {
+ while( ++mnPass <= 7 )
+ {
+ pParam = &aInterlaceParams[ mnPass ];
+
+ // skip this pass if the original image is too small for it
+ if( (pParam->mnXStart < maOrigSize.Width())
+ && (pParam->mnYStart < maOrigSize.Height()) )
+ break;
+ }
+ if( mnPass > 7 )
+ return false;
+
+ // skip the last passes if possible (for scaled down target images)
+ if( mnPreviewMask & (pParam->mnXStart | pParam->mnYStart) )
+ return false;
+ }
+
+ mnYpos = pParam->mnYStart;
+ mnXStart = pParam->mnXStart;
+ mnXAdd = pParam->mnXAdd;
+ mnYAdd = pParam->mnYAdd;
+
+ // in Interlace mode the size of scanline is not constant
+ // so first we calculate the number of entrys
+ long nScanWidth = (maOrigSize.Width() - mnXStart + mnXAdd - 1) / mnXAdd;
+ mnScansize = nScanWidth;
+
+ if( mbRGBTriple )
+ mnScansize = 3 * nScanWidth;
+
+ if( mbAlphaChannel )
+ mnScansize += nScanWidth;
+
+ // convert to width in bytes
+ mnScansize = ( mnScansize*mnPngDepth + 7 ) >> 3;
+
+ ++mnScansize; // scan size also needs room for the filtertype byte
+ rtl_zeroMemory( mpScanPrior, mnScansize );
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// ImplApplyFilter writes the complete Scanline (nY)
+// in interlace mode the parameter nXStart and nXAdd are non-zero
+
+void PNGReaderImpl::ImplApplyFilter()
+{
+ OSL_ASSERT( mnScansize >= mnBPP + 1 );
+ const BYTE* const pScanEnd = mpInflateInBuf + mnScansize;
+
+ BYTE nFilterType = *mpInflateInBuf; // the filter type may change each scanline
+ switch ( nFilterType )
+ {
+ default: // unknown Scanline Filter Type
+ case 0: // Filter Type "None"
+ // we let the pixels pass and display the data unfiltered
+ break;
+
+ case 1: // Scanline Filter Type "Sub"
+ {
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = p1;
+ p1 += mnBPP;
+
+ // use left pixels
+ do
+ *p1 = static_cast<BYTE>( *p1 + *(p2++) );
+ while( ++p1 < pScanEnd );
+ }
+ break;
+
+ case 2: // Scanline Filter Type "Up"
+ {
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = mpScanPrior + 1;
+
+ // use pixels from prior line
+ while( p1 < pScanEnd )
+ {
+ *p1 = static_cast<BYTE>( *p1 + *(p2++) );
+ ++p1;
+ }
+ }
+ break;
+
+ case 3: // Scanline Filter Type "Average"
+ {
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = mpScanPrior + 1;
+ const BYTE* p3 = p1;
+
+ // use one pixel from prior line
+ for( int n = mnBPP; --n >= 0; ++p1, ++p2)
+ *p1 = static_cast<BYTE>( *p1 + (*p2 >> 1) );
+
+ // predict by averaging the left and prior line pixels
+ while( p1 < pScanEnd )
+ {
+ *p1 = static_cast<BYTE>( *p1 + ((*(p2++) + *(p3++)) >> 1) );
+ ++p1;
+ }
+ }
+ break;
+
+ case 4: // Scanline Filter Type "PaethPredictor"
+ {
+ BYTE* p1 = mpInflateInBuf + 1;
+ const BYTE* p2 = mpScanPrior + 1;
+ const BYTE* p3 = p1;
+ const BYTE* p4 = p2;
+
+ // use one pixel from prior line
+ for( int n = mnBPP; --n >= 0; ++p1)
+ *p1 = static_cast<BYTE>( *p1 + *(p2++) );
+
+ // predict by using the left and the prior line pixels
+ while( p1 < pScanEnd )
+ {
+ int na = *(p2++);
+ int nb = *(p3++);
+ int nc = *(p4++);
+
+ int npa = nb - (int)nc;
+ int npb = na - (int)nc;
+ int npc = npa + npb;
+
+ if( npa < 0 )
+ npa =-npa;
+ if( npb < 0 )
+ npb =-npb;
+ if( npc < 0 )
+ npc =-npc;
+
+ if( npa > npb )
+ na = nb, npa = npb;
+ if( npa > npc )
+ na = nc;
+
+ *p1 = static_cast<BYTE>( *p1 + na );
+ ++p1;
+ }
+ }
+ break;
+ }
+
+ rtl_copyMemory( mpScanPrior, mpInflateInBuf, mnScansize );
+}
+
+// ---------------------------------------------------------------------------------------------------
+// ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
+// In interlace mode the parameter nXStart and nXAdd append to the currently used pass
+
+void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd )
+{
+ // optimization for downscaling
+ if( mnYpos & mnPreviewMask )
+ return;
+ if( nXStart & mnPreviewMask )
+ return;
+
+ // convert nY to pixel units in the target image
+ // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
+ const sal_uInt32 nY = mnYpos >> mnPreviewShift;
+
+ const BYTE* pTmp = mpInflateInBuf + 1;
+ if ( mpAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
+ {
+ switch ( mpAcc->GetBitCount() )
+ {
+ case 1 :
+ {
+ if ( mbTransparent )
+ {
+ for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
+ {
+ BYTE nCol;
+ nShift = (nShift - 1) & 7;
+ if ( nShift == 0 )
+ nCol = *(pTmp++);
+ else
+ nCol = static_cast<BYTE>( *pTmp >> nShift );
+ nCol &= 1;
+
+ ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
+ }
+ }
+ else
+ { // BMP_FORMAT_1BIT_MSB_PAL
+ for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
+ {
+ nShift = (nShift - 1) & 7;
+
+ BYTE nCol;
+ if ( nShift == 0 )
+ nCol = *(pTmp++);
+ else
+ nCol = static_cast<BYTE>( *pTmp >> nShift );
+ nCol &= 1;
+
+ ImplSetPixel( nY, nX, nCol );
+ }
+ }
+ }
+ break;
+
+ case 4 :
+ {
+ if ( mbTransparent )
+ {
+ if ( mnPngDepth == 4 ) // check if source has a two bit pixel format
+ {
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, ++nXIndex )
+ {
+ if( nXIndex & 1 )
+ {
+ ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
+ pTmp++;
+ }
+ else
+ {
+ ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
+ }
+ }
+ }
+ else // if ( mnPngDepth == 2 )
+ {
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
+ {
+ BYTE nCol;
+ switch( nXIndex & 3 )
+ {
+ case 0 :
+ nCol = *pTmp >> 6;
+ break;
+
+ case 1 :
+ nCol = ( *pTmp >> 4 ) & 0x03 ;
+ break;
+
+ case 2 :
+ nCol = ( *pTmp >> 2 ) & 0x03;
+ break;
+
+ case 3 :
+ nCol = ( *pTmp++ ) & 0x03;
+ break;
+
+ default: // get rid of nCol uninitialized warning
+ nCol = 0;
+ break;
+ }
+
+ ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
+ }
+ }
+ }
+ else
+ {
+ if ( mnPngDepth == 4 ) // maybe the source is a two bitmap graphic
+ { // BMP_FORMAT_4BIT_LSN_PAL
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
+ {
+ if( nXIndex & 1 )
+ ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
+ else
+ ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
+ }
+ }
+ else // if ( mnPngDepth == 2 )
+ {
+ for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
+ {
+ switch( nXIndex & 3 )
+ {
+ case 0 :
+ ImplSetPixel( nY, nX, *pTmp >> 6 );
+ break;
+
+ case 1 :
+ ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
+ break;
+
+ case 2 :
+ ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
+ break;
+
+ case 3 :
+ ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case 8 :
+ {
+ if ( mbAlphaChannel )
+ {
+ if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
+ ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
+ }
+ else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
+ ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
+ }
+ }
+ else if ( mbTransparent )
+ {
+ if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp++ )
+ ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
+ }
+ else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
+ ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
+ }
+ }
+ else // neither alpha nor transparency
+ {
+ if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
+ {
+ if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
+ {
+ int nLineBytes = maOrigSize.Width();
+ mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_8BIT_PAL, nLineBytes );
+ pTmp += nLineBytes;
+ }
+ else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd )
+ ImplSetPixel( nY, nX, *pTmp++ );
+ }
+ }
+ else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
+ ImplSetPixel( nY, nX, *pTmp );
+ }
+ }
+ }
+ break;
+
+ default :
+ mbStatus = FALSE;
+ break;
+ }
+ }
+ else // no palette => truecolor
+ {
+ if( mbAlphaChannel ) // has RGB + alpha
+ { // BMP_FORMAT_32BIT_TC_RGBA
+ if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
+ {
+ if ( mpColorTable != mpDefaultColorTable )
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
+ ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 1 ] ],
+ mpColorTable[ pTmp[ 2 ] ] ), pTmp[ 3 ] );
+ }
+ else
+ {
+// if ( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
+// {
+// int nLineBytes = 4 * maOrigSize.Width();
+// mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_32BIT_TC_RGBA, nLineBytes );
+// pTmp += nLineBytes;
+// }
+// else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
+ ImplSetAlphaPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ), pTmp[3] );
+ }
+ }
+ }
+ else
+ { // BMP_FORMAT_64BIT_TC_RGBA
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 8 )
+ ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 2 ] ],
+ mpColorTable[ pTmp[ 4 ] ] ), pTmp[6] );
+ }
+ }
+ else if( mbTransparent ) // has RGB + transparency
+ { // BMP_FORMAT_24BIT_TC_RGB
+ if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
+ {
+ sal_uInt8 nRed = pTmp[ 0 ];
+ sal_uInt8 nGreen = pTmp[ 1 ];
+ sal_uInt8 nBlue = pTmp[ 2 ];
+ sal_Bool bTransparent = ( ( nRed == mnTransRed )
+ && ( nGreen == mnTransGreen )
+ && ( nBlue == mnTransBlue ) );
+
+ ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
+ mpColorTable[ nGreen ],
+ mpColorTable[ nBlue ] ), bTransparent );
+ }
+ }
+ else
+ { // BMP_FORMAT_48BIT_TC_RGB
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
+ {
+ sal_uInt8 nRed = pTmp[ 0 ];
+ sal_uInt8 nGreen = pTmp[ 2 ];
+ sal_uInt8 nBlue = pTmp[ 4 ];
+ sal_Bool bTransparent = ( ( nRed == mnTransRed )
+ && ( nGreen == mnTransGreen )
+ && ( nBlue == mnTransBlue ) );
+
+ ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
+ mpColorTable[ nGreen ],
+ mpColorTable[ nBlue ] ), bTransparent );
+ }
+ }
+ }
+ else // has RGB but neither alpha nor transparency
+ { // BMP_FORMAT_24BIT_TC_RGB
+ if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
+ {
+ if ( mpColorTable != mpDefaultColorTable )
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
+ ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 1 ] ],
+ mpColorTable[ pTmp[ 2 ] ] ) );
+ }
+ else
+ {
+ if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
+ {
+ int nLineBytes = maOrigSize.Width() * 3;
+ mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_24BIT_TC_RGB, nLineBytes );
+ pTmp += nLineBytes;
+ }
+ else
+ {
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
+ ImplSetPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ) );
+ }
+ }
+ }
+ else
+ { // BMP_FORMAT_48BIT_TC_RGB
+ for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
+ ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
+ mpColorTable[ pTmp[ 2 ] ],
+ mpColorTable[ pTmp[ 4 ] ] ) );
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
+{
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
+
+ mpAcc->SetPixel( nY, nX, rBitmapColor );
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, BYTE nPalIndex )
+{
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
+
+ mpAcc->SetPixel( nY, nX, nPalIndex );
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, BOOL bTrans )
+{
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
+
+ mpAcc->SetPixel( nY, nX, rBitmapColor );
+
+ if ( bTrans )
+ mpMaskAcc->SetPixel( nY, nX, mcTranspColor );
+ else
+ mpMaskAcc->SetPixel( nY, nX, mcOpaqueColor );
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
+ BYTE nPalIndex, BYTE nAlpha )
+{
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
+
+ mpAcc->SetPixel( nY, nX, nPalIndex );
+ mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
+ const BitmapColor& rBitmapColor, BYTE nAlpha )
+{
+ // TODO: get preview mode checks out of inner loop
+ if( nX & mnPreviewMask )
+ return;
+ nX >>= mnPreviewShift;
+
+ mpAcc->SetPixel( nY, nX, rBitmapColor );
+ mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
+}
+
+// ------------------------------------------------------------------------
+
+sal_uInt32 PNGReaderImpl::ImplReadsal_uInt32()
+{
+ sal_uInt32 nRet;
+ nRet = *maDataIter++;
+ nRet <<= 8;
+ nRet |= *maDataIter++;
+ nRet <<= 8;
+ nRet |= *maDataIter++;
+ nRet <<= 8;
+ nRet |= *maDataIter++;
+ return nRet;
+}
+
+// ------------------------------------------------------------------------
+
+// -------------
+// - PNGReader -
+// -------------
+
+PNGReader::PNGReader( SvStream& rIStm ) :
+ mpImpl( new ::vcl::PNGReaderImpl( rIStm ) )
+{
+}
+
+// ------------------------------------------------------------------------
+
+PNGReader::~PNGReader()
+{
+ delete mpImpl;
+}
+
+// ------------------------------------------------------------------------
+
+BitmapEx PNGReader::Read( const Size& i_rPreviewSizeHint )
+{
+ return mpImpl->GetBitmapEx( i_rPreviewSizeHint );
+}
+
+// ------------------------------------------------------------------------
+
+const std::vector< vcl::PNGReader::ChunkData >& PNGReader::GetChunks() const
+{
+ return mpImpl->GetAllChunks();
+}
+
+// ------------------------------------------------------------------------
+
+void PNGReader::SetIgnoreGammaChunk( sal_Bool b )
+{
+ mpImpl->SetIgnoreGammaChunk( b );
+}
+
+
+} // namespace vcl
diff --git a/vcl/source/gdi/pngwrite.cxx b/vcl/source/gdi/pngwrite.cxx
new file mode 100644
index 000000000000..47152ea6ac11
--- /dev/null
+++ b/vcl/source/gdi/pngwrite.cxx
@@ -0,0 +1,737 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/pngwrite.hxx>
+
+#include <cmath>
+#include <limits>
+#include <rtl/crc.h>
+#include <rtl/memory.h>
+#include <rtl/alloc.h>
+#include <tools/zcodec.hxx>
+#include <tools/stream.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/alpha.hxx>
+#include <osl/endian.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define PNG_DEF_COMPRESSION 6
+
+#define PNGCHUNK_IHDR 0x49484452
+#define PNGCHUNK_PLTE 0x504c5445
+#define PNGCHUNK_IDAT 0x49444154
+#define PNGCHUNK_IEND 0x49454e44
+#define PNGCHUNK_bKGD 0x624b4744
+#define PNGCHUNK_cHRM 0x6348524d
+#define PNGCHUNK_gAMA 0x67414d41
+#define PNGCHUNK_hIST 0x68495354
+#define PNGCHUNK_pHYs 0x70485973
+#define PNGCHUNK_sBIT 0x73425420
+#define PNGCHUNK_tIME 0x74494d45
+#define PNGCHUNK_tEXt 0x74455874
+#define PNGCHUNK_tRNS 0x74524e53
+#define PNGCHUNK_zTXt 0x7a545874
+
+namespace vcl
+{
+// -----------------
+// - PNGWriterImplImpl -
+// -----------------
+
+class PNGWriterImpl
+{
+public:
+
+ PNGWriterImpl( const BitmapEx& BmpEx,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL );
+ ~PNGWriterImpl();
+
+ sal_Bool Write( SvStream& rOStm );
+
+ std::vector< vcl::PNGWriter::ChunkData >& GetChunks();
+
+private:
+
+ std::vector< vcl::PNGWriter::ChunkData > maChunkSeq;
+
+ sal_Int32 mnCompLevel;
+ sal_Int32 mnInterlaced;
+ sal_uInt32 mnMaxChunkSize;
+ BOOL mbStatus;
+
+ BitmapReadAccess* mpAccess;
+ BitmapReadAccess* mpMaskAccess;
+ ZCodec* mpZCodec;
+
+ BYTE* mpDeflateInBuf; // as big as the size of a scanline + alphachannel + 1
+ BYTE* mpPreviousScan; // as big as mpDeflateInBuf
+ BYTE* mpCurrentScan;
+ ULONG mnDeflateInSize;
+
+ ULONG mnWidth, mnHeight;
+ BYTE mnBitsPerPixel;
+ BYTE mnFilterType; // 0 oder 4;
+ ULONG mnBBP; // bytes per pixel ( needed for filtering )
+ BOOL mbTrueAlpha;
+ ULONG mnCRC;
+ long mnChunkDatSize;
+ ULONG mnLastPercent;
+
+ void ImplWritepHYs( const BitmapEx& rBitmapEx );
+ void ImplWriteIDAT();
+ ULONG ImplGetFilter( ULONG nY, ULONG nXStart=0, ULONG nXAdd=1 );
+ void ImplClearFirstScanline();
+ void ImplWriteTransparent();
+ BOOL ImplWriteHeader();
+ void ImplWritePalette();
+ void ImplOpenChunk( ULONG nChunkType );
+ void ImplWriteChunk( BYTE nNumb );
+ void ImplWriteChunk( sal_uInt32 nNumb );
+ void ImplWriteChunk( unsigned char* pSource, sal_uInt32 nDatSize );
+ void ImplCloseChunk( void );
+};
+
+// ------------------------------------------------------------------------
+
+PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
+ mnCompLevel ( PNG_DEF_COMPRESSION ),
+ mbStatus ( TRUE ),
+ mpAccess ( NULL ),
+ mpMaskAccess ( NULL ),
+ mpZCodec ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
+ mnCRC(0UL),
+ mnLastPercent ( 0UL )
+{
+ if ( !rBmpEx.IsEmpty() )
+ {
+ Bitmap aBmp( rBmpEx.GetBitmap() );
+
+ mnInterlaced = 0; // ( aBmp.GetSizePixel().Width() > 128 ) || ( aBmp.GetSizePixel().Height() > 128 ) ? 1 : 0; #i67236#
+
+ // #i67234# defaulting max chunk size to 256kb when using interlace mode
+ mnMaxChunkSize = mnInterlaced == 0 ? std::numeric_limits< sal_uInt32 >::max() : 0x40000;
+
+ if ( pFilterData )
+ {
+ sal_Int32 i = 0;
+ for ( i = 0; i < pFilterData->getLength(); i++ )
+ {
+ if ( (*pFilterData)[ i ].Name.equalsAscii( "Compression" ) )
+ (*pFilterData)[ i ].Value >>= mnCompLevel;
+ else if ( (*pFilterData)[ i ].Name.equalsAscii( "Interlaced" ) )
+ (*pFilterData)[ i ].Value >>= mnInterlaced;
+ else if ( (*pFilterData)[ i ].Name.equalsAscii( "MaxChunkSize" ) )
+ {
+ sal_Int32 nVal = 0;
+ if ( (*pFilterData)[ i ].Value >>= nVal )
+ mnMaxChunkSize = (sal_uInt32)nVal;
+ }
+ }
+ }
+ mnBitsPerPixel = (BYTE)aBmp.GetBitCount();
+
+ if( rBmpEx.IsTransparent() )
+ {
+ if ( mnBitsPerPixel <= 8 && rBmpEx.IsAlpha() )
+ {
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+ mnBitsPerPixel = 24;
+ }
+
+ if ( mnBitsPerPixel <= 8 ) // transparent palette
+ {
+ aBmp.Convert( BMP_CONVERSION_8BIT_TRANS );
+ aBmp.Replace( rBmpEx.GetMask(), BMP_COL_TRANS );
+ mnBitsPerPixel = 8;
+ mpAccess = aBmp.AcquireReadAccess();
+ if ( mpAccess )
+ {
+ if ( ImplWriteHeader() )
+ {
+ ImplWritepHYs( rBmpEx );
+ ImplWritePalette();
+ ImplWriteTransparent();
+ ImplWriteIDAT();
+ }
+ aBmp.ReleaseAccess( mpAccess );
+ }
+ else
+ mbStatus = FALSE;
+ }
+ else
+ {
+ mpAccess = aBmp.AcquireReadAccess(); // TRUE RGB with alphachannel
+ if( mpAccess )
+ {
+ if ( ( mbTrueAlpha = rBmpEx.IsAlpha() ) != FALSE )
+ {
+ AlphaMask aMask( rBmpEx.GetAlpha() );
+ mpMaskAccess = aMask.AcquireReadAccess();
+ if ( mpMaskAccess )
+ {
+ if ( ImplWriteHeader() )
+ {
+ ImplWritepHYs( rBmpEx );
+ ImplWriteIDAT();
+ }
+ aMask.ReleaseAccess( mpMaskAccess );
+ }
+ else
+ mbStatus = FALSE;
+ }
+ else
+ {
+ Bitmap aMask( rBmpEx.GetMask() );
+ mpMaskAccess = aMask.AcquireReadAccess();
+ if( mpMaskAccess )
+ {
+ if ( ImplWriteHeader() )
+ {
+ ImplWritepHYs( rBmpEx );
+ ImplWriteIDAT();
+ }
+ aMask.ReleaseAccess( mpMaskAccess );
+ }
+ else
+ mbStatus = FALSE;
+ }
+ aBmp.ReleaseAccess( mpAccess );
+ }
+ else
+ mbStatus = FALSE;
+ }
+ }
+ else
+ {
+ mpAccess = aBmp.AcquireReadAccess(); // palette + RGB without alphachannel
+ if( mpAccess )
+ {
+ if ( ImplWriteHeader() )
+ {
+ ImplWritepHYs( rBmpEx );
+ if( mpAccess->HasPalette() )
+ ImplWritePalette();
+
+ ImplWriteIDAT();
+ }
+ aBmp.ReleaseAccess( mpAccess );
+ }
+ else
+ mbStatus = FALSE;
+ }
+ if ( mbStatus )
+ {
+ ImplOpenChunk( PNGCHUNK_IEND ); // create an IEND chunk
+ ImplCloseChunk();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+PNGWriterImpl::~PNGWriterImpl()
+{
+ delete mpZCodec;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool PNGWriterImpl::Write( SvStream& rOStm )
+{
+ /* png signature is always an array of 8 bytes */
+ sal_uInt16 nOldMode = rOStm.GetNumberFormatInt();
+ rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
+ rOStm << static_cast<sal_uInt32>(0x89504e47);
+ rOStm << static_cast<sal_uInt32>(0x0d0a1a0a);
+
+ std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg( maChunkSeq.begin() );
+ std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd( maChunkSeq.end() );
+ while( aBeg != aEnd )
+ {
+ sal_uInt32 nType = aBeg->nType;
+ #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
+ nType = SWAPLONG( nType );
+ #endif
+ sal_uInt32 nCRC = rtl_crc32( 0, &nType, 4 );
+ sal_uInt32 nDataSize = aBeg->aData.size();
+ if ( nDataSize )
+ nCRC = rtl_crc32( nCRC, &aBeg->aData[ 0 ], nDataSize );
+ rOStm << nDataSize
+ << aBeg->nType;
+ if ( nDataSize )
+ rOStm.Write( &aBeg->aData[ 0 ], nDataSize );
+ rOStm << nCRC;
+ aBeg++;
+ }
+ rOStm.SetNumberFormatInt( nOldMode );
+ return mbStatus;
+}
+
+// ------------------------------------------------------------------------
+
+std::vector< vcl::PNGWriter::ChunkData >& PNGWriterImpl::GetChunks()
+{
+ return maChunkSeq;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL PNGWriterImpl::ImplWriteHeader()
+{
+ ImplOpenChunk(PNGCHUNK_IHDR);
+ ImplWriteChunk( sal_uInt32( mnWidth = mpAccess->Width() ) );
+ ImplWriteChunk( sal_uInt32( mnHeight = mpAccess->Height() ) );
+
+ if ( mnWidth && mnHeight && mnBitsPerPixel && mbStatus )
+ {
+ BYTE nBitDepth = mnBitsPerPixel;
+ if ( mnBitsPerPixel <= 8 )
+ mnFilterType = 0;
+ else
+ mnFilterType = 4;
+
+ BYTE nColorType = 2; // colortype:
+ // bit 0 -> palette is used
+ if ( mpAccess->HasPalette() ) // bit 1 -> color is used
+ nColorType |= 1; // bit 2 -> alpha channel is used
+ else
+ nBitDepth /= 3;
+
+ if ( mpMaskAccess )
+ nColorType |= 4;
+
+ ImplWriteChunk( nBitDepth );
+ ImplWriteChunk( nColorType ); // colortype
+ ImplWriteChunk((BYTE) 0 ); // compression type
+ ImplWriteChunk((BYTE) 0 ); // filter type - is not supported in this version
+ ImplWriteChunk((BYTE) mnInterlaced ); // interlace type
+ ImplCloseChunk();
+ }
+ else
+ mbStatus = FALSE;
+ return mbStatus;
+}
+
+// ------------------------------------------------------------------------
+
+void PNGWriterImpl::ImplWritePalette()
+{
+ const ULONG nCount = mpAccess->GetPaletteEntryCount();
+ BYTE* pTempBuf = new BYTE[ nCount*3 ];
+ BYTE* pTmp = pTempBuf;
+
+ ImplOpenChunk( PNGCHUNK_PLTE );
+
+ for ( USHORT i = 0; i < nCount; i++ )
+ {
+ const BitmapColor& rColor = mpAccess->GetPaletteColor( i );
+ *pTmp++ = rColor.GetRed();
+ *pTmp++ = rColor.GetGreen();
+ *pTmp++ = rColor.GetBlue();
+ }
+ ImplWriteChunk( pTempBuf, nCount*3 );
+ ImplCloseChunk();
+ delete[] pTempBuf;
+}
+
+// ------------------------------------------------------------------------
+
+void PNGWriterImpl::ImplWriteTransparent ()
+{
+ const ULONG nTransIndex = mpAccess->GetBestMatchingColor( BMP_COL_TRANS );
+
+ ImplOpenChunk( PNGCHUNK_tRNS );
+
+ for ( ULONG n = 0UL; n <= nTransIndex; n++ )
+ ImplWriteChunk( ( nTransIndex == n ) ? (BYTE) 0x0 : (BYTE) 0xff );
+
+ ImplCloseChunk();
+}
+
+// ------------------------------------------------------------------------
+
+void PNGWriterImpl::ImplWritepHYs( const BitmapEx& rBmpEx )
+{
+ if ( rBmpEx.GetPrefMapMode() == MAP_100TH_MM )
+ {
+ Size aPrefSize( rBmpEx.GetPrefSize() );
+ if ( aPrefSize.Width() && aPrefSize.Height() )
+ {
+ ImplOpenChunk( PNGCHUNK_pHYs );
+ sal_uInt8 nMapUnit = 1;
+ sal_uInt32 nPrefSizeX = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Width() / mnWidth ) + 0.5 );
+ sal_uInt32 nPrefSizeY = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Height() / mnHeight ) + 0.5 );
+ ImplWriteChunk( nPrefSizeX );
+ ImplWriteChunk( nPrefSizeY );
+ ImplWriteChunk( nMapUnit );
+ ImplCloseChunk();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void PNGWriterImpl::ImplWriteIDAT ()
+{
+ mnDeflateInSize = mnBitsPerPixel;
+
+ if( mpMaskAccess )
+ mnDeflateInSize += 8;
+
+ mnBBP = ( mnDeflateInSize + 7 ) >> 3;
+
+ mnDeflateInSize = mnBBP * mnWidth + 1;
+
+ mpDeflateInBuf = new BYTE[ mnDeflateInSize ];
+
+ if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times
+ {
+ mpPreviousScan = new BYTE[ mnDeflateInSize ];
+ mpCurrentScan = new BYTE[ mnDeflateInSize ];
+ ImplClearFirstScanline();
+ }
+ mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT + mnCompLevel );
+ mpZCodec->SetCRC( mnCRC );
+ SvMemoryStream aOStm;
+ if ( mnInterlaced == 0 )
+ {
+ for ( ULONG nY = 0; nY < mnHeight; nY++ )
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter( nY ) );
+ }
+ else
+ {
+ // interlace mode
+ ULONG nY;
+ for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 1
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 8 ) );
+ ImplClearFirstScanline();
+
+ for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 2
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 4, 8 ) );
+ ImplClearFirstScanline();
+
+ if ( mnHeight >= 5 ) // pass 3
+ {
+ for ( nY = 4; nY < mnHeight; nY+=8 )
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 4 ) );
+ ImplClearFirstScanline();
+ }
+
+ for ( nY = 0; nY < mnHeight; nY+=4 ) // pass 4
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 2, 4 ) );
+ ImplClearFirstScanline();
+
+ if ( mnHeight >= 3 ) // pass 5
+ {
+ for ( nY = 2; nY < mnHeight; nY+=4 )
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 2 ) );
+ ImplClearFirstScanline();
+ }
+
+ for ( nY = 0; nY < mnHeight; nY+=2 ) // pass 6
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 1, 2 ) );
+ ImplClearFirstScanline();
+
+ if ( mnHeight >= 2 ) // pass 7
+ {
+ for ( nY = 1; nY < mnHeight; nY+=2 )
+ mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 1 ) );
+ }
+ }
+ mpZCodec->EndCompression();
+ mnCRC = mpZCodec->GetCRC();
+
+ if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times
+ {
+ delete[] mpCurrentScan;
+ delete[] mpPreviousScan;
+ }
+ delete[] mpDeflateInBuf;
+
+ sal_uInt32 nIDATSize = aOStm.Tell();
+ sal_uInt32 nBytes, nBytesToWrite = nIDATSize;
+ while( nBytesToWrite )
+ {
+ nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize;
+ ImplOpenChunk( PNGCHUNK_IDAT );
+ ImplWriteChunk( (unsigned char*)aOStm.GetData() + ( nIDATSize - nBytesToWrite ), nBytes );
+ ImplCloseChunk();
+ nBytesToWrite -= nBytes;
+ }
+}
+
+// ---------------------------------------------------------------------------------------------------
+// ImplGetFilter writes the complete Scanline (nY) - in interlace mode the parameter nXStart and nXAdd
+// appends to the currently used pass
+// the complete size of scanline will be returned - in interlace mode zero is possible!
+
+ULONG PNGWriterImpl::ImplGetFilter ( ULONG nY, ULONG nXStart, ULONG nXAdd )
+{
+ BYTE* pDest;
+
+ if ( mnFilterType )
+ pDest = mpCurrentScan;
+ else
+ pDest = mpDeflateInBuf;
+
+ if ( nXStart < mnWidth )
+ {
+ *pDest++ = mnFilterType; // in this version the filter type is either 0 or 4
+
+ if ( mpAccess->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
+ {
+ switch ( mnBitsPerPixel )
+ {
+ case( 1 ):
+ {
+ ULONG nX, nXIndex;
+ for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+=nXAdd, nXIndex++ )
+ {
+ ULONG nShift = ( nXIndex & 7 ) ^ 7;
+ if ( nShift == 7)
+ *pDest = (BYTE)(mpAccess->GetPixel( nY, nX ) << nShift);
+ else if ( nShift == 0 )
+ *pDest++ |= (BYTE) mpAccess->GetPixel( nY, nX ) << nShift;
+ else
+ *pDest |= (BYTE) mpAccess->GetPixel( nY, nX ) << nShift;
+ }
+ if ( ( nXIndex & 7 ) != 0 ) pDest++; // byte is not completely used, so the
+ } // bufferpointer is to correct
+ break;
+
+ case( 4 ):
+ {
+ ULONG nX, nXIndex;
+ for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+= nXAdd, nXIndex++ )
+ {
+ if( nXIndex & 1 )
+ *pDest++ |= (BYTE) mpAccess->GetPixel( nY, nX );
+ else
+ *pDest = (BYTE) mpAccess->GetPixel( nY, nX ) << 4;
+ }
+ if ( nXIndex & 1 ) pDest++;
+ }
+ break;
+
+ case( 8 ):
+ {
+ for ( ULONG nX = nXStart; nX < mnWidth; nX+=nXAdd )
+ *pDest++ = mpAccess->GetPixel( nY, nX );
+ }
+ break;
+
+ default :
+ mbStatus = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ if ( mpMaskAccess ) // mpMaskAccess != NULL -> alphachannel is to create
+ {
+ if ( mbTrueAlpha )
+ {
+ for ( ULONG nX = nXStart; nX < mnWidth; nX += nXAdd )
+ {
+ const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
+ *pDest++ = rColor.GetRed();
+ *pDest++ = rColor.GetGreen();
+ *pDest++ = rColor.GetBlue();
+ *pDest++ = 255 - mpMaskAccess->GetPixel( nY, nX );
+ }
+ }
+ else
+ {
+ const BitmapColor aTrans( mpMaskAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for ( ULONG nX = nXStart; nX < mnWidth; nX+=nXAdd )
+ {
+ const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
+ *pDest++ = rColor.GetRed();
+ *pDest++ = rColor.GetGreen();
+ *pDest++ = rColor.GetBlue();
+
+ if( mpMaskAccess->GetPixel( nY, nX ) == aTrans )
+ *pDest++ = 0;
+ else
+ *pDest++ = 0xff;
+ }
+ }
+ }
+ else
+ {
+ for ( ULONG nX = nXStart; nX < mnWidth; nX+=nXAdd )
+ {
+ const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
+ *pDest++ = rColor.GetRed();
+ *pDest++ = rColor.GetGreen();
+ *pDest++ = rColor.GetBlue();
+ }
+ }
+ }
+ }
+ // filter type4 ( PAETH ) will be used only for 24bit graphics
+ if ( mnFilterType )
+ {
+ mnDeflateInSize = pDest - mpCurrentScan;
+ pDest = mpDeflateInBuf;
+ *pDest++ = 4; // filter type
+
+ ULONG na, nb, nc;
+ long np, npa, npb, npc;
+
+ BYTE* p1 = mpCurrentScan + 1; // Current Pixel
+ BYTE* p2 = p1 - mnBBP; // left pixel
+ BYTE* p3 = mpPreviousScan; // upper pixel
+ BYTE* p4 = p3 - mnBBP; // upperleft Pixel;
+
+ while ( pDest < mpDeflateInBuf + mnDeflateInSize )
+ {
+ nb = *p3++;
+ if ( p2 >= mpCurrentScan + 1 )
+ {
+ na = *p2;
+ nc = *p4;
+ }
+ else
+ na = nc = 0;
+
+ np = na + nb;
+ np -= nc;
+ npa = np - na;
+ npb = np - nb;
+ npc = np - nc;
+ if ( npa < 0 )
+ npa =-npa;
+ if ( npb < 0 )
+ npb =-npb;
+ if ( npc < 0 )
+ npc =-npc;
+ if ( ( npa <= npb ) && ( npa <= npc ) ) *pDest++ = *p1++ - (BYTE)na;
+ else if ( npb <= npc ) *pDest++ = *p1++ - (BYTE)nb;
+ else *pDest++ = *p1++ - (BYTE)nc;
+ p4++;
+ p2++;
+ }
+ for ( long i = 0; i < (long)( mnDeflateInSize - 1 ); i++ )
+ mpPreviousScan[ i ] = mpCurrentScan[ i + 1 ];
+ }
+ else
+ mnDeflateInSize = pDest - mpDeflateInBuf;
+ return ( mnDeflateInSize );
+}
+
+// ------------------------------------------------------------------------
+
+void PNGWriterImpl::ImplClearFirstScanline()
+{
+ if ( mnFilterType )
+ rtl_zeroMemory( mpPreviousScan, mnDeflateInSize );
+}
+
+// ------------------------------------------------------------------------
+
+void PNGWriterImpl::ImplOpenChunk ( ULONG nChunkType )
+{
+ maChunkSeq.resize( maChunkSeq.size() + 1 );
+ maChunkSeq.back().nType = nChunkType;
+}
+
+// ------------------------------------------------------------------------
+
+void PNGWriterImpl::ImplWriteChunk ( BYTE nSource )
+{
+ maChunkSeq.back().aData.push_back( nSource );
+}
+
+void PNGWriterImpl::ImplWriteChunk ( sal_uInt32 nSource )
+{
+ vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
+ rChunkData.aData.push_back( (sal_uInt8)( nSource >> 24 ) );
+ rChunkData.aData.push_back( (sal_uInt8)( nSource >> 16 ) );
+ rChunkData.aData.push_back( (sal_uInt8)( nSource >> 8 ) );
+ rChunkData.aData.push_back( (sal_uInt8)( nSource ) );
+}
+
+void PNGWriterImpl::ImplWriteChunk ( unsigned char* pSource, sal_uInt32 nDatSize )
+{
+ if ( nDatSize )
+ {
+ vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
+ sal_uInt32 nSize = rChunkData.aData.size();
+ rChunkData.aData.resize( nSize + nDatSize );
+ rtl_copyMemory( &rChunkData.aData[ nSize ], pSource, nDatSize );
+ }
+}
+
+// ------------------------------------------------------------------------
+// nothing to do
+void PNGWriterImpl::ImplCloseChunk ( void )
+{
+}
+
+// -------------
+// - PNGWriter -
+// -------------
+
+PNGWriter::PNGWriter( const BitmapEx& rBmpEx,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
+ mpImpl( new ::vcl::PNGWriterImpl( rBmpEx, pFilterData ) )
+{
+}
+
+// ------------------------------------------------------------------------
+
+PNGWriter::~PNGWriter()
+{
+ delete mpImpl;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool PNGWriter::Write( SvStream& rIStm )
+{
+ return mpImpl->Write( rIStm );
+}
+
+// ------------------------------------------------------------------------
+
+std::vector< vcl::PNGWriter::ChunkData >& PNGWriter::GetChunks()
+{
+ return mpImpl->GetChunks();
+}
+
+} // namespace vcl
+
diff --git a/vcl/source/gdi/polyscan.cxx b/vcl/source/gdi/polyscan.cxx
new file mode 100644
index 000000000000..eb329f8c6869
--- /dev/null
+++ b/vcl/source/gdi/polyscan.cxx
@@ -0,0 +1,358 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <tools/new.hxx>
+#include <vcl/salbtype.hxx>
+#include "polyscan.hxx"
+#include <tools/poly.hxx>
+
+// ----------------
+// - PolyScanline -
+// ----------------
+
+PolyScanline::PolyScanline() :
+ mpFirst ( NULL ),
+ mpLast ( NULL ),
+ mpAct ( NULL ),
+ mnLeft ( 0L ),
+ mnRight ( 0L )
+{
+}
+
+// ------------------------------------------------------------------------
+
+PolyScanline::~PolyScanline()
+{
+ ImplDelete();
+}
+
+// ------------------------------------------------------------------------
+
+void PolyScanline::ImplDelete()
+{
+ ScanlinePoint* pAct = mpFirst;
+
+ while( pAct )
+ {
+ ScanlinePoint* pNext = pAct->mpNext;
+ delete pAct;
+ pAct = pNext;
+ }
+
+ mnLeft = mnRight = 0L;
+ mpFirst = mpAct = mpLast = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+void PolyScanline::Insert( long nX )
+{
+ // first point to insert?
+ if( !mpFirst )
+ mpLast = mpFirst = new ScanlinePoint( mnLeft = mnRight = nX, NULL );
+ else
+ {
+ // insert at the beginning of the scanline
+ if( nX <= mpFirst->mnX )
+ mpFirst = new ScanlinePoint( mnLeft = nX, mpFirst );
+ else if( nX >= mnRight )
+ mpLast = mpLast->mpNext = new ScanlinePoint( mnRight = nX, NULL );
+ else
+ {
+ ScanlinePoint* pLast = mpFirst;
+ ScanlinePoint* pAct = mpFirst->mpNext;
+
+ while( pAct )
+ {
+ // insert in the midlle of the scanline?
+ if( nX <= pAct->mnX )
+ {
+ pLast->mpNext = new ScanlinePoint( nX, pAct );
+ break;
+ }
+
+ pLast = pAct;
+ pAct = pAct->mpNext;
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void PolyScanline::Set( long nStart, long nEnd )
+{
+ if( mpFirst )
+ ImplDelete();
+
+ if( nStart <= nEnd )
+ mpFirst = new ScanlinePoint( mnLeft = nStart, mpLast = new ScanlinePoint( mnRight = nEnd, NULL ) );
+ else
+ mpFirst = new ScanlinePoint( mnLeft = nEnd, mpLast = new ScanlinePoint( mnRight = nStart, NULL ) );
+}
+
+// ------------------------------------------------------------------------
+
+BOOL PolyScanline::GetFirstSegment( PolyScanSegment& rSegment )
+{
+ BOOL bRet = GetFirstX( rSegment.mnStart );
+
+ if( bRet && !GetNextX( rSegment.mnEnd ) )
+ rSegment.mnEnd = rSegment.mnStart;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+BOOL PolyScanline::GetNextSegment( PolyScanSegment& rSegment )
+{
+ BOOL bRet = GetNextX( rSegment.mnStart );
+
+ if( bRet && !GetNextX( rSegment.mnEnd ) )
+ rSegment.mnEnd = rSegment.mnStart;
+
+ return bRet;
+}
+
+// ---------------
+// - PolyScanner -
+// ---------------
+
+PolyScanner::PolyScanner( const Rectangle& rRect )
+{
+ if( !rRect.IsEmpty() )
+ {
+ Rectangle aRect( rRect );
+ ULONG nHeight;
+
+ aRect.Justify();
+ mnLeft = aRect.Left();
+ mnTop = aRect.Top();
+ mnRight = aRect.Right();
+ mnBottom = aRect.Bottom();
+ mpArray = new PolyScanline[ nHeight = Height() ];
+
+ for( ULONG i = 0UL; i < nHeight; i++ )
+ mpArray[ i ].Set( mnLeft, mnRight );
+ }
+ else
+ {
+ mnLeft = mnTop = mnRight = mnBottom = 0L;
+ mpArray = NULL;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+PolyScanner::PolyScanner( const Polygon& rPoly )
+{
+ const long nCount = rPoly.GetSize();
+
+ if( nCount )
+ {
+ long nLast = nCount - 1;
+ Point aFirst( rPoly[ 0 ] );
+ Point aLast( rPoly[ (USHORT) nLast ] );
+
+ while( nLast && ( aLast == aFirst ) )
+ aLast = rPoly[ (USHORT) --nLast ];
+
+ if( !nLast )
+ {
+ aLast = rPoly[ 0 ];
+ mnLeft = mnRight = aLast.X();
+ mnTop = mnBottom = aLast.Y();
+ mpArray = new PolyScanline[ 1UL ];
+ mpArray[ 0 ].Set( mnLeft, mnRight );
+ }
+ else
+ {
+ const Rectangle aRect( rPoly.GetBoundRect() );
+ ULONG nHeight;
+
+ mnLeft = aRect.Left();
+ mnTop = aRect.Top();
+ mnRight = aRect.Right();
+ mnBottom = aRect.Bottom();
+ aLast = aFirst;
+ mpArray = new PolyScanline[ nHeight = Height() ];
+
+ for( long i = 1L; i <= nLast; i++ )
+ {
+ const Point& rPt = rPoly[ (USHORT) i ];
+
+ if( rPt != aLast )
+ {
+ InsertLine( aLast, rPt );
+ aLast = rPt;
+ }
+ }
+
+ InsertLine( aLast, aFirst );
+ }
+ }
+ else
+ mpArray = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+PolyScanner::PolyScanner( const PolyPolygon& rPolyPoly )
+{
+ mpArray = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+PolyScanner::~PolyScanner()
+{
+ delete[] mpArray;
+}
+
+// ------------------------------------------------------------------------
+
+PolyScanline* PolyScanner::operator[]( ULONG nPos ) const
+{
+ DBG_ASSERT( nPos < Count(), "nPos out of range!" );
+ return( mpArray ? ( mpArray + nPos ) : NULL );
+}
+
+// ------------------------------------------------------------------------
+
+void PolyScanner::InsertLine( const Point& rStart, const Point& rEnd )
+{
+ long nX, nY;
+
+ if( rStart.Y() == rEnd.Y() )
+ mpArray[ rStart.Y() - mnTop ].Insert( rStart.X() );
+ else if( rStart.X() == rEnd.X() )
+ {
+ // vertical line
+ const long nEndY = rEnd.Y();
+
+ nX = rStart.X();
+ nY = rStart.Y();
+
+ if( nEndY > nY )
+ while( nY < nEndY )
+ mpArray[ nY++ - mnTop ].Insert( nX );
+ else
+ while( nY > nEndY )
+ mpArray[ nY-- - mnTop ].Insert( nX );
+ }
+ else
+ {
+ const long nDX = labs( rEnd.X() - rStart.X() );
+ const long nDY = labs( rEnd.Y() - rStart.Y() );
+ const long nStartX = rStart.X();
+ const long nStartY = rStart.Y();
+ const long nEndX = rEnd.X();
+ const long nEndY = rEnd.Y();
+ const long nXInc = ( nStartX < nEndX ) ? 1L : -1L;
+ const long nYInc = ( nStartY < nEndY ) ? 1L : -1L;
+ long nLastX = nStartX;
+ long nLastY = nStartY;
+ BOOL bLast = FALSE;
+
+ mpArray[ nStartY - mnTop ].Insert( nStartX );
+
+ if( nDX >= nDY )
+ {
+ const long nDYX = ( nDY - nDX ) << 1;
+ const long nDY2 = nDY << 1;
+ long nD = nDY2 - nDX;
+
+ for( nX = nStartX, nY = nLastY = nStartY; nX != nEndX; )
+ {
+ if( nY != nLastY )
+ {
+ if( bLast )
+ mpArray[ nLastY - mnTop ].Insert( nLastX );
+
+ mpArray[ nY - mnTop ].Insert( nX );
+ bLast = FALSE;
+ }
+ else
+ bLast = TRUE;
+
+ nLastX = nX;
+ nLastY = nY;
+
+ if( nD < 0L )
+ nD += nDY2;
+ else
+ {
+ nD += nDYX;
+ nY += nYInc;
+ }
+
+ nX += nXInc;
+ }
+ }
+ else
+ {
+ const long nDYX = ( nDX - nDY ) << 1;
+ const long nDY2 = nDX << 1;
+ long nD = nDY2 - nDY;
+
+ for( nX = nStartX, nY = nStartY; nY != nEndY; )
+ {
+ if( nY != nLastY )
+ {
+ if( bLast )
+ mpArray[ nLastY - mnTop ].Insert( nLastX );
+
+ mpArray[ nY - mnTop ].Insert( nX );
+ bLast = FALSE;
+ }
+ else
+ bLast = TRUE;
+
+ nLastX = nX;
+ nLastY = nY;
+
+ if( nD < 0L )
+ nD += nDY2;
+ else
+ {
+ nD += nDYX;
+ nX += nXInc;
+ }
+
+ nY += nYInc;
+ }
+ }
+
+ if( bLast )
+ mpArray[ nLastY - mnTop ].Insert( nLastX );
+ }
+}
diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx
new file mode 100644
index 000000000000..2ea9bfcc4c11
--- /dev/null
+++ b/vcl/source/gdi/print.cxx
@@ -0,0 +1,1481 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define ENABLE_BYTESTRING_STREAM_OPERATORS
+#include <list>
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salinst.hxx>
+#include <vcl/salgdi.hxx>
+#include <vcl/salptype.hxx>
+#include <vcl/salprn.hxx>
+
+#include <vcl/unohelp.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/jobset.h>
+#include <vcl/outdev.h>
+#include <vcl/virdev.hxx>
+#include <vcl/window.hxx>
+#include <vcl/print.h>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/print.hxx>
+
+#include <comphelper/processfactory.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+
+int nImplSysDialog = 0;
+
+// =======================================================================
+
+namespace
+{
+ static Paper ImplGetPaperFormat( long nWidth100thMM, long nHeight100thMM )
+ {
+ PaperInfo aInfo(nWidth100thMM, nHeight100thMM);
+ aInfo.doSloppyFit();
+ return aInfo.getPaper();
+ }
+
+// -----------------------------------------------------------------------
+
+ static const PaperInfo& ImplGetEmptyPaper()
+ {
+ static PaperInfo aInfo(PAPER_USER);
+ return aInfo;
+ }
+}
+
+// =======================================================================
+
+void ImplUpdateJobSetupPaper( JobSetup& rJobSetup )
+{
+ const ImplJobSetup* pConstData = rJobSetup.ImplGetConstData();
+
+ if ( !pConstData->mnPaperWidth || !pConstData->mnPaperHeight )
+ {
+ if ( pConstData->mePaperFormat != PAPER_USER )
+ {
+ ImplJobSetup* pData = rJobSetup.ImplGetData();
+ PaperInfo aInfo(pConstData->mePaperFormat);
+ pData->mnPaperWidth = aInfo.getWidth();
+ pData->mnPaperHeight = aInfo.getHeight();
+ }
+ }
+ else if ( pConstData->mePaperFormat == PAPER_USER )
+ {
+ Paper ePaper = ImplGetPaperFormat( pConstData->mnPaperWidth, pConstData->mnPaperHeight );
+ if ( ePaper != PAPER_USER )
+ rJobSetup.ImplGetData()->mePaperFormat = ePaper;
+ }
+}
+
+// ------------------
+// - PrinterOptions -
+// ------------------
+
+PrinterOptions::PrinterOptions() :
+ mbReduceTransparency( FALSE ),
+ meReducedTransparencyMode( PRINTER_TRANSPARENCY_AUTO ),
+ mbReduceGradients( FALSE ),
+ meReducedGradientsMode( PRINTER_GRADIENT_STRIPES ),
+ mnReducedGradientStepCount( 64 ),
+ mbReduceBitmaps( FALSE ),
+ meReducedBitmapMode( PRINTER_BITMAP_NORMAL ),
+ mnReducedBitmapResolution( 200 ),
+ mbReducedBitmapsIncludeTransparency( TRUE ),
+ mbConvertToGreyscales( FALSE )
+{
+}
+
+// -----------------------------------------------------------------------
+
+PrinterOptions::~PrinterOptions()
+{
+}
+
+// -------------
+// - QueueInfo -
+// -------------
+
+QueueInfo::QueueInfo()
+{
+ mnStatus = 0;
+ mnJobs = 0;
+}
+
+// -----------------------------------------------------------------------
+
+QueueInfo::QueueInfo( const QueueInfo& rInfo ) :
+ maPrinterName( rInfo.maPrinterName ),
+ maDriver( rInfo.maDriver ),
+ maLocation( rInfo.maLocation ),
+ maComment( rInfo.maComment ),
+ mnStatus( rInfo.mnStatus ),
+ mnJobs( rInfo.mnJobs )
+{
+}
+
+// -----------------------------------------------------------------------
+
+QueueInfo::~QueueInfo()
+{
+}
+
+// -----------------------------------------------------------------------
+
+bool QueueInfo::operator==( const QueueInfo& rInfo ) const
+{
+ return
+ maPrinterName == rInfo.maPrinterName &&
+ maDriver == rInfo.maDriver &&
+ maLocation == rInfo.maLocation &&
+ maComment == rInfo.maComment &&
+ mnStatus == rInfo.mnStatus &&
+ mnJobs == rInfo.mnJobs;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStream, const QueueInfo& rInfo )
+{
+ VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
+
+ rOStream.WriteByteString( rInfo.maPrinterName, RTL_TEXTENCODING_UTF8 );
+ rOStream.WriteByteString( rInfo.maDriver, RTL_TEXTENCODING_UTF8 );
+ rOStream.WriteByteString( rInfo.maLocation, RTL_TEXTENCODING_UTF8 );
+ rOStream.WriteByteString( rInfo.maComment, RTL_TEXTENCODING_UTF8 );
+ rOStream << rInfo.mnStatus;
+ rOStream << rInfo.mnJobs;
+
+ return rOStream;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStream, QueueInfo& rInfo )
+{
+ VersionCompat aCompat( rIStream, STREAM_READ );
+
+ rIStream.ReadByteString( rInfo.maPrinterName, RTL_TEXTENCODING_UTF8 );
+ rIStream.ReadByteString( rInfo.maDriver, RTL_TEXTENCODING_UTF8 );
+ rIStream.ReadByteString( rInfo.maLocation, RTL_TEXTENCODING_UTF8 );
+ rIStream.ReadByteString( rInfo.maComment, RTL_TEXTENCODING_UTF8 );
+ rIStream >> rInfo.mnStatus;
+ rIStream >> rInfo.mnJobs;
+
+ return rIStream;
+}
+
+// =======================================================================
+
+SalPrinterQueueInfo::SalPrinterQueueInfo()
+{
+ mnStatus = 0;
+ mnJobs = QUEUE_JOBS_DONTKNOW;
+ mpSysData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinterQueueInfo::~SalPrinterQueueInfo()
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImplPrnQueueList::~ImplPrnQueueList()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ for( unsigned int i = 0; i < m_aQueueInfos.size(); i++ )
+ {
+ delete m_aQueueInfos[i].mpQueueInfo;
+ pSVData->mpDefInst->DeletePrinterQueueInfo( m_aQueueInfos[i].mpSalQueueInfo );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplPrnQueueList::Add( SalPrinterQueueInfo* pData )
+{
+ std::hash_map< rtl::OUString, sal_Int32, rtl::OUStringHash >::iterator it =
+ m_aNameToIndex.find( pData->maPrinterName );
+ if( it == m_aNameToIndex.end() )
+ {
+ m_aNameToIndex[ pData->maPrinterName ] = m_aQueueInfos.size();
+ m_aQueueInfos.push_back( ImplPrnQueueData() );
+ m_aQueueInfos.back().mpQueueInfo = NULL;
+ m_aQueueInfos.back().mpSalQueueInfo = pData;
+ m_aPrinterList.push_back( pData->maPrinterName );
+ }
+ else // this should not happen, but ...
+ {
+ ImplPrnQueueData& rData = m_aQueueInfos[ it->second ];
+ delete rData.mpQueueInfo;
+ rData.mpQueueInfo = NULL;
+ ImplGetSVData()->mpDefInst->DeletePrinterQueueInfo( rData.mpSalQueueInfo );
+ rData.mpSalQueueInfo = pData;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplPrnQueueData* ImplPrnQueueList::Get( const rtl::OUString& rPrinter )
+{
+ ImplPrnQueueData* pData = NULL;
+ std::hash_map<rtl::OUString,sal_Int32,rtl::OUStringHash>::iterator it =
+ m_aNameToIndex.find( rPrinter );
+ if( it != m_aNameToIndex.end() )
+ pData = &m_aQueueInfos[it->second];
+ return pData;
+}
+
+// =======================================================================
+
+static void ImplInitPrnQueueList()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ pSVData->maGDIData.mpPrinterQueueList = new ImplPrnQueueList;
+
+ static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" );
+ if( !pEnv || !*pEnv )
+ pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDeletePrnQueueList()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList;
+
+ if ( pPrnList )
+ {
+ delete pPrnList;
+ pSVData->maGDIData.mpPrinterQueueList = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const std::vector<rtl::OUString>& Printer::GetPrinterQueues()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maGDIData.mpPrinterQueueList )
+ ImplInitPrnQueueList();
+ return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList;
+}
+
+// -----------------------------------------------------------------------
+const QueueInfo* Printer::GetQueueInfo( const String& rPrinterName, bool bStatusUpdate )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( !pSVData->maGDIData.mpPrinterQueueList )
+ ImplInitPrnQueueList();
+
+ ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName );
+ if( pInfo )
+ {
+ if( !pInfo->mpQueueInfo || bStatusUpdate )
+ pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo );
+
+ if ( !pInfo->mpQueueInfo )
+ pInfo->mpQueueInfo = new QueueInfo;
+
+ pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName;
+ pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver;
+ pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation;
+ pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment;
+ pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus;
+ pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs;
+ return pInfo->mpQueueInfo;
+ }
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Printer::GetDefaultPrinterName()
+{
+ static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" );
+ if( !pEnv || !*pEnv )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+
+ return pSVData->mpDefInst->GetDefaultPrinter();
+ }
+ return XubString();
+}
+
+// =======================================================================
+
+void Printer::ImplInitData()
+{
+ mbDevOutput = FALSE;
+ meOutDevType = OUTDEV_PRINTER;
+ mbDefPrinter = FALSE;
+ mnError = 0;
+ mnCurPage = 0;
+ mnCurPrintPage = 0;
+ mnPageQueueSize = 0;
+ mnCopyCount = 1;
+ mbCollateCopy = FALSE;
+ mbPrinting = FALSE;
+ mbJobActive = FALSE;
+ mbPrintFile = FALSE;
+ mbInPrintPage = FALSE;
+ mbNewJobSetup = FALSE;
+ mpInfoPrinter = NULL;
+ mpPrinter = NULL;
+ mpDisplayDev = NULL;
+ mbIsQueuePrinter = FALSE;
+ mpPrinterOptions = new PrinterOptions;
+
+ // Printer in die Liste eintragen
+ ImplSVData* pSVData = ImplGetSVData();
+ mpNext = pSVData->maGDIData.mpFirstPrinter;
+ mpPrev = NULL;
+ if ( mpNext )
+ mpNext->mpPrev = this;
+ else
+ pSVData->maGDIData.mpLastPrinter = this;
+ pSVData->maGDIData.mpFirstPrinter = this;
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::ImplInit( SalPrinterQueueInfo* pInfo )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ // #i74084# update info for this specific SalPrinterQueueInfo
+ pSVData->mpDefInst->GetPrinterQueueState( pInfo );
+
+ // Testen, ob Treiber ueberhaupt mit dem JobSetup uebereinstimmt
+ ImplJobSetup* pJobSetup = maJobSetup.ImplGetData();
+
+ if ( pJobSetup->mpDriverData )
+ {
+ if ( (pJobSetup->maPrinterName != pInfo->maPrinterName) ||
+ (pJobSetup->maDriver != pInfo->maDriver) )
+ {
+ rtl_freeMemory( pJobSetup->mpDriverData );
+ pJobSetup->mpDriverData = NULL;
+ pJobSetup->mnDriverDataLen = 0;
+ }
+ }
+
+ // Printernamen merken
+ maPrinterName = pInfo->maPrinterName;
+ maDriver = pInfo->maDriver;
+
+ // In JobSetup den Printernamen eintragen
+ pJobSetup->maPrinterName = maPrinterName;
+ pJobSetup->maDriver = maDriver;
+
+ mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, pJobSetup );
+ mpPrinter = NULL;
+ mpJobGraphics = NULL;
+ ImplUpdateJobSetupPaper( maJobSetup );
+
+ if ( !mpInfoPrinter )
+ {
+ ImplInitDisplay( NULL );
+ return;
+ }
+
+ // we need a graphics
+ if ( !ImplGetGraphics() )
+ {
+ ImplInitDisplay( NULL );
+ return;
+ }
+
+ // Daten initialisieren
+ ImplUpdatePageData();
+ mpFontList = new ImplDevFontList();
+ mpFontCache = new ImplFontCache( TRUE );
+ mpGraphics->GetDevFontList( mpFontList );
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::ImplInitDisplay( const Window* pWindow )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ mpInfoPrinter = NULL;
+ mpPrinter = NULL;
+ mpJobGraphics = NULL;
+
+ if ( pWindow )
+ mpDisplayDev = new VirtualDevice( *pWindow );
+ else
+ mpDisplayDev = new VirtualDevice();
+ mpFontList = pSVData->maGDIData.mpScreenFontList;
+ mpFontCache = pSVData->maGDIData.mpScreenFontCache;
+ mnDPIX = mpDisplayDev->mnDPIX;
+ mnDPIY = mpDisplayDev->mnDPIY;
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const XubString& rPrinterName,
+ const XubString* pDriver )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maGDIData.mpPrinterQueueList )
+ ImplInitPrnQueueList();
+
+ ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList;
+ if ( pPrnList && pPrnList->m_aQueueInfos.size() )
+ {
+ // first search for the printer name driectly
+ ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName );
+ if( pInfo )
+ return pInfo->mpSalQueueInfo;
+
+ // then search case insensitive
+ for( unsigned int i = 0; i < pPrnList->m_aQueueInfos.size(); i++ )
+ {
+ if( pPrnList->m_aQueueInfos[i].mpSalQueueInfo->maPrinterName.EqualsIgnoreCaseAscii( rPrinterName ) )
+ return pPrnList->m_aQueueInfos[i].mpSalQueueInfo;
+ }
+
+ // then search for driver name
+ if ( pDriver )
+ {
+ for( unsigned int i = 0; i < pPrnList->m_aQueueInfos.size(); i++ )
+ {
+ if( pPrnList->m_aQueueInfos[i].mpSalQueueInfo->maDriver == *pDriver )
+ return pPrnList->m_aQueueInfos[i].mpSalQueueInfo;
+ }
+ }
+
+ // then the default printer
+ pInfo = pPrnList->Get( GetDefaultPrinterName() );
+ if( pInfo )
+ return pInfo->mpSalQueueInfo;
+
+ // last chance: the first available printer
+ return pPrnList->m_aQueueInfos[0].mpSalQueueInfo;
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::ImplUpdatePageData()
+{
+ // we need a graphics
+ if ( !ImplGetGraphics() )
+ return;
+
+ mpGraphics->GetResolution( mnDPIX, mnDPIY );
+ mpInfoPrinter->GetPageInfo( maJobSetup.ImplGetConstData(),
+ mnOutWidth, mnOutHeight,
+ maPageOffset.X(), maPageOffset.Y(),
+ maPaperSize.Width(), maPaperSize.Height() );
+ static const char* pDebugOffset = getenv( "SAL_DBG_PAGEOFFSET" );
+ if( pDebugOffset )
+ {
+ rtl::OString aLine( pDebugOffset );
+ sal_Int32 nIndex = 0;
+ rtl::OString aToken( aLine.getToken( 0, ',', nIndex ) );
+ sal_Int32 nLeft = aToken.toInt32();
+ sal_Int32 nTop = nLeft;
+ if( nIndex > 0 )
+ {
+ aToken = aLine.getToken( 0, ',', nIndex );
+ nTop = aToken.toInt32();
+ }
+ maPageOffset = LogicToPixel( Point( static_cast<long>(nLeft),
+ static_cast<long>(nTop) ),
+ MapMode( MAP_100TH_MM )
+ );
+ mnOutWidth = maPaperSize.Width() - 2*maPageOffset.X();
+ mnOutWidth = maPaperSize.Width() - 2*maPageOffset.Y();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::ImplUpdateFontList()
+{
+ ImplUpdateFontData( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+Printer::Printer()
+{
+ ImplInitData();
+ SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), NULL );
+ if ( pInfo )
+ {
+ ImplInit( pInfo );
+ if ( !IsDisplayPrinter() )
+ mbDefPrinter = TRUE;
+ }
+ else
+ ImplInitDisplay( NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Printer::Printer( const Window* pWindow )
+{
+ ImplInitData();
+ ImplInitDisplay( pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+Printer::Printer( const JobSetup& rJobSetup ) :
+ maJobSetup( rJobSetup )
+{
+ ImplInitData();
+ SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rJobSetup.mpData->maPrinterName,
+ &rJobSetup.mpData->maDriver );
+ if ( pInfo )
+ {
+ ImplInit( pInfo );
+ SetJobSetup( rJobSetup );
+ }
+ else
+ {
+ ImplInitDisplay( NULL );
+ maJobSetup = JobSetup();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Printer::Printer( const QueueInfo& rQueueInfo )
+{
+ ImplInitData();
+ SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(),
+ &rQueueInfo.GetDriver() );
+ if ( pInfo )
+ ImplInit( pInfo );
+ else
+ ImplInitDisplay( NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Printer::Printer( const XubString& rPrinterName )
+{
+ ImplInitData();
+ SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, NULL );
+ if ( pInfo )
+ ImplInit( pInfo );
+ else
+ ImplInitDisplay( NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Printer::~Printer()
+{
+ DBG_ASSERT( !IsPrinting(), "Printer::~Printer() - Job is printing" );
+ DBG_ASSERT( !IsJobActive(), "Printer::~Printer() - Job is active" );
+
+ delete mpPrinterOptions;
+
+ ImplReleaseGraphics();
+ if ( mpInfoPrinter )
+ ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
+ if ( mpDisplayDev )
+ delete mpDisplayDev;
+ else
+ {
+ // OutputDevice-Dtor versucht das gleiche, deshalb muss hier
+ // der FontEntry auch auf NULL gesetzt werden
+ // TODO: consolidate duplicate cleanup by Printer and OutputDevice
+ if ( mpFontEntry )
+ {
+ mpFontCache->Release( mpFontEntry );
+ mpFontEntry = NULL;
+ }
+ if ( mpGetDevFontList )
+ {
+ delete mpGetDevFontList;
+ mpGetDevFontList = NULL;
+ }
+ if ( mpGetDevSizeList )
+ {
+ delete mpGetDevSizeList;
+ mpGetDevSizeList = NULL;
+ }
+ delete mpFontCache;
+ mpFontCache = NULL;
+ // font list deleted by OutputDevice dtor
+ }
+
+ // Printer aus der Liste eintragen
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( mpPrev )
+ mpPrev->mpNext = mpNext;
+ else
+ pSVData->maGDIData.mpFirstPrinter = mpNext;
+ if ( mpNext )
+ mpNext->mpPrev = mpPrev;
+ else
+ pSVData->maGDIData.mpLastPrinter = mpPrev;
+}
+
+// -----------------------------------------------------------------------
+void Printer::Compat_OldPrinterMetrics( bool bSet )
+{
+ // propagate flag
+ if( mpInfoPrinter )
+ mpInfoPrinter->m_bCompatMetrics = bSet;
+
+ // get new font data
+ ImplUpdateFontData( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Printer::GetCapabilities( USHORT nType ) const
+{
+ if ( IsDisplayPrinter() )
+ return FALSE;
+
+ if( mpInfoPrinter )
+ return mpInfoPrinter->GetCapabilities( maJobSetup.ImplGetConstData(), nType );
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::HasSupport( PrinterSupport eFeature ) const
+{
+ switch ( eFeature )
+ {
+ case SUPPORT_SET_ORIENTATION:
+ return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETORIENTATION );
+ case SUPPORT_SET_PAPERBIN:
+ return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETPAPERBIN );
+ case SUPPORT_SET_PAPERSIZE:
+ return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETPAPERSIZE );
+ case SUPPORT_SET_PAPER:
+ return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETPAPER );
+ case SUPPORT_COPY:
+ return (GetCapabilities( PRINTER_CAPABILITIES_COPIES ) != 0);
+ case SUPPORT_COLLATECOPY:
+ return (GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES ) != 0);
+ case SUPPORT_SETUPDIALOG:
+ return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SUPPORTDIALOG );
+ case SUPPORT_FAX:
+ return (BOOL) GetCapabilities( PRINTER_CAPABILITIES_FAX );
+ case SUPPORT_PDF:
+ return (BOOL) GetCapabilities( PRINTER_CAPABILITIES_PDF );
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetJobSetup( const JobSetup& rSetup )
+{
+ if ( IsDisplayPrinter() || mbInPrintPage )
+ return FALSE;
+
+ JobSetup aJobSetup = rSetup;
+
+ ImplReleaseGraphics();
+ if ( mpInfoPrinter->SetPrinterData( aJobSetup.ImplGetData() ) )
+ {
+ ImplUpdateJobSetupPaper( aJobSetup );
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ ImplUpdatePageData();
+ ImplUpdateFontList();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+
+BOOL Printer::Setup( Window* pWindow )
+{
+ if ( IsDisplayPrinter() )
+ return FALSE;
+
+ if ( IsJobActive() || IsPrinting() )
+ return FALSE;
+
+ JobSetup aJobSetup = maJobSetup;
+ SalFrame* pFrame;
+ if ( !pWindow )
+ pWindow = ImplGetDefaultWindow();
+ if( !pWindow )
+ return FALSE;
+
+ pFrame = pWindow->ImplGetFrame();
+ ImplReleaseGraphics();
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mnModalMode++;
+ nImplSysDialog++;
+ BOOL bSetup = mpInfoPrinter->Setup( pFrame, aJobSetup.ImplGetData() );
+ pSVData->maAppData.mnModalMode--;
+ nImplSysDialog--;
+ if ( bSetup )
+ {
+ ImplUpdateJobSetupPaper( aJobSetup );
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ ImplUpdatePageData();
+ ImplUpdateFontList();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetPrinterProps( const Printer* pPrinter )
+{
+ if ( IsJobActive() || IsPrinting() )
+ return FALSE;
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ mbDefPrinter = pPrinter->mbDefPrinter;
+ maPrintFile = pPrinter->maPrintFile;
+ mbPrintFile = pPrinter->mbPrintFile;
+ mnCopyCount = pPrinter->mnCopyCount;
+ mbCollateCopy = pPrinter->mbCollateCopy;
+ mnPageQueueSize = pPrinter->mnPageQueueSize;
+ *mpPrinterOptions = *pPrinter->mpPrinterOptions;
+
+ if ( pPrinter->IsDisplayPrinter() )
+ {
+ // Alten Printer zerstoeren
+ if ( !IsDisplayPrinter() )
+ {
+ ImplReleaseGraphics();
+ pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
+ if ( mpFontEntry )
+ {
+ mpFontCache->Release( mpFontEntry );
+ mpFontEntry = NULL;
+ }
+ if ( mpGetDevFontList )
+ {
+ delete mpGetDevFontList;
+ mpGetDevFontList = NULL;
+ }
+ if ( mpGetDevSizeList )
+ {
+ delete mpGetDevSizeList;
+ mpGetDevSizeList = NULL;
+ }
+ // clean up font list
+ delete mpFontCache;
+ delete mpFontList;
+ mpFontCache = NULL;
+ mpFontList = NULL;
+
+ mbInitFont = TRUE;
+ mbNewFont = TRUE;
+ mpInfoPrinter = NULL;
+ }
+
+ // Neuen Printer bauen
+ ImplInitDisplay( NULL );
+ return TRUE;
+ }
+
+ // Alten Printer zerstoeren?
+ if ( GetName() != pPrinter->GetName() )
+ {
+ ImplReleaseGraphics();
+ if ( mpDisplayDev )
+ {
+ delete mpDisplayDev;
+ mpDisplayDev = NULL;
+ }
+ else
+ {
+ pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
+
+ if ( mpFontEntry )
+ {
+ mpFontCache->Release( mpFontEntry );
+ mpFontEntry = NULL;
+ }
+ if ( mpGetDevFontList )
+ {
+ delete mpGetDevFontList;
+ mpGetDevFontList = NULL;
+ }
+ if ( mpGetDevSizeList )
+ {
+ delete mpGetDevSizeList;
+ mpGetDevSizeList = NULL;
+ }
+ delete mpFontCache;
+ delete mpFontList;
+ mpFontCache = NULL;
+ mpFontList = NULL;
+ mbInitFont = TRUE;
+ mbNewFont = TRUE;
+ mpInfoPrinter = NULL;
+ }
+
+ // Neuen Printer bauen
+ XubString aDriver = pPrinter->GetDriverName();
+ SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver );
+ if ( pInfo )
+ {
+ ImplInit( pInfo );
+ SetJobSetup( pPrinter->GetJobSetup() );
+ }
+ else
+ ImplInitDisplay( NULL );
+ }
+ else
+ SetJobSetup( pPrinter->GetJobSetup() );
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetOrientation( Orientation eOrientation )
+{
+ if ( mbInPrintPage )
+ return FALSE;
+
+ if ( maJobSetup.ImplGetConstData()->meOrientation != eOrientation )
+ {
+ JobSetup aJobSetup = maJobSetup;
+ ImplJobSetup* pSetupData = aJobSetup.ImplGetData();
+ pSetupData->meOrientation = eOrientation;
+
+ if ( IsDisplayPrinter() )
+ {
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ return TRUE;
+ }
+
+ ImplReleaseGraphics();
+ if ( mpInfoPrinter->SetData( SAL_JOBSET_ORIENTATION, pSetupData ) )
+ {
+ ImplUpdateJobSetupPaper( aJobSetup );
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ ImplUpdatePageData();
+ ImplUpdateFontList();
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+Orientation Printer::GetOrientation() const
+{
+ return maJobSetup.ImplGetConstData()->meOrientation;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetPaperBin( USHORT nPaperBin )
+{
+ if ( mbInPrintPage )
+ return FALSE;
+
+ if ( (maJobSetup.ImplGetConstData()->mnPaperBin != nPaperBin) &&
+ (nPaperBin < GetPaperBinCount()) )
+ {
+ JobSetup aJobSetup = maJobSetup;
+ ImplJobSetup* pSetupData = aJobSetup.ImplGetData();
+ pSetupData->mnPaperBin = nPaperBin;
+
+ if ( IsDisplayPrinter() )
+ {
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ return TRUE;
+ }
+
+ ImplReleaseGraphics();
+ if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERBIN, pSetupData ) )
+ {
+ ImplUpdateJobSetupPaper( aJobSetup );
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ ImplUpdatePageData();
+ ImplUpdateFontList();
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Printer::GetPaperBin() const
+{
+ return maJobSetup.ImplGetConstData()->mnPaperBin;
+}
+
+// -----------------------------------------------------------------------
+
+// Map user paper format to a available printer paper formats
+void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup, bool bMatchNearest )
+{
+ ImplJobSetup* pSetupData = aJobSetup.ImplGetData();
+
+ int nLandscapeAngle = GetLandscapeAngle();
+ int nPaperCount = GetPaperInfoCount();
+ bool bFound = false;
+
+ PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight);
+
+ // Alle Papierformate vergleichen und ein passendes raussuchen
+ for ( int i = 0; i < nPaperCount; i++ )
+ {
+ const PaperInfo& rPaperInfo = GetPaperInfo( i );
+
+ if ( aInfo.sloppyEqual(rPaperInfo) )
+ {
+ pSetupData->mePaperFormat = ImplGetPaperFormat( rPaperInfo.getWidth(),
+ rPaperInfo.getHeight() );
+ pSetupData->meOrientation = ORIENTATION_PORTRAIT;
+ bFound = true;
+ break;
+ }
+ }
+
+ // If the printer supports landscape orientation, check paper sizes again
+ // with landscape orientation. This is necessary as a printer driver provides
+ // all paper sizes with portrait orientation only!!
+ if ( pSetupData->mePaperFormat == PAPER_USER &&
+ nLandscapeAngle != 0 &&
+ HasSupport( SUPPORT_SET_ORIENTATION ))
+ {
+
+ PaperInfo aRotatedInfo(pSetupData->mnPaperHeight, pSetupData->mnPaperWidth);
+
+ for ( int i = 0; i < nPaperCount; i++ )
+ {
+ const PaperInfo& rPaperInfo = GetPaperInfo( i );
+
+ if ( aRotatedInfo.sloppyEqual( rPaperInfo ) )
+ {
+ pSetupData->mePaperFormat = ImplGetPaperFormat( rPaperInfo.getWidth(),
+ rPaperInfo.getHeight() );
+ pSetupData->meOrientation = ORIENTATION_LANDSCAPE;
+ bFound = true;
+ break;
+ }
+ }
+ }
+
+ if( ! bFound && bMatchNearest )
+ {
+ sal_Int64 nBestMatch = SAL_MAX_INT64;
+ int nBestIndex = 0;
+ Orientation eBestOrientation = ORIENTATION_PORTRAIT;
+ for( int i = 0; i < nPaperCount; i++ )
+ {
+ const PaperInfo& rPaperInfo = GetPaperInfo( i );
+
+ // check protrait match
+ sal_Int64 nDX = pSetupData->mnPaperWidth - rPaperInfo.getWidth();
+ sal_Int64 nDY = pSetupData->mnPaperHeight - rPaperInfo.getHeight();
+ sal_Int64 nMatch = nDX*nDX + nDY*nDY;
+ if( nMatch < nBestMatch )
+ {
+ nBestMatch = nMatch;
+ nBestIndex = i;
+ eBestOrientation = ORIENTATION_PORTRAIT;
+ }
+
+ // check landscape match
+ nDX = pSetupData->mnPaperWidth - rPaperInfo.getHeight();
+ nDY = pSetupData->mnPaperHeight - rPaperInfo.getWidth();
+ nMatch = nDX*nDX + nDY*nDY;
+ if( nMatch < nBestMatch )
+ {
+ nBestMatch = nMatch;
+ nBestIndex = i;
+ eBestOrientation = ORIENTATION_LANDSCAPE;
+ }
+ }
+ const PaperInfo& rBestInfo = GetPaperInfo( nBestIndex );
+ pSetupData->mePaperFormat = ImplGetPaperFormat( rBestInfo.getWidth(),
+ rBestInfo.getHeight() );
+ pSetupData->meOrientation = eBestOrientation;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetPaper( Paper ePaper )
+{
+ if ( mbInPrintPage )
+ return FALSE;
+
+ if ( maJobSetup.ImplGetConstData()->mePaperFormat != ePaper )
+ {
+ JobSetup aJobSetup = maJobSetup;
+ ImplJobSetup* pSetupData = aJobSetup.ImplGetData();
+ pSetupData->mePaperFormat = ePaper;
+ if ( ePaper != PAPER_USER )
+ {
+ PaperInfo aInfo(ePaper);
+ pSetupData->mnPaperWidth = aInfo.getWidth();
+ pSetupData->mnPaperHeight = aInfo.getHeight();
+ }
+
+ if ( IsDisplayPrinter() )
+ {
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ return TRUE;
+ }
+
+ ImplReleaseGraphics();
+ if ( ePaper == PAPER_USER )
+ ImplFindPaperFormatForUserSize( aJobSetup, false );
+ if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE|SAL_JOBSET_ORIENTATION, pSetupData ) )
+ {
+ ImplUpdateJobSetupPaper( aJobSetup );
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ ImplUpdatePageData();
+ ImplUpdateFontList();
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetPaperSizeUser( const Size& rSize )
+{
+ return SetPaperSizeUser( rSize, false );
+}
+
+BOOL Printer::SetPaperSizeUser( const Size& rSize, bool bMatchNearest )
+{
+ if ( mbInPrintPage )
+ return FALSE;
+
+ Size aPixSize = LogicToPixel( rSize );
+ Size aPageSize = PixelToLogic( aPixSize, MAP_100TH_MM );
+ if ( (maJobSetup.ImplGetConstData()->mePaperFormat != PAPER_USER) ||
+ (maJobSetup.ImplGetConstData()->mnPaperWidth != aPageSize.Width()) ||
+ (maJobSetup.ImplGetConstData()->mnPaperHeight != aPageSize.Height()) )
+ {
+ JobSetup aJobSetup = maJobSetup;
+ ImplJobSetup* pSetupData = aJobSetup.ImplGetData();
+ pSetupData->mePaperFormat = PAPER_USER;
+ pSetupData->mnPaperWidth = aPageSize.Width();
+ pSetupData->mnPaperHeight = aPageSize.Height();
+
+ if ( IsDisplayPrinter() )
+ {
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ return TRUE;
+ }
+
+ ImplReleaseGraphics();
+ ImplFindPaperFormatForUserSize( aJobSetup, bMatchNearest );
+
+ // Changing the paper size can also change the orientation!
+ if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE|SAL_JOBSET_ORIENTATION, pSetupData ) )
+ {
+ ImplUpdateJobSetupPaper( aJobSetup );
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ ImplUpdatePageData();
+ ImplUpdateFontList();
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+int Printer::GetPaperInfoCount() const
+{
+ if( ! mpInfoPrinter )
+ return 0;
+ if( ! mpInfoPrinter->m_bPapersInit )
+ mpInfoPrinter->InitPaperFormats( maJobSetup.ImplGetConstData() );
+ return mpInfoPrinter->m_aPaperFormats.size();
+}
+
+// -----------------------------------------------------------------------
+
+const PaperInfo& Printer::GetPaperInfo( int nPaper ) const
+{
+ if( ! mpInfoPrinter )
+ return ImplGetEmptyPaper();
+ if( ! mpInfoPrinter->m_bPapersInit )
+ mpInfoPrinter->InitPaperFormats( maJobSetup.ImplGetConstData() );
+ if( mpInfoPrinter->m_aPaperFormats.empty() || nPaper < 0 || nPaper >= int(mpInfoPrinter->m_aPaperFormats.size()) )
+ return ImplGetEmptyPaper();
+ return mpInfoPrinter->m_aPaperFormats[nPaper];
+}
+
+// -----------------------------------------------------------------------
+
+DuplexMode Printer::GetDuplexMode() const
+{
+ return maJobSetup.ImplGetConstData()->meDuplexMode;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetDuplexMode( DuplexMode eDuplex )
+{
+ if ( mbInPrintPage )
+ return FALSE;
+
+ if ( maJobSetup.ImplGetConstData()->meDuplexMode != eDuplex )
+ {
+ JobSetup aJobSetup = maJobSetup;
+ ImplJobSetup* pSetupData = aJobSetup.ImplGetData();
+ pSetupData->meDuplexMode = eDuplex;
+
+ if ( IsDisplayPrinter() )
+ {
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ return TRUE;
+ }
+
+ ImplReleaseGraphics();
+ if ( mpInfoPrinter->SetData( SAL_JOBSET_DUPLEXMODE, pSetupData ) )
+ {
+ ImplUpdateJobSetupPaper( aJobSetup );
+ mbNewJobSetup = TRUE;
+ maJobSetup = aJobSetup;
+ ImplUpdatePageData();
+ ImplUpdateFontList();
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+int Printer::GetLandscapeAngle() const
+{
+ return mpInfoPrinter ? mpInfoPrinter->GetLandscapeAngle( maJobSetup.ImplGetConstData() ) : 900;
+}
+
+// -----------------------------------------------------------------------
+
+Paper Printer::GetPaper() const
+{
+ return maJobSetup.ImplGetConstData()->mePaperFormat;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Printer::GetPaperBinCount() const
+{
+ if ( IsDisplayPrinter() )
+ return 0;
+
+ return (USHORT)mpInfoPrinter->GetPaperBinCount( maJobSetup.ImplGetConstData() );
+}
+
+// -----------------------------------------------------------------------
+
+XubString Printer::GetPaperBinName( USHORT nPaperBin ) const
+{
+ if ( IsDisplayPrinter() )
+ return ImplGetSVEmptyStr();
+
+ if ( nPaperBin < GetPaperBinCount() )
+ return mpInfoPrinter->GetPaperBinName( maJobSetup.ImplGetConstData(), nPaperBin );
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::SetCopyCount( USHORT nCopy, BOOL bCollate )
+{
+ mnCopyCount = nCopy;
+ mbCollateCopy = bCollate;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::Error()
+{
+ maErrorHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+
+ULONG Printer::ImplSalPrinterErrorCodeToVCL( ULONG nError )
+{
+ ULONG nVCLError;
+ switch ( nError )
+ {
+ case 0:
+ nVCLError = PRINTER_OK;
+ break;
+ case SAL_PRINTER_ERROR_ABORT:
+ nVCLError = PRINTER_ABORT;
+ break;
+ default:
+ nVCLError = PRINTER_GENERALERROR;
+ break;
+ }
+
+ return nVCLError;
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::ImplEndPrint()
+{
+ mbPrinting = FALSE;
+ mnCurPrintPage = 0;
+ maJobName.Erase();
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Printer, ImplDestroyPrinterAsync, void*, pSalPrinter )
+{
+ SalPrinter* pPrinter = (SalPrinter*)pSalPrinter;
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpDefInst->DestroyPrinter( pPrinter );
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::EndJob()
+{
+ BOOL bRet = FALSE;
+ if ( !IsJobActive() )
+ return bRet;
+
+ DBG_ASSERT( !mbInPrintPage, "Printer::EndJob() - StartPage() without EndPage() called" );
+
+ mbJobActive = FALSE;
+
+ if ( mpPrinter )
+ {
+ ImplReleaseGraphics();
+
+ mnCurPage = 0;
+
+ bRet = TRUE;
+
+ mbPrinting = FALSE;
+ mnCurPrintPage = 0;
+ maJobName.Erase();
+
+ mbDevOutput = FALSE;
+ bRet = mpPrinter->EndJob();
+ // Hier den Drucker nicht asyncron zerstoeren, da es
+ // W95 nicht verkraftet, wenn gleichzeitig gedruckt wird
+ // und ein Druckerobjekt zerstoert wird
+ ImplGetSVData()->mpDefInst->DestroyPrinter( mpPrinter );
+ mpPrinter = NULL;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Printer::AbortJob()
+{
+ // Wenn wir einen Queue-Printer haben, kann man diesen noch mit
+ // AbortJob() abbrechen, solange dieser noch am Drucken ist
+ if ( !IsJobActive() && !IsPrinting() )
+ return FALSE;
+
+ mbJobActive = FALSE;
+ mbInPrintPage = FALSE;
+ mpJobGraphics = NULL;
+
+ if ( mpPrinter )
+ {
+ mbPrinting = FALSE;
+ mnCurPage = 0;
+ mnCurPrintPage = 0;
+ maJobName.Erase();
+
+ ImplReleaseGraphics();
+ mbDevOutput = FALSE;
+ mpPrinter->AbortJob();
+ Application::PostUserEvent( LINK( this, Printer, ImplDestroyPrinterAsync ), mpPrinter );
+ mpPrinter = NULL;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::ImplStartPage()
+{
+ if ( !IsJobActive() )
+ return;
+
+ if ( mpPrinter )
+ {
+ SalGraphics* pGraphics = mpPrinter->StartPage( maJobSetup.ImplGetConstData(), mbNewJobSetup );
+ if ( pGraphics )
+ {
+ ImplReleaseGraphics();
+ mpJobGraphics = pGraphics;
+ }
+ mbDevOutput = TRUE;
+
+ // PrintJob not aborted ???
+ if ( IsJobActive() )
+ {
+ mbInPrintPage = TRUE;
+ mnCurPage++;
+ mnCurPrintPage++;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::ImplEndPage()
+{
+ if ( !IsJobActive() )
+ return;
+
+ mbInPrintPage = FALSE;
+
+ if ( mpPrinter )
+ {
+ mpPrinter->EndPage();
+ ImplReleaseGraphics();
+ mbDevOutput = FALSE;
+
+ mpJobGraphics = NULL;
+ mbNewJobSetup = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Printer::updatePrinters()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList;
+
+ if ( pPrnList )
+ {
+ ImplPrnQueueList* pNewList = new ImplPrnQueueList;
+ pSVData->mpDefInst->GetPrinterQueueInfo( pNewList );
+
+ bool bChanged = pPrnList->m_aQueueInfos.size() != pNewList->m_aQueueInfos.size();
+ for( unsigned int i = 0; ! bChanged && i < pPrnList->m_aQueueInfos.size(); i++ )
+ {
+ ImplPrnQueueData& rInfo = pPrnList->m_aQueueInfos[i];
+ ImplPrnQueueData& rNewInfo = pNewList->m_aQueueInfos[i];
+ if( ! rInfo.mpSalQueueInfo || ! rNewInfo.mpSalQueueInfo || // sanity check
+ rInfo.mpSalQueueInfo->maPrinterName != rNewInfo.mpSalQueueInfo->maPrinterName )
+ {
+ bChanged = true;
+ }
+ }
+ if( bChanged )
+ {
+ ImplDeletePrnQueueList();
+ pSVData->maGDIData.mpPrinterQueueList = pNewList;
+
+ Application* pApp = GetpApp();
+ if( pApp )
+ {
+ DataChangedEvent aDCEvt( DATACHANGED_PRINTER );
+ pApp->DataChanged( aDCEvt );
+ pApp->NotifyAllWindows( aDCEvt );
+ }
+ }
+ else
+ delete pNewList;
+ }
+}
diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx
new file mode 100644
index 000000000000..d560b0b6e7cc
--- /dev/null
+++ b/vcl/source/gdi/print2.cxx
@@ -0,0 +1,1570 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <functional>
+#include <algorithm>
+#include <utility>
+#include <list>
+#include <vector>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <tools/debug.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/print.h>
+#include <vcl/salbtype.hxx>
+#include <vcl/print.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/sallayout.hxx>
+#include <vcl/bmpacc.hxx>
+
+#include "pdfwriter_impl.hxx"
+
+// -----------
+// - Defines -
+// -----------
+
+#define MAX_TILE_WIDTH 1024
+#define MAX_TILE_HEIGHT 1024
+
+// ---------
+// - Types -
+// ---------
+
+typedef ::std::pair< MetaAction*, int > Component; // MetaAction plus index in metafile
+
+typedef ::std::list< Component > ComponentList;
+
+// List of (intersecting) actions, plus overall bounds
+struct ConnectedComponents
+{
+ ConnectedComponents() :
+ aComponentList(),
+ aBounds(),
+ aBgColor(COL_WHITE),
+ bIsSpecial(false),
+ bIsFullyTransparent(false)
+ {}
+
+ ComponentList aComponentList;
+ Rectangle aBounds;
+ Color aBgColor;
+ bool bIsSpecial;
+ bool bIsFullyTransparent;
+};
+
+typedef ::std::list< ConnectedComponents > ConnectedComponentsList;
+
+
+// -----------
+// - Printer -
+// -----------
+
+/** #i10613# Extracted from Printer::GetPreparedMetaFile. Returns true
+ if given action requires special handling (usually because of
+ transparency)
+*/
+static bool ImplIsActionSpecial( const MetaAction& rAct )
+{
+ switch( rAct.GetType() )
+ {
+ case META_TRANSPARENT_ACTION:
+ return true;
+
+ case META_FLOATTRANSPARENT_ACTION:
+ return true;
+
+ case META_BMPEX_ACTION:
+ return static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx().IsTransparent();
+
+ case META_BMPEXSCALE_ACTION:
+ return static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx().IsTransparent();
+
+ case META_BMPEXSCALEPART_ACTION:
+ return static_cast<const MetaBmpExScalePartAction&>(rAct).GetBitmapEx().IsTransparent();
+
+ default:
+ return false;
+ }
+}
+
+/** Check whether rCurrRect rectangle fully covers io_rPrevRect - if
+ yes, return true and update o_rBgColor
+ */
+static bool checkRect( Rectangle& io_rPrevRect,
+ Color& o_rBgColor,
+ const Rectangle& rCurrRect,
+ OutputDevice& rMapModeVDev )
+{
+ // shape needs to fully cover previous content, and have uniform
+ // color
+ const bool bRet(
+ rMapModeVDev.LogicToPixel(rCurrRect).IsInside(io_rPrevRect) &&
+ rMapModeVDev.IsFillColor() );
+
+ if( bRet )
+ {
+ io_rPrevRect = rCurrRect;
+ o_rBgColor = rMapModeVDev.GetFillColor();
+ }
+
+ return bRet;
+}
+
+/** #107169# Convert BitmapEx to Bitmap with appropriately blended
+ color. Convert MetaTransparentAction to plain polygon,
+ appropriately colored
+
+ @param o_rMtf
+ Add converted actions to this metafile
+*/
+static void ImplConvertTransparentAction( GDIMetaFile& o_rMtf,
+ const MetaAction& rAct,
+ const OutputDevice& rStateOutDev,
+ Color aBgColor )
+{
+ if( rAct.GetType() == META_TRANSPARENT_ACTION )
+ {
+ const MetaTransparentAction* pTransAct = static_cast<const MetaTransparentAction*>(&rAct);
+ USHORT nTransparency( pTransAct->GetTransparence() );
+
+ // #i10613# Respect transparency for draw color
+ if( nTransparency )
+ {
+ o_rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR|PUSH_FILLCOLOR ) );
+
+ // assume white background for alpha blending
+ Color aLineColor( rStateOutDev.GetLineColor() );
+ aLineColor.SetRed( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetRed()) / 100L ) );
+ aLineColor.SetGreen( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetGreen()) / 100L ) );
+ aLineColor.SetBlue( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetBlue()) / 100L ) );
+ o_rMtf.AddAction( new MetaLineColorAction(aLineColor, TRUE) );
+
+ Color aFillColor( rStateOutDev.GetFillColor() );
+ aFillColor.SetRed( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetRed()) / 100L ) );
+ aFillColor.SetGreen( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetGreen()) / 100L ) );
+ aFillColor.SetBlue( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetBlue()) / 100L ) );
+ o_rMtf.AddAction( new MetaFillColorAction(aFillColor, TRUE) );
+ }
+
+ o_rMtf.AddAction( new MetaPolyPolygonAction(pTransAct->GetPolyPolygon()) );
+
+ if( nTransparency )
+ o_rMtf.AddAction( new MetaPopAction() );
+ }
+ else
+ {
+ BitmapEx aBmpEx;
+
+ switch( rAct.GetType() )
+ {
+ case META_BMPEX_ACTION:
+ aBmpEx = static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx();
+ break;
+
+ case META_BMPEXSCALE_ACTION:
+ aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
+ break;
+
+ case META_BMPEXSCALEPART_ACTION:
+ aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
+ break;
+
+ case META_TRANSPARENT_ACTION:
+
+ default:
+ DBG_ERROR("Printer::GetPreparedMetafile impossible state reached");
+ break;
+ }
+
+ Bitmap aBmp( aBmpEx.GetBitmap() );
+ if( !aBmpEx.IsAlpha() )
+ {
+ // blend with mask
+ BitmapReadAccess* pRA = aBmp.AcquireReadAccess();
+
+ if( !pRA )
+ return; // what else should I do?
+
+ Color aActualColor( aBgColor );
+
+ if( pRA->HasPalette() )
+ aActualColor = pRA->GetBestPaletteColor( aBgColor ).operator Color();
+
+ aBmp.ReleaseAccess(pRA);
+
+ // did we get true white?
+ if( aActualColor.GetColorError( aBgColor ) )
+ {
+ // no, create truecolor bitmap, then
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+
+ // fill masked out areas white
+ aBmp.Replace( aBmpEx.GetMask(), aBgColor );
+ }
+ else
+ {
+ // fill masked out areas white
+ aBmp.Replace( aBmpEx.GetMask(), aActualColor );
+ }
+ }
+ else
+ {
+ // blend with alpha channel
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+ aBmp.Blend(aBmpEx.GetAlpha(),aBgColor);
+ }
+
+ // add corresponding action
+ switch( rAct.GetType() )
+ {
+ case META_BMPEX_ACTION:
+ o_rMtf.AddAction( new MetaBmpAction(
+ static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
+ aBmp ));
+ break;
+ case META_BMPEXSCALE_ACTION:
+ o_rMtf.AddAction( new MetaBmpScaleAction(
+ static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
+ static_cast<const MetaBmpExScaleAction&>(rAct).GetSize(),
+ aBmp ));
+ break;
+ case META_BMPEXSCALEPART_ACTION:
+ o_rMtf.AddAction( new MetaBmpScalePartAction(
+ static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
+ static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize(),
+ static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcPoint(),
+ static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcSize(),
+ aBmp ));
+ break;
+ default:
+ DBG_ERROR("Unexpected case");
+ break;
+ }
+ }
+}
+
+// #i10613# Extracted from ImplCheckRect::ImplCreate
+// Returns true, if given action creates visible (i.e. non-transparent) output
+static bool ImplIsNotTransparent( const MetaAction& rAct, const OutputDevice& rOut )
+{
+ const bool bLineTransparency( rOut.IsLineColor() ? rOut.GetLineColor().GetTransparency() == 255 : true );
+ const bool bFillTransparency( rOut.IsFillColor() ? rOut.GetFillColor().GetTransparency() == 255 : true );
+ bool bRet( false );
+
+ switch( rAct.GetType() )
+ {
+ case META_POINT_ACTION:
+ if( !bLineTransparency )
+ bRet = true;
+ break;
+
+ case META_LINE_ACTION:
+ if( !bLineTransparency )
+ bRet = true;
+ break;
+
+ case META_RECT_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_ROUNDRECT_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_ELLIPSE_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_ARC_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_PIE_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_CHORD_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_POLYLINE_ACTION:
+ if( !bLineTransparency )
+ bRet = true;
+ break;
+
+ case META_POLYGON_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_POLYPOLYGON_ACTION:
+ if( !bLineTransparency || !bFillTransparency )
+ bRet = true;
+ break;
+
+ case META_TEXT_ACTION:
+ {
+ const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
+ const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
+
+ if( aString.Len() )
+ bRet = true;
+ }
+ break;
+
+ case META_TEXTARRAY_ACTION:
+ {
+ const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
+ const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
+
+ if( aString.Len() )
+ bRet = true;
+ }
+ break;
+
+ case META_PIXEL_ACTION:
+ case META_BMP_ACTION:
+ case META_BMPSCALE_ACTION:
+ case META_BMPSCALEPART_ACTION:
+ case META_BMPEX_ACTION:
+ case META_BMPEXSCALE_ACTION:
+ case META_BMPEXSCALEPART_ACTION:
+ case META_MASK_ACTION:
+ case META_MASKSCALE_ACTION:
+ case META_MASKSCALEPART_ACTION:
+ case META_GRADIENT_ACTION:
+ case META_GRADIENTEX_ACTION:
+ case META_HATCH_ACTION:
+ case META_WALLPAPER_ACTION:
+ case META_TRANSPARENT_ACTION:
+ case META_FLOATTRANSPARENT_ACTION:
+ case META_EPS_ACTION:
+ case META_TEXTRECT_ACTION:
+ case META_STRETCHTEXT_ACTION:
+ case META_TEXTLINE_ACTION:
+ // all other actions: generate non-transparent output
+ bRet = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return bRet;
+}
+
+// #i10613# Extracted from ImplCheckRect::ImplCreate
+static Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevice& rOut )
+{
+ Rectangle aActionBounds;
+
+ switch( rAct.GetType() )
+ {
+ case META_PIXEL_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaPixelAction&>(rAct).GetPoint(), Size( 1, 1 ) );
+ break;
+
+ case META_POINT_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaPointAction&>(rAct).GetPoint(), Size( 1, 1 ) );
+ break;
+
+ case META_LINE_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaLineAction&>(rAct).GetStartPoint(),
+ static_cast<const MetaLineAction&>(rAct).GetEndPoint() );
+ break;
+
+ case META_RECT_ACTION:
+ aActionBounds = static_cast<const MetaRectAction&>(rAct).GetRect();
+ break;
+
+ case META_ROUNDRECT_ACTION:
+ aActionBounds = Polygon( static_cast<const MetaRoundRectAction&>(rAct).GetRect(),
+ static_cast<const MetaRoundRectAction&>(rAct).GetHorzRound(),
+ static_cast<const MetaRoundRectAction&>(rAct).GetVertRound() ).GetBoundRect();
+ break;
+
+ case META_ELLIPSE_ACTION:
+ {
+ const Rectangle& rRect = static_cast<const MetaEllipseAction&>(rAct).GetRect();
+ aActionBounds = Polygon( rRect.Center(),
+ rRect.GetWidth() >> 1,
+ rRect.GetHeight() >> 1 ).GetBoundRect();
+ break;
+ }
+
+ case META_ARC_ACTION:
+ aActionBounds = Polygon( static_cast<const MetaArcAction&>(rAct).GetRect(),
+ static_cast<const MetaArcAction&>(rAct).GetStartPoint(),
+ static_cast<const MetaArcAction&>(rAct).GetEndPoint(), POLY_ARC ).GetBoundRect();
+ break;
+
+ case META_PIE_ACTION:
+ aActionBounds = Polygon( static_cast<const MetaPieAction&>(rAct).GetRect(),
+ static_cast<const MetaPieAction&>(rAct).GetStartPoint(),
+ static_cast<const MetaPieAction&>(rAct).GetEndPoint(), POLY_PIE ).GetBoundRect();
+ break;
+
+ case META_CHORD_ACTION:
+ aActionBounds = Polygon( static_cast<const MetaChordAction&>(rAct).GetRect(),
+ static_cast<const MetaChordAction&>(rAct).GetStartPoint(),
+ static_cast<const MetaChordAction&>(rAct).GetEndPoint(), POLY_CHORD ).GetBoundRect();
+ break;
+
+ case META_POLYLINE_ACTION:
+ aActionBounds = static_cast<const MetaPolyLineAction&>(rAct).GetPolygon().GetBoundRect();
+ break;
+
+ case META_POLYGON_ACTION:
+ aActionBounds = static_cast<const MetaPolygonAction&>(rAct).GetPolygon().GetBoundRect();
+ break;
+
+ case META_POLYPOLYGON_ACTION:
+ aActionBounds = static_cast<const MetaPolyPolygonAction&>(rAct).GetPolyPolygon().GetBoundRect();
+ break;
+
+ case META_BMP_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaBmpAction&>(rAct).GetPoint(),
+ rOut.PixelToLogic( static_cast<const MetaBmpAction&>(rAct).GetBitmap().GetSizePixel() ) );
+ break;
+
+ case META_BMPSCALE_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaBmpScaleAction&>(rAct).GetPoint(),
+ static_cast<const MetaBmpScaleAction&>(rAct).GetSize() );
+ break;
+
+ case META_BMPSCALEPART_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaBmpScalePartAction&>(rAct).GetDestPoint(),
+ static_cast<const MetaBmpScalePartAction&>(rAct).GetDestSize() );
+ break;
+
+ case META_BMPEX_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
+ rOut.PixelToLogic( static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx().GetSizePixel() ) );
+ break;
+
+ case META_BMPEXSCALE_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
+ static_cast<const MetaBmpExScaleAction&>(rAct).GetSize() );
+ break;
+
+ case META_BMPEXSCALEPART_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
+ static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize() );
+ break;
+
+ case META_MASK_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaMaskAction&>(rAct).GetPoint(),
+ rOut.PixelToLogic( static_cast<const MetaMaskAction&>(rAct).GetBitmap().GetSizePixel() ) );
+ break;
+
+ case META_MASKSCALE_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaMaskScaleAction&>(rAct).GetPoint(),
+ static_cast<const MetaMaskScaleAction&>(rAct).GetSize() );
+ break;
+
+ case META_MASKSCALEPART_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaMaskScalePartAction&>(rAct).GetDestPoint(),
+ static_cast<const MetaMaskScalePartAction&>(rAct).GetDestSize() );
+ break;
+
+ case META_GRADIENT_ACTION:
+ aActionBounds = static_cast<const MetaGradientAction&>(rAct).GetRect();
+ break;
+
+ case META_GRADIENTEX_ACTION:
+ aActionBounds = static_cast<const MetaGradientExAction&>(rAct).GetPolyPolygon().GetBoundRect();
+ break;
+
+ case META_HATCH_ACTION:
+ aActionBounds = static_cast<const MetaHatchAction&>(rAct).GetPolyPolygon().GetBoundRect();
+ break;
+
+ case META_WALLPAPER_ACTION:
+ aActionBounds = static_cast<const MetaWallpaperAction&>(rAct).GetRect();
+ break;
+
+ case META_TRANSPARENT_ACTION:
+ aActionBounds = static_cast<const MetaTransparentAction&>(rAct).GetPolyPolygon().GetBoundRect();
+ break;
+
+ case META_FLOATTRANSPARENT_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaFloatTransparentAction&>(rAct).GetPoint(),
+ static_cast<const MetaFloatTransparentAction&>(rAct).GetSize() );
+ break;
+
+ case META_EPS_ACTION:
+ aActionBounds = Rectangle( static_cast<const MetaEPSAction&>(rAct).GetPoint(),
+ static_cast<const MetaEPSAction&>(rAct).GetSize() );
+ break;
+
+ case META_TEXT_ACTION:
+ {
+ const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
+ const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
+
+ if( aString.Len() )
+ {
+ const Point aPtLog( rTextAct.GetPoint() );
+
+ // #105987# Use API method instead of Impl* methods
+ // #107490# Set base parameter equal to index parameter
+ rOut.GetTextBoundRect( aActionBounds, rTextAct.GetText(), rTextAct.GetIndex(),
+ rTextAct.GetIndex(), rTextAct.GetLen() );
+ aActionBounds.Move( aPtLog.X(), aPtLog.Y() );
+ }
+ }
+ break;
+
+ case META_TEXTARRAY_ACTION:
+ {
+ const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
+ const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
+ const long nLen = aString.Len();
+
+ if( nLen )
+ {
+ // #105987# ImplLayout takes everything in logical coordinates
+ SalLayout* pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
+ rTextAct.GetLen(), rTextAct.GetPoint(),
+ 0, rTextAct.GetDXArray() );
+ if( pSalLayout )
+ {
+ Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
+ aActionBounds = rOut.PixelToLogic( aBoundRect );
+ pSalLayout->Release();
+ }
+ }
+ }
+ break;
+
+ case META_TEXTRECT_ACTION:
+ aActionBounds = static_cast<const MetaTextRectAction&>(rAct).GetRect();
+ break;
+
+ case META_STRETCHTEXT_ACTION:
+ {
+ const MetaStretchTextAction& rTextAct = static_cast<const MetaStretchTextAction&>(rAct);
+ const XubString aString( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen() );
+ const long nLen = aString.Len();
+
+ // #i16195# Literate copy from TextArray action, the
+ // semantics for the ImplLayout call are copied from the
+ // OutDev::DrawStretchText() code. Unfortunately, also in
+ // this case, public outdev methods such as GetTextWidth()
+ // don't provide enough info.
+ if( nLen )
+ {
+ // #105987# ImplLayout takes everything in logical coordinates
+ SalLayout* pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
+ rTextAct.GetLen(), rTextAct.GetPoint(),
+ rTextAct.GetWidth() );
+ if( pSalLayout )
+ {
+ Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
+ aActionBounds = rOut.PixelToLogic( aBoundRect );
+ pSalLayout->Release();
+ }
+ }
+ }
+ break;
+
+ case META_TEXTLINE_ACTION:
+ DBG_ERROR("META_TEXTLINE_ACTION not supported");
+ break;
+
+ default:
+ break;
+ }
+
+ if( !aActionBounds.IsEmpty() )
+ return rOut.LogicToPixel( aActionBounds );
+ else
+ return Rectangle();
+}
+
+static bool ImplIsActionHandlingTransparency( const MetaAction& rAct )
+{
+ // META_FLOATTRANSPARENT_ACTION can contain a whole metafile,
+ // which is to be rendered with the given transparent gradient. We
+ // currently cannot emulate transparent painting on a white
+ // background reliably.
+
+ // the remainder can handle printing itself correctly on a uniform
+ // white background.
+ switch( rAct.GetType() )
+ {
+ case META_TRANSPARENT_ACTION:
+ case META_BMPEX_ACTION:
+ case META_BMPEXSCALE_ACTION:
+ case META_BMPEXSCALEPART_ACTION:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// remove comment to enable highlighting of generated output
+bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf,
+ long nMaxBmpDPIX, long nMaxBmpDPIY,
+ bool bReduceTransparency, bool bTransparencyAutoMode,
+ bool bDownsampleBitmaps,
+ const Color& rBackground
+ )
+{
+ MetaAction* pCurrAct;
+ bool bTransparent( false );
+
+ rOutMtf.Clear();
+
+ if( ! bReduceTransparency || bTransparencyAutoMode )
+ {
+ // watch for transparent drawing actions
+ for( pCurrAct = ( (GDIMetaFile&) rInMtf ).FirstAction();
+ pCurrAct && !bTransparent;
+ pCurrAct = ( (GDIMetaFile&) rInMtf ).NextAction() )
+ {
+ // #i10613# Extracted "specialness" predicate into extra method
+
+ // #107169# Also examine metafiles with masked bitmaps in
+ // detail. Further down, this is optimized in such a way
+ // that there's no unnecessary painting of masked bitmaps
+ // (which are _always_ subdivided into rectangular regions
+ // of uniform opacity): if a masked bitmap is printed over
+ // empty background, we convert to a plain bitmap with
+ // white background.
+ if( ImplIsActionSpecial( *pCurrAct ) )
+ {
+ bTransparent = true;
+ }
+ }
+ }
+
+ // #i10613# Determine set of connected components containing transparent objects. These are
+ // then processed as bitmaps, the original actions are removed from the metafile.
+ if( !bTransparent )
+ {
+ // nothing transparent -> just copy
+ rOutMtf = rInMtf;
+ }
+ else
+ {
+ // #i10613#
+ // This works as follows: we want a number of distinct sets of
+ // connected components, where each set contains metafile
+ // actions that are intersecting (note: there are possibly
+ // more actions contained as are directly intersecting,
+ // because we can only produce rectangular bitmaps later
+ // on. Thus, each set of connected components is the smallest
+ // enclosing, axis-aligned rectangle that completely bounds a
+ // number of intersecting metafile actions, plus any action
+ // that would otherwise be cut in two). Therefore, we
+ // iteratively add metafile actions from the original metafile
+ // to this connected components list (aCCList), by checking
+ // each element's bounding box against intersection with the
+ // metaaction at hand.
+ // All those intersecting elements are removed from aCCList
+ // and collected in a temporary list (aCCMergeList). After all
+ // elements have been checked, the aCCMergeList elements are
+ // merged with the metaaction at hand into one resulting
+ // connected component, with one big bounding box, and
+ // inserted into aCCList again.
+ // The time complexity of this algorithm is O(n^3), where n is
+ // the number of metafile actions, and it finds all distinct
+ // regions of rectangle-bounded connected components. This
+ // algorithm was designed by AF.
+ //
+
+ //
+ // STAGE 1: Detect background
+ // ==========================
+ //
+
+ // Receives uniform background content, and is _not_ merged
+ // nor checked for intersection against other aCCList elements
+ ConnectedComponents aBackgroundComponent;
+
+ // create an OutputDevice to record mapmode changes and the like
+ VirtualDevice aMapModeVDev;
+ aMapModeVDev.mnDPIX = mnDPIX;
+ aMapModeVDev.mnDPIY = mnDPIY;
+ aMapModeVDev.EnableOutput(FALSE);
+
+ int nLastBgAction, nActionNum;
+
+ // weed out page-filling background objects (if they are
+ // uniformly coloured). Keeping them outside the other
+ // connected components often prevents whole-page bitmap
+ // generation.
+ bool bStillBackground=true; // true until first non-bg action
+ nActionNum=0; nLastBgAction=-1;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
+ if( rBackground != Color( COL_TRANSPARENT ) )
+ {
+ aBackgroundComponent.aBgColor = rBackground;
+ if( meOutDevType == OUTDEV_PRINTER )
+ {
+ Printer* pThis = dynamic_cast<Printer*>(this);
+ Point aPageOffset = pThis->GetPageOffsetPixel();
+ aPageOffset = Point( 0, 0 ) - aPageOffset;
+ Size aSize = pThis->GetPaperSizePixel();
+ aBackgroundComponent.aBounds = Rectangle( aPageOffset, aSize );
+ }
+ else
+ aBackgroundComponent.aBounds = Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
+ }
+ while( pCurrAct && bStillBackground )
+ {
+ switch( pCurrAct->GetType() )
+ {
+ case META_RECT_ACTION:
+ {
+ if( !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ static_cast<const MetaRectAction*>(pCurrAct)->GetRect(),
+ aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
+ }
+ case META_POLYGON_ACTION:
+ {
+ const Polygon aPoly(
+ static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
+ if( !basegfx::tools::isRectangle(
+ aPoly.getB2DPolygon()) ||
+ !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ aPoly.GetBoundRect(),
+ aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
+ }
+ case META_POLYPOLYGON_ACTION:
+ {
+ const PolyPolygon aPoly(
+ static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
+ if( aPoly.Count() != 1 ||
+ !basegfx::tools::isRectangle(
+ aPoly[0].getB2DPolygon()) ||
+ !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ aPoly.GetBoundRect(),
+ aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
+ }
+ case META_WALLPAPER_ACTION:
+ {
+ if( !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect(),
+ aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
+ }
+ default:
+ {
+ if( ImplIsNotTransparent( *pCurrAct,
+ aMapModeVDev ) )
+ bStillBackground=false; // non-transparent action, possibly
+ // not uniform
+ else
+ // extend current bounds (next uniform action
+ // needs to fully cover this area)
+ aBackgroundComponent.aBounds.Union(
+ ImplCalcActionBounds(*pCurrAct, aMapModeVDev) );
+ break;
+ }
+ }
+
+ // execute action to get correct MapModes etc.
+ pCurrAct->Execute( &aMapModeVDev );
+
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
+ ++nActionNum;
+ }
+
+ ConnectedComponentsList aCCList; // list containing distinct sets of connected components as elements.
+
+ // create an OutputDevice to record mapmode changes and the like
+ VirtualDevice aMapModeVDev2;
+ aMapModeVDev2.mnDPIX = mnDPIX;
+ aMapModeVDev2.mnDPIY = mnDPIY;
+ aMapModeVDev2.EnableOutput(FALSE);
+
+ // fast-forward until one after the last background action
+ // (need to reconstruct map mode vdev state)
+ nActionNum=0;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
+ while( pCurrAct && nActionNum<=nLastBgAction )
+ {
+ // up to and including last ink-generating background
+ // action go to background component
+ aBackgroundComponent.aComponentList.push_back(
+ ::std::make_pair(
+ pCurrAct, nActionNum) );
+
+ // execute action to get correct MapModes etc.
+ pCurrAct->Execute( &aMapModeVDev2 );
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
+ ++nActionNum;
+ }
+
+ //
+ // STAGE 2: Generate connected components list
+ // ===========================================
+ //
+
+ // iterate over all actions (start where background action
+ // search left off)
+ for( ;
+ pCurrAct;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
+ {
+ // execute action to get correct MapModes etc.
+ pCurrAct->Execute( &aMapModeVDev2 );
+
+ // cache bounds of current action
+ const Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, aMapModeVDev2) );
+
+ // accumulate collected bounds here, initialize with current action
+ Rectangle aTotalBounds( aBBCurrAct ); // thus,
+ // aTotalComponents.aBounds
+ // is
+ // empty
+ // for
+ // non-output-generating
+ // actions
+ bool bTreatSpecial( false );
+ ConnectedComponents aTotalComponents;
+
+ //
+ // STAGE 2.1: Search for intersecting cc entries
+ // =============================================
+ //
+
+ // if aBBCurrAct is empty, it will intersect with no
+ // aCCList member. Thus, we can save the check.
+ // Furthermore, this ensures that non-output-generating
+ // actions get their own aCCList entry, which is necessary
+ // when copying them to the output metafile (see stage 4
+ // below).
+
+ // #107169# Wholly transparent objects need
+ // not be considered for connected components,
+ // too. Just put each of them into a separate
+ // component.
+ aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, aMapModeVDev2);
+
+ if( !aBBCurrAct.IsEmpty() &&
+ !aTotalComponents.bIsFullyTransparent )
+ {
+ if( !aBackgroundComponent.aComponentList.empty() &&
+ !aBackgroundComponent.aBounds.IsInside(aTotalBounds) )
+ {
+ // it seems the background is not large enough. to
+ // be on the safe side, combine with this component.
+ aTotalBounds.Union( aBackgroundComponent.aBounds );
+
+ // extract all aCurr actions to aTotalComponents
+ aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
+ aBackgroundComponent.aComponentList );
+
+ if( aBackgroundComponent.bIsSpecial )
+ bTreatSpecial = true;
+ }
+
+ ConnectedComponentsList::iterator aCurrCC;
+ const ConnectedComponentsList::iterator aLastCC( aCCList.end() );
+ bool bSomeComponentsChanged;
+
+ // now, this is unfortunate: since changing anyone of
+ // the aCCList elements (e.g. by merging or addition
+ // of an action) might generate new intersection with
+ // other aCCList elements, have to repeat the whole
+ // element scanning, until nothing changes anymore.
+ // Thus, this loop here makes us O(n^3) in the worst
+ // case.
+ do
+ {
+ // only loop here if 'intersects' branch below was hit
+ bSomeComponentsChanged = false;
+
+ // iterate over all current members of aCCList
+ for( aCurrCC=aCCList.begin(); aCurrCC != aLastCC; )
+ {
+ // first check if current element's bounds are
+ // empty. This ensures that empty actions are not
+ // merged into one component, as a matter of fact,
+ // they have no position.
+
+ // #107169# Wholly transparent objects need
+ // not be considered for connected components,
+ // too. Just put each of them into a separate
+ // component.
+ if( !aCurrCC->aBounds.IsEmpty() &&
+ !aCurrCC->bIsFullyTransparent &&
+ aCurrCC->aBounds.IsOver( aTotalBounds ) )
+ {
+ // union the intersecting aCCList element into aTotalComponents
+
+ // calc union bounding box
+ aTotalBounds.Union( aCurrCC->aBounds );
+
+ // extract all aCurr actions to aTotalComponents
+ aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
+ aCurrCC->aComponentList );
+
+ if( aCurrCC->bIsSpecial )
+ bTreatSpecial = true;
+
+ // remove and delete aCurrCC element from list (we've now merged its content)
+ aCurrCC = aCCList.erase( aCurrCC );
+
+ // at least one component changed, need to rescan everything
+ bSomeComponentsChanged = true;
+ }
+ else
+ {
+ ++aCurrCC;
+ }
+ }
+ }
+ while( bSomeComponentsChanged );
+ }
+
+ //
+ // STAGE 2.2: Determine special state for cc element
+ // =================================================
+ //
+
+ // now test whether the whole connected component must be
+ // treated specially (i.e. rendered as a bitmap): if the
+ // added action is the very first action, or all actions
+ // before it are completely transparent, the connected
+ // component need not be treated specially, not even if
+ // the added action contains transparency. This is because
+ // painting of transparent objects on _white background_
+ // works without alpha compositing (you just calculate the
+ // color). Note that for the test "all objects before me
+ // are transparent" no sorting is necessary, since the
+ // added metaaction pCurrAct is always in the order the
+ // metafile is painted. Generally, the order of the
+ // metaactions in the ConnectedComponents are not
+ // guaranteed to be the same as in the metafile.
+ if( bTreatSpecial )
+ {
+ // prev component(s) special -> this one, too
+ aTotalComponents.bIsSpecial = true;
+ }
+ else if( !ImplIsActionSpecial( *pCurrAct ) )
+ {
+ // added action and none of prev components special ->
+ // this one normal, too
+ aTotalComponents.bIsSpecial = false;
+ }
+ else
+ {
+ // added action is special and none of prev components
+ // special -> do the detailed tests
+
+ // can the action handle transparency correctly
+ // (i.e. when painted on white background, does the
+ // action still look correct)?
+ if( !ImplIsActionHandlingTransparency( *pCurrAct ) )
+ {
+ // no, action cannot handle its transparency on
+ // a printer device, render to bitmap
+ aTotalComponents.bIsSpecial = true;
+ }
+ else
+ {
+ // yes, action can handle its transparency, so
+ // check whether we're on white background
+ if( aTotalComponents.aComponentList.empty() )
+ {
+ // nothing between pCurrAct and page
+ // background -> don't be special
+ aTotalComponents.bIsSpecial = false;
+ }
+ else
+ {
+ // #107169# Fixes abnove now ensure that _no_
+ // object in the list is fully transparent. Thus,
+ // if the component list is not empty above, we
+ // must assume that we have to treat this
+ // component special.
+
+ // there are non-transparent objects between
+ // pCurrAct and the empty sheet of paper -> be
+ // special, then
+ aTotalComponents.bIsSpecial = true;
+ }
+ }
+ }
+
+
+ //
+ // STAGE 2.3: Add newly generated CC list element
+ // ==============================================
+ //
+
+ // set new bounds and add action to list
+ aTotalComponents.aBounds = aTotalBounds;
+ aTotalComponents.aComponentList.push_back(
+ ::std::make_pair(
+ pCurrAct, nActionNum) );
+
+ // add aTotalComponents as a new entry to aCCList
+ aCCList.push_back( aTotalComponents );
+
+ DBG_ASSERT( !aTotalComponents.aComponentList.empty(),
+ "Printer::GetPreparedMetaFile empty component" );
+ DBG_ASSERT( !aTotalComponents.aBounds.IsEmpty() ||
+ (aTotalComponents.aBounds.IsEmpty() && aTotalComponents.aComponentList.size() == 1),
+ "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
+ DBG_ASSERT( !aTotalComponents.bIsFullyTransparent ||
+ (aTotalComponents.bIsFullyTransparent && aTotalComponents.aComponentList.size() == 1),
+ "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
+ }
+
+ // well now, we've got the list of disjunct connected
+ // components. Now we've got to create a map, which contains
+ // the corresponding aCCList element for every
+ // metaaction. Later on, we always process the complete
+ // metafile for each bitmap to be generated, but switch on
+ // output only for actions contained in the then current
+ // aCCList element. This ensures correct mapmode and attribute
+ // settings for all cases.
+
+ // maps mtf actions to CC list entries
+ ::std::vector< const ConnectedComponents* > aCCList_MemberMap( rInMtf.GetActionCount() );
+
+ // iterate over all aCCList members and their contained metaactions
+ ConnectedComponentsList::iterator aCurr( aCCList.begin() );
+ const ConnectedComponentsList::iterator aLast( aCCList.end() );
+ for( ; aCurr != aLast; ++aCurr )
+ {
+ ComponentList::iterator aCurrentAction( aCurr->aComponentList.begin() );
+ const ComponentList::iterator aLastAction( aCurr->aComponentList.end() );
+ for( ; aCurrentAction != aLastAction; ++aCurrentAction )
+ {
+ // set pointer to aCCList element for corresponding index
+ aCCList_MemberMap[ aCurrentAction->second ] = &(*aCurr);
+ }
+ }
+
+ //
+ // STAGE 3.1: Output background mtf actions (if there are any)
+ // ===========================================================
+ //
+
+ ComponentList::iterator aCurrAct( aBackgroundComponent.aComponentList.begin() );
+ const ComponentList::iterator aLastAct( aBackgroundComponent.aComponentList.end() );
+ for( ; aCurrAct != aLastAct; ++aCurrAct )
+ {
+ // simply add this action (above, we inserted the actions
+ // starting at index 0 up to and including nLastBgAction)
+ rOutMtf.AddAction( ( aCurrAct->first->Duplicate(), aCurrAct->first ) );
+ }
+
+
+ //
+ // STAGE 3.2: Generate banded bitmaps for special regions
+ // ====================================================
+ //
+
+ Point aPageOffset;
+ Size aTmpSize( GetOutputSizePixel() );
+ if( mpPDFWriter )
+ {
+ aTmpSize = mpPDFWriter->getCurPageSize();
+ aTmpSize = LogicToPixel( aTmpSize, MapMode( MAP_POINT ) );
+
+ // also add error code to PDFWriter
+ mpPDFWriter->insertError( vcl::PDFWriter::Warning_Transparency_Converted );
+ }
+ else if( meOutDevType == OUTDEV_PRINTER )
+ {
+ Printer* pThis = dynamic_cast<Printer*>(this);
+ aPageOffset = pThis->GetPageOffsetPixel();
+ aPageOffset = Point( 0, 0 ) - aPageOffset;
+ aTmpSize = pThis->GetPaperSizePixel();
+ }
+ const Rectangle aOutputRect( aPageOffset, aTmpSize );
+ bool bTiling = dynamic_cast<Printer*>(this) != NULL;
+
+ // iterate over all aCCList members and generate bitmaps for the special ones
+ for( aCurr = aCCList.begin(); aCurr != aLast; ++aCurr )
+ {
+ if( aCurr->bIsSpecial )
+ {
+ Rectangle aBoundRect( aCurr->aBounds );
+ aBoundRect.Intersection( aOutputRect );
+
+ const double fBmpArea( (double) aBoundRect.GetWidth() * aBoundRect.GetHeight() );
+ const double fOutArea( (double) aOutputRect.GetWidth() * aOutputRect.GetHeight() );
+
+ // check if output doesn't exceed given size
+ if( bReduceTransparency && bTransparencyAutoMode && ( fBmpArea > ( 0.25 * fOutArea ) ) )
+ {
+ // output normally. Therefore, we simply clear the
+ // special attribute, as everything non-special is
+ // copied to rOutMtf further below.
+ aCurr->bIsSpecial = false;
+ }
+ else
+ {
+ // create new bitmap action first
+ if( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
+ {
+ Point aDstPtPix( aBoundRect.TopLeft() );
+ Size aDstSzPix;
+
+ VirtualDevice aMapVDev; // here, we record only mapmode information
+ aMapVDev.EnableOutput(FALSE);
+
+ VirtualDevice aPaintVDev; // into this one, we render.
+
+ rOutMtf.AddAction( new MetaPushAction( PUSH_MAPMODE ) );
+ rOutMtf.AddAction( new MetaMapModeAction() );
+
+ aPaintVDev.SetDrawMode( GetDrawMode() );
+
+ while( aDstPtPix.Y() <= aBoundRect.Bottom() )
+ {
+ aDstPtPix.X() = aBoundRect.Left();
+ aDstSzPix = bTiling ? Size( MAX_TILE_WIDTH, MAX_TILE_HEIGHT ) : aBoundRect.GetSize();
+
+ if( ( aDstPtPix.Y() + aDstSzPix.Height() - 1L ) > aBoundRect.Bottom() )
+ aDstSzPix.Height() = aBoundRect.Bottom() - aDstPtPix.Y() + 1L;
+
+ while( aDstPtPix.X() <= aBoundRect.Right() )
+ {
+ if( ( aDstPtPix.X() + aDstSzPix.Width() - 1L ) > aBoundRect.Right() )
+ aDstSzPix.Width() = aBoundRect.Right() - aDstPtPix.X() + 1L;
+
+ if( !Rectangle( aDstPtPix, aDstSzPix ).Intersection( aBoundRect ).IsEmpty() &&
+ aPaintVDev.SetOutputSizePixel( aDstSzPix ) )
+ {
+ aPaintVDev.Push();
+ aMapVDev.Push();
+
+ aMapVDev.mnDPIX = aPaintVDev.mnDPIX = mnDPIX;
+ aMapVDev.mnDPIY = aPaintVDev.mnDPIY = mnDPIY;
+
+ aPaintVDev.EnableOutput(FALSE);
+
+ // iterate over all actions
+ for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
+ pCurrAct;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
+ {
+ // enable output only for
+ // actions that are members of
+ // the current aCCList element
+ // (aCurr)
+ if( aCCList_MemberMap[nActionNum] == &(*aCurr) )
+ aPaintVDev.EnableOutput(TRUE);
+
+ // but process every action
+ const USHORT nType( pCurrAct->GetType() );
+
+ if( META_MAPMODE_ACTION == nType )
+ {
+ pCurrAct->Execute( &aMapVDev );
+
+ MapMode aMtfMap( aMapVDev.GetMapMode() );
+ const Point aNewOrg( aMapVDev.PixelToLogic( aDstPtPix ) );
+
+ aMtfMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
+ aPaintVDev.SetMapMode( aMtfMap );
+ }
+ else if( ( META_PUSH_ACTION == nType ) || ( META_POP_ACTION ) == nType )
+ {
+ pCurrAct->Execute( &aMapVDev );
+ pCurrAct->Execute( &aPaintVDev );
+ }
+ else if( META_GRADIENT_ACTION == nType )
+ {
+ MetaGradientAction* pGradientAction = static_cast<MetaGradientAction*>(pCurrAct);
+ Printer* pPrinter = dynamic_cast< Printer* >(this);
+ if( pPrinter )
+ pPrinter->DrawGradientEx( &aPaintVDev, pGradientAction->GetRect(), pGradientAction->GetGradient() );
+ else
+ DrawGradient( pGradientAction->GetRect(), pGradientAction->GetGradient() );
+ }
+ else
+ {
+ pCurrAct->Execute( &aPaintVDev );
+ }
+
+ if( !( nActionNum % 8 ) )
+ Application::Reschedule();
+ }
+
+ const BOOL bOldMap = mbMap;
+ mbMap = aPaintVDev.mbMap = FALSE;
+
+ Bitmap aBandBmp( aPaintVDev.GetBitmap( Point(), aDstSzPix ) );
+
+ // scale down bitmap, if requested
+ if( bDownsampleBitmaps )
+ {
+ aBandBmp = GetDownsampledBitmap( aDstSzPix,
+ Point(), aBandBmp.GetSizePixel(),
+ aBandBmp, nMaxBmpDPIX, nMaxBmpDPIY );
+ }
+
+ rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) );
+ rOutMtf.AddAction( new MetaBmpScaleAction( aDstPtPix, aDstSzPix, aBandBmp ) );
+ rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_END" ) );
+
+ aPaintVDev.mbMap = TRUE;
+ mbMap = bOldMap;
+ aMapVDev.Pop();
+ aPaintVDev.Pop();
+ }
+
+ // overlapping bands to avoid missing lines (e.g. PostScript)
+ aDstPtPix.X() += aDstSzPix.Width();
+ }
+
+ // overlapping bands to avoid missing lines (e.g. PostScript)
+ aDstPtPix.Y() += aDstSzPix.Height();
+ }
+
+ rOutMtf.AddAction( new MetaPopAction() );
+ }
+ }
+ }
+ }
+
+ //
+ // STAGE 4: Copy actions to output metafile
+ // ========================================
+ //
+
+ // create an OutputDevice to record color settings, mapmode
+ // changes and the like
+ VirtualDevice aMapModeVDev3;
+ aMapModeVDev3.mnDPIX = mnDPIX;
+ aMapModeVDev3.mnDPIY = mnDPIY;
+ aMapModeVDev3.EnableOutput(FALSE);
+
+ // iterate over all actions and duplicate the ones not in a
+ // special aCCList member into rOutMtf
+ for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
+ pCurrAct;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
+ {
+ const ConnectedComponents* pCurrAssociatedComponent = aCCList_MemberMap[nActionNum];
+
+ // NOTE: This relies on the fact that map-mode or draw
+ // mode changing actions are solitary aCCList elements and
+ // have empty bounding boxes, see comment on stage 2.1
+ // above
+ if( pCurrAssociatedComponent &&
+ (pCurrAssociatedComponent->aBounds.IsEmpty() ||
+ !pCurrAssociatedComponent->bIsSpecial) )
+ {
+ // #107169# Treat transparent bitmaps special, if they
+ // are the first (or sole) action in their bounds
+ // list. Note that we previously ensured that no
+ // fully-transparent objects are before us here.
+ if( ImplIsActionHandlingTransparency( *pCurrAct ) &&
+ pCurrAssociatedComponent->aComponentList.begin()->first == pCurrAct )
+ {
+ // convert actions, where masked-out parts are of
+ // given background color
+ ImplConvertTransparentAction(rOutMtf,
+ *pCurrAct,
+ aMapModeVDev3,
+ aBackgroundComponent.aBgColor);
+ }
+ else
+ {
+ // simply add this action
+ rOutMtf.AddAction( ( pCurrAct->Duplicate(), pCurrAct ) );
+ }
+
+ pCurrAct->Execute(&aMapModeVDev3);
+ }
+ }
+
+ rOutMtf.SetPrefMapMode( rInMtf.GetPrefMapMode() );
+ rOutMtf.SetPrefSize( rInMtf.GetPrefSize() );
+ }
+ return bTransparent;
+}
+
+// -----------------------------------------------------------------------------
+
+Bitmap OutputDevice::GetDownsampledBitmap( const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const Bitmap& rBmp, long nMaxBmpDPIX, long nMaxBmpDPIY )
+{
+ Bitmap aBmp( rBmp );
+
+ if( !aBmp.IsEmpty() )
+ {
+ Point aPoint;
+ const Rectangle aBmpRect( aPoint, aBmp.GetSizePixel() );
+ Rectangle aSrcRect( rSrcPt, rSrcSz );
+
+ // do cropping if neccessary
+ if( aSrcRect.Intersection( aBmpRect ) != aBmpRect )
+ {
+ if( !aSrcRect.IsEmpty() )
+ aBmp.Crop( aSrcRect );
+ else
+ aBmp.SetEmpty();
+ }
+
+ if( !aBmp.IsEmpty() )
+ {
+ // do downsampling if neccessary
+ Size aDstSizeTwip( PixelToLogic( LogicToPixel( rDstSz ), MAP_TWIP ) );
+
+ // #103209# Normalize size (mirroring has to happen outside of this method)
+ aDstSizeTwip = Size( labs(aDstSizeTwip.Width()), labs(aDstSizeTwip.Height()) );
+
+ const Size aBmpSize( aBmp.GetSizePixel() );
+ const double fBmpPixelX = aBmpSize.Width();
+ const double fBmpPixelY = aBmpSize.Height();
+ const double fMaxPixelX = aDstSizeTwip.Width() * nMaxBmpDPIX / 1440.0;
+ const double fMaxPixelY = aDstSizeTwip.Height() * nMaxBmpDPIY / 1440.0;
+
+ // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
+ if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
+ ( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) &&
+ ( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) )
+ {
+ // do scaling
+ Size aNewBmpSize;
+ const double fBmpWH = fBmpPixelX / fBmpPixelY;
+ const double fMaxWH = fMaxPixelX / fMaxPixelY;
+
+ if( fBmpWH < fMaxWH )
+ {
+ aNewBmpSize.Width() = FRound( fMaxPixelY * fBmpWH );
+ aNewBmpSize.Height() = FRound( fMaxPixelY );
+ }
+ else if( fBmpWH > 0.0 )
+ {
+ aNewBmpSize.Width() = FRound( fMaxPixelX );
+ aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH);
+ }
+
+ if( aNewBmpSize.Width() && aNewBmpSize.Height() )
+ aBmp.Scale( aNewBmpSize );
+ else
+ aBmp.SetEmpty();
+ }
+ }
+ }
+
+ return aBmp;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapEx OutputDevice::GetDownsampledBitmapEx( const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const BitmapEx& rBmpEx, long nMaxBmpDPIX, long nMaxBmpDPIY )
+{
+ BitmapEx aBmpEx( rBmpEx );
+
+ if( !aBmpEx.IsEmpty() )
+ {
+ Point aPoint;
+ const Rectangle aBmpRect( aPoint, aBmpEx.GetSizePixel() );
+ Rectangle aSrcRect( rSrcPt, rSrcSz );
+
+ // do cropping if neccessary
+ if( aSrcRect.Intersection( aBmpRect ) != aBmpRect )
+ {
+ if( !aSrcRect.IsEmpty() )
+ aBmpEx.Crop( aSrcRect );
+ else
+ aBmpEx.SetEmpty();
+ }
+
+ if( !aBmpEx.IsEmpty() )
+ {
+ // do downsampling if neccessary
+ Size aDstSizeTwip( PixelToLogic( LogicToPixel( rDstSz ), MAP_TWIP ) );
+
+ // #103209# Normalize size (mirroring has to happen outside of this method)
+ aDstSizeTwip = Size( labs(aDstSizeTwip.Width()), labs(aDstSizeTwip.Height()) );
+
+ const Size aBmpSize( aBmpEx.GetSizePixel() );
+ const double fBmpPixelX = aBmpSize.Width();
+ const double fBmpPixelY = aBmpSize.Height();
+ const double fMaxPixelX = aDstSizeTwip.Width() * nMaxBmpDPIX / 1440.0;
+ const double fMaxPixelY = aDstSizeTwip.Height() * nMaxBmpDPIY / 1440.0;
+
+ // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
+ if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
+ ( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) &&
+ ( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) )
+ {
+ // do scaling
+ Size aNewBmpSize;
+ const double fBmpWH = fBmpPixelX / fBmpPixelY;
+ const double fMaxWH = fMaxPixelX / fMaxPixelY;
+
+ if( fBmpWH < fMaxWH )
+ {
+ aNewBmpSize.Width() = FRound( fMaxPixelY * fBmpWH );
+ aNewBmpSize.Height() = FRound( fMaxPixelY );
+ }
+ else if( fBmpWH > 0.0 )
+ {
+ aNewBmpSize.Width() = FRound( fMaxPixelX );
+ aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH);
+ }
+
+ if( aNewBmpSize.Width() && aNewBmpSize.Height() )
+ aBmpEx.Scale( aNewBmpSize );
+ else
+ aBmpEx.SetEmpty();
+ }
+ }
+ }
+
+ return aBmpEx;
+}
+
+// -----------------------------------------------------------------------------
+
+void Printer::DrawGradientEx( OutputDevice* pOut, const Rectangle& rRect, const Gradient& rGradient )
+{
+ const PrinterOptions& rPrinterOptions = GetPrinterOptions();
+
+ if( rPrinterOptions.IsReduceGradients() )
+ {
+ if( PRINTER_GRADIENT_STRIPES == rPrinterOptions.GetReducedGradientMode() )
+ {
+ if( !rGradient.GetSteps() || ( rGradient.GetSteps() > rPrinterOptions.GetReducedGradientStepCount() ) )
+ {
+ Gradient aNewGradient( rGradient );
+
+ aNewGradient.SetSteps( rPrinterOptions.GetReducedGradientStepCount() );
+ pOut->DrawGradient( rRect, aNewGradient );
+ }
+ else
+ pOut->DrawGradient( rRect, rGradient );
+ }
+ else
+ {
+ const Color& rStartColor = rGradient.GetStartColor();
+ const Color& rEndColor = rGradient.GetEndColor();
+ const long nR = ( ( (long) rStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100L +
+ ( (long) rEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
+ const long nG = ( ( (long) rStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100L +
+ ( (long) rEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
+ const long nB = ( ( (long) rStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100L +
+ ( (long) rEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
+ const Color aColor( (BYTE) nR, (BYTE) nG, (BYTE) nB );
+
+ pOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ pOut->SetLineColor( aColor );
+ pOut->SetFillColor( aColor );
+ pOut->DrawRect( rRect );
+ pOut->Pop();
+ }
+ }
+ else
+ pOut->DrawGradient( rRect, rGradient );
+}
+
+// -----------------------------------------------------------------------------
+
+void Printer::DrawGradientEx( OutputDevice* pOut, const PolyPolygon& rPolyPoly, const Gradient& rGradient )
+{
+ const PrinterOptions& rPrinterOptions = GetPrinterOptions();
+
+ if( rPrinterOptions.IsReduceGradients() )
+ {
+ if( PRINTER_GRADIENT_STRIPES == rPrinterOptions.GetReducedGradientMode() )
+ {
+ if( !rGradient.GetSteps() || ( rGradient.GetSteps() > rPrinterOptions.GetReducedGradientStepCount() ) )
+ {
+ Gradient aNewGradient( rGradient );
+
+ aNewGradient.SetSteps( rPrinterOptions.GetReducedGradientStepCount() );
+ pOut->DrawGradient( rPolyPoly, aNewGradient );
+ }
+ else
+ pOut->DrawGradient( rPolyPoly, rGradient );
+ }
+ else
+ {
+ const Color& rStartColor = rGradient.GetStartColor();
+ const Color& rEndColor = rGradient.GetEndColor();
+ const long nR = ( ( (long) rStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100L +
+ ( (long) rEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
+ const long nG = ( ( (long) rStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100L +
+ ( (long) rEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
+ const long nB = ( ( (long) rStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100L +
+ ( (long) rEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100L ) >> 1;
+ const Color aColor( (BYTE) nR, (BYTE) nG, (BYTE) nB );
+
+ pOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ pOut->SetLineColor( aColor );
+ pOut->SetFillColor( aColor );
+ pOut->DrawPolyPolygon( rPolyPoly );
+ pOut->Pop();
+ }
+ }
+ else
+ pOut->DrawGradient( rPolyPoly, rGradient );
+}
diff --git a/vcl/source/gdi/print3.cxx b/vcl/source/gdi/print3.cxx
new file mode 100755
index 000000000000..0aeb928856fc
--- /dev/null
+++ b/vcl/source/gdi/print3.cxx
@@ -0,0 +1,1882 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_vcl.hxx"
+
+#include "vcl/print.hxx"
+#include "vcl/prndlg.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/salinst.hxx"
+#include "vcl/salprn.hxx"
+#include "vcl/svids.hrc"
+#include "vcl/metaact.hxx"
+#include "vcl/msgbox.hxx"
+#include "vcl/configsettings.hxx"
+
+#include "tools/urlobj.hxx"
+
+#include "com/sun/star/ui/dialogs/XFilePicker.hpp"
+#include "com/sun/star/ui/dialogs/XFilterManager.hpp"
+#include "com/sun/star/ui/dialogs/TemplateDescription.hpp"
+#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
+#include "com/sun/star/view/DuplexMode.hpp"
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/awt/Size.hpp"
+#include "comphelper/processfactory.hxx"
+
+#include <hash_map>
+#include <hash_set>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace vcl;
+
+class ImplPageCache
+{
+ struct CacheEntry
+ {
+ GDIMetaFile aPage;
+ PrinterController::PageSize aSize;
+ };
+
+ std::vector< CacheEntry > maPages;
+ std::vector< sal_Int32 > maPageNumbers;
+ std::vector< sal_Int32 > maCacheRanking;
+
+ static const sal_Int32 nCacheSize = 6;
+
+ void updateRanking( sal_Int32 nLastHit )
+ {
+ if( maCacheRanking[0] != nLastHit )
+ {
+ bool bMove = false;
+ for( sal_Int32 i = nCacheSize-1; i > 0; i-- )
+ {
+ if( maCacheRanking[i] == nLastHit )
+ bMove = true;
+ maCacheRanking[i] = maCacheRanking[i-1];
+ }
+ maCacheRanking[0] = nLastHit;
+ }
+ }
+
+public:
+ ImplPageCache()
+ : maPages( nCacheSize )
+ , maPageNumbers( nCacheSize, -1 )
+ , maCacheRanking( nCacheSize )
+ {
+ for( sal_Int32 i = 0; i < nCacheSize; i++ )
+ maCacheRanking[i] = nCacheSize - i - 1;
+ }
+
+ // caution: does not ensure uniqueness
+ void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize )
+ {
+ sal_Int32 nReplacePage = maCacheRanking.back();
+ maPages[ nReplacePage ].aPage = i_rPage;
+ maPages[ nReplacePage ].aSize = i_rSize;
+ maPageNumbers[ nReplacePage ] = i_nPageNo;
+ // cache insertion means in our case, the page was just queried
+ // so update the ranking
+ updateRanking( nReplacePage );
+ }
+
+ // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6
+ // this needs to be urgently rewritten. However do NOT increase the cache size lightly,
+ // whole pages can be rather memory intensive
+ bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize )
+ {
+ for( sal_Int32 i = 0; i < nCacheSize; ++i )
+ {
+ if( maPageNumbers[i] == i_nPageNo )
+ {
+ updateRanking( i );
+ o_rPageFile = maPages[i].aPage;
+ o_rSize = maPages[i].aSize;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void invalidate()
+ {
+ for( sal_Int32 i = 0; i < nCacheSize; ++i )
+ {
+ maPageNumbers[i] = -1;
+ maPages[i].aPage.Clear();
+ maCacheRanking[i] = nCacheSize - i - 1;
+ }
+ }
+};
+
+class vcl::ImplPrinterControllerData
+{
+public:
+ struct ControlDependency
+ {
+ rtl::OUString maDependsOnName;
+ sal_Int32 mnDependsOnEntry;
+
+ ControlDependency() : mnDependsOnEntry( -1 ) {}
+ };
+
+ typedef std::hash_map< rtl::OUString, size_t, rtl::OUStringHash > PropertyToIndexMap;
+ typedef std::hash_map< rtl::OUString, ControlDependency, rtl::OUStringHash > ControlDependencyMap;
+
+ boost::shared_ptr<Printer> mpPrinter;
+ Sequence< PropertyValue > maUIOptions;
+ std::vector< PropertyValue > maUIProperties;
+ std::vector< bool > maUIPropertyEnabled;
+ PropertyToIndexMap maPropertyToIndex;
+ Link maOptionChangeHdl;
+ ControlDependencyMap maControlDependencies;
+ sal_Bool mbFirstPage;
+ sal_Bool mbLastPage;
+ sal_Bool mbReversePageOrder;
+ view::PrintableState meJobState;
+
+ vcl::PrinterController::MultiPageSetup maMultiPage;
+
+ vcl::PrintProgressDialog* mpProgress;
+
+ ImplPageCache maPageCache;
+
+ // set by user through printer config dialog
+ // if set, pages are centered and trimmed onto the fixed page
+ Size maFixedPageSize;
+ sal_Int32 mnDefaultPaperBin;
+
+ ImplPrinterControllerData() :
+ mbFirstPage( sal_True ),
+ mbLastPage( sal_False ),
+ mbReversePageOrder( sal_False ),
+ meJobState( view::PrintableState_JOB_STARTED ),
+ mpProgress( NULL ),
+ mnDefaultPaperBin( -1 )
+ {}
+ ~ImplPrinterControllerData() { delete mpProgress; }
+
+ Size getRealPaperSize( const Size& i_rPageSize ) const
+ {
+ if( maFixedPageSize.Width() > 0 && maFixedPageSize.Height() > 0 )
+ return maFixedPageSize;
+ if( maMultiPage.nRows * maMultiPage.nColumns > 1 )
+ return maMultiPage.aPaperSize;
+ return i_rPageSize;
+ }
+ bool isFixedPageSize() const
+ { return maFixedPageSize.Width() != 0 && maFixedPageSize.Height() != 0; }
+ PrinterController::PageSize modifyJobSetup( const Sequence< PropertyValue >& i_rProps );
+};
+
+PrinterController::PrinterController()
+ : mpImplData( new ImplPrinterControllerData )
+{
+}
+
+PrinterController::PrinterController( const boost::shared_ptr<Printer>& i_pPrinter )
+ : mpImplData( new ImplPrinterControllerData )
+{
+ mpImplData->mpPrinter = i_pPrinter;
+}
+
+static rtl::OUString queryFile( Printer* pPrinter )
+{
+ rtl::OUString aResult;
+
+ uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
+ if( xFactory.is() )
+ {
+ uno::Sequence< uno::Any > aTempl( 1 );
+ aTempl.getArray()[0] <<= ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION;
+ uno::Reference< ui::dialogs::XFilePicker > xFilePicker(
+ xFactory->createInstanceWithArguments(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FilePicker" ) ),
+ aTempl ), uno::UNO_QUERY );
+ DBG_ASSERT( xFilePicker.is(), "could not get FilePicker service" );
+
+ uno::Reference< ui::dialogs::XFilterManager > xFilterMgr( xFilePicker, uno::UNO_QUERY );
+ if( xFilePicker.is() && xFilterMgr.is() )
+ {
+ try
+ {
+#ifdef UNX
+ // add PostScript and PDF
+ bool bPS = true, bPDF = true;
+ if( pPrinter )
+ {
+ if( pPrinter->GetCapabilities( PRINTER_CAPABILITIES_PDF ) )
+ bPS = false;
+ else
+ bPDF = false;
+ }
+ if( bPS )
+ xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PostScript" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.ps" ) ) );
+ if( bPDF )
+ xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Portable Document Format" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.pdf" ) ) );
+#elif defined WNT
+ (void)pPrinter;
+ xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.PRN" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.prn" ) ) );
+#endif
+ // add arbitrary files
+ xFilterMgr->appendFilter( String( VclResId( SV_STDTEXT_ALLFILETYPES ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.*" ) ) );
+ }
+ catch( lang::IllegalArgumentException rExc )
+ {
+ DBG_ERRORFILE( "caught IllegalArgumentException when registering filter\n" );
+ }
+
+ if( xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK )
+ {
+ uno::Sequence< ::rtl::OUString > aPathSeq( xFilePicker->getFiles() );
+ INetURLObject aObj( aPathSeq[0] );
+ aResult = aObj.PathToFileName();
+ }
+ }
+ }
+ return aResult;
+}
+
+struct PrintJobAsync
+{
+ boost::shared_ptr<PrinterController> mpController;
+ JobSetup maInitSetup;
+
+ PrintJobAsync( const boost::shared_ptr<PrinterController>& i_pController,
+ const JobSetup& i_rInitSetup
+ )
+ : mpController( i_pController ), maInitSetup( i_rInitSetup )
+ {}
+
+ DECL_LINK( ExecJob, void* );
+};
+
+IMPL_LINK( PrintJobAsync, ExecJob, void*, EMPTYARG )
+{
+ Printer::ImplPrintJob( mpController, maInitSetup );
+
+ // clean up, do not access members after this
+ delete this;
+
+ return 0;
+}
+
+void Printer::PrintJob( const boost::shared_ptr<PrinterController>& i_pController,
+ const JobSetup& i_rInitSetup
+ )
+{
+ sal_Bool bSynchronous = sal_False;
+ beans::PropertyValue* pVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Wait" ) ) );
+ if( pVal )
+ pVal->Value >>= bSynchronous;
+
+ if( bSynchronous )
+ ImplPrintJob( i_pController, i_rInitSetup );
+ else
+ {
+ PrintJobAsync* pAsync = new PrintJobAsync( i_pController, i_rInitSetup );
+ Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob ) );
+ }
+}
+
+void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pController,
+ const JobSetup& i_rInitSetup
+ )
+{
+ boost::shared_ptr<PrinterController> pController( i_pController );
+
+ // check if there is a default printer; if not, show an error box (if appropriate)
+ if( GetDefaultPrinterName().Len() == 0 )
+ {
+ if( pController->isShowDialogs()
+ // && ! pController->isDirectPrint()
+ )
+ {
+ ErrorBox aBox( NULL, VclResId( SV_PRINT_NOPRINTERWARNING ) );
+ aBox.Execute();
+ }
+ pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ),
+ makeAny( sal_False ) );
+ }
+
+ // setup printer
+
+ // if no specific printer is already set, create one
+
+ // #i108686#
+ // in case of a UI (platform independent or system dialog) print job, make the printer persistent over jobs
+ // however if no printer was already set by the print job's originator,
+ // and this is an API job, then use the system default location (because
+ // this is the only sensible default available if the user has no means of changing
+ // the destination
+ if( ! pController->getPrinter() )
+ {
+ rtl::OUString aPrinterName( i_rInitSetup.GetPrinterName() );
+ if( ! aPrinterName.getLength() && pController->isShowDialogs() && ! pController->isDirectPrint() )
+ {
+ // get printer name from configuration
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ aPrinterName = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinterUsed" ) ) );
+ }
+
+ boost::shared_ptr<Printer> pPrinter( new Printer( aPrinterName ) );
+ pController->setPrinter( pPrinter );
+ }
+
+ // reset last page property
+ i_pController->setLastPage( sal_False );
+
+ // update "PageRange" property inferring from other properties:
+ // case 1: "Pages" set from UNO API ->
+ // setup "Print Selection" and insert "PageRange" attribute
+ // case 2: "All pages" is selected
+ // update "Page range" attribute to have a sensible default,
+ // but leave "All" as selected
+
+ // "Pages" attribute from API is now equivalent to "PageRange"
+ // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
+ // Argh ! That sure needs cleaning up
+ beans::PropertyValue* pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintRange" ) ) );
+ if( ! pContentVal )
+ pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintContent" ) ) );
+
+ // case 1: UNO API has set "Pages"
+ beans::PropertyValue* pPagesVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pages" ) ) );
+ if( pPagesVal )
+ {
+ rtl::OUString aPagesVal;
+ pPagesVal->Value >>= aPagesVal;
+ if( aPagesVal.getLength() )
+ {
+ // "Pages" attribute from API is now equivalent to "PageRange"
+ // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
+ // Argh ! That sure needs cleaning up
+ if( pContentVal )
+ {
+ pContentVal->Value = makeAny( sal_Int32( 1 ) );
+ i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), pPagesVal->Value );
+ }
+ }
+ }
+ // case 2: is "All" selected ?
+ else if( pContentVal )
+ {
+ sal_Int32 nContent = -1;
+ if( pContentVal->Value >>= nContent )
+ {
+ if( nContent == 0 )
+ {
+ sal_Int32 nPages = i_pController->getPageCount();
+ if( nPages > 0 )
+ {
+ rtl::OUStringBuffer aBuf( 32 );
+ aBuf.appendAscii( "1" );
+ if( nPages > 1 )
+ {
+ aBuf.appendAscii( "-" );
+ aBuf.append( nPages );
+ }
+ i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), makeAny( aBuf.makeStringAndClear() ) );
+ }
+ }
+ }
+ }
+
+ beans::PropertyValue* pReverseVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintReverse" ) ) );
+ if( pReverseVal )
+ {
+ sal_Bool bReverse = sal_False;
+ pReverseVal->Value >>= bReverse;
+ pController->setReversePrint( bReverse );
+ }
+
+ // in direct print case check whether there is anything to print.
+ // if not, show an errorbox (if appropriate)
+ if( pController->isShowDialogs() && pController->isDirectPrint() )
+ {
+ if( pController->getFilteredPageCount() == 0 )
+ {
+ ErrorBox aBox( NULL, VclResId( SV_PRINT_NOCONTENT ) );
+ aBox.Execute();
+ return;
+ }
+ }
+
+ // check if the printer brings up its own dialog
+ // in that case leave the work to that dialog
+ if( ! pController->getPrinter()->GetCapabilities( PRINTER_CAPABILITIES_EXTERNALDIALOG ) &&
+ ! pController->isDirectPrint() &&
+ pController->isShowDialogs()
+ )
+ {
+ try
+ {
+ PrintDialog aDlg( NULL, i_pController );
+ if( ! aDlg.Execute() )
+ {
+ GDIMetaFile aPageFile;
+ i_pController->setLastPage( sal_True );
+ i_pController->getFilteredPageFile( 0, aPageFile );
+ return;
+ }
+ if( aDlg.isPrintToFile() )
+ {
+ rtl::OUString aFile = queryFile( pController->getPrinter().get() );
+ if( ! aFile.getLength() )
+ {
+ GDIMetaFile aPageFile;
+ i_pController->setLastPage( sal_True );
+ i_pController->getFilteredPageFile( 0, aPageFile );
+ return;
+ }
+ pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ),
+ makeAny( aFile ) );
+ }
+ else if( aDlg.isSingleJobs() )
+ {
+ pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ),
+ makeAny( sal_True ) );
+ }
+ }
+ catch( std::bad_alloc& )
+ {
+ }
+ }
+
+ pController->pushPropertiesToPrinter();
+
+ rtl::OUString aJobName;
+ beans::PropertyValue* pJobNameVal = pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "JobName" ) ) );
+ if( pJobNameVal )
+ pJobNameVal->Value >>= aJobName;
+
+ pController->getPrinter()->StartJob( String( aJobName ), pController );
+
+ pController->jobFinished( pController->getJobState() );
+}
+
+bool Printer::StartJob( const rtl::OUString& i_rJobName, boost::shared_ptr<vcl::PrinterController>& i_pController )
+{
+ mnError = PRINTER_OK;
+
+ if ( IsDisplayPrinter() )
+ return FALSE;
+
+ if ( IsJobActive() || IsPrinting() )
+ return FALSE;
+
+ ULONG nCopies = mnCopyCount;
+ bool bCollateCopy = mbCollateCopy;
+ bool bUserCopy = FALSE;
+
+ if ( nCopies > 1 )
+ {
+ ULONG nDevCopy;
+
+ if ( bCollateCopy )
+ nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES );
+ else
+ nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COPIES );
+
+ // need to do copies by hand ?
+ if ( nCopies > nDevCopy )
+ {
+ bUserCopy = TRUE;
+ nCopies = 1;
+ bCollateCopy = FALSE;
+ }
+ }
+ else
+ bCollateCopy = FALSE;
+
+
+ ImplSVData* pSVData = ImplGetSVData();
+ mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
+
+ if ( !mpPrinter )
+ return FALSE;
+
+ sal_Bool bSinglePrintJobs = sal_False;
+ beans::PropertyValue* pSingleValue = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
+ if( pSingleValue )
+ {
+ pSingleValue->Value >>= bSinglePrintJobs;
+ }
+
+ // remark: currently it is still possible to use EnablePrintFile and
+ // SetPrintFileName to redirect printout into file
+ // it can be argued that those methods should be removed in favor
+ // of only using the LocalFileName property
+ beans::PropertyValue* pFileValue = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ) );
+ if( pFileValue )
+ {
+ rtl::OUString aFile;
+ pFileValue->Value >>= aFile;
+ if( aFile.getLength() )
+ {
+ mbPrintFile = TRUE;
+ maPrintFile = aFile;
+ bSinglePrintJobs = sal_False;
+ }
+ }
+
+ XubString* pPrintFile = NULL;
+ if ( mbPrintFile )
+ pPrintFile = &maPrintFile;
+
+ maJobName = i_rJobName;
+ mnCurPage = 1;
+ mnCurPrintPage = 1;
+ mbPrinting = TRUE;
+ if( ImplGetSVData()->maGDIData.mbPrinterPullModel )
+ {
+ mbJobActive = TRUE;
+ // sallayer does all necessary page printing
+ // and also handles showing a dialog
+ // that also means it must call jobStarted when the dialog is finished
+ // it also must set the JobState of the Controller
+ if( mpPrinter->StartJob( pPrintFile,
+ i_rJobName,
+ Application::GetDisplayName(),
+ maJobSetup.ImplGetConstData(),
+ *i_pController ) )
+ {
+ EndJob();
+ }
+ else
+ {
+ mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() );
+ if ( !mnError )
+ mnError = PRINTER_GENERALERROR;
+ pSVData->mpDefInst->DestroyPrinter( mpPrinter );
+ mnCurPage = 0;
+ mnCurPrintPage = 0;
+ mbPrinting = FALSE;
+ mpPrinter = NULL;
+
+ return false;
+ }
+ }
+ else
+ {
+ // possibly a dialog has been shown
+ // now the real job starts
+ i_pController->setJobState( view::PrintableState_JOB_STARTED );
+ i_pController->jobStarted();
+
+ int nJobs = 1;
+ int nOuterRepeatCount = 1;
+ int nInnerRepeatCount = 1;
+ if( bUserCopy )
+ {
+ if( mbCollateCopy )
+ nOuterRepeatCount = mnCopyCount;
+ else
+ nInnerRepeatCount = mnCopyCount;
+ }
+ if( bSinglePrintJobs )
+ {
+ nJobs = mnCopyCount;
+ nCopies = 1;
+ nOuterRepeatCount = nInnerRepeatCount = 1;
+ }
+
+ for( int nJobIteration = 0; nJobIteration < nJobs; nJobIteration++ )
+ {
+ bool bError = false;
+ if( mpPrinter->StartJob( pPrintFile,
+ i_rJobName,
+ Application::GetDisplayName(),
+ nCopies,
+ bCollateCopy,
+ i_pController->isDirectPrint(),
+ maJobSetup.ImplGetConstData() ) )
+ {
+ mbJobActive = TRUE;
+ i_pController->createProgressDialog();
+ int nPages = i_pController->getFilteredPageCount();
+ for( int nOuterIteration = 0; nOuterIteration < nOuterRepeatCount; nOuterIteration++ )
+ {
+ for( int nPage = 0; nPage < nPages; nPage++ )
+ {
+ for( int nInnerIteration = 0; nInnerIteration < nInnerRepeatCount; nInnerIteration++ )
+ {
+ if( nPage == nPages-1 &&
+ nOuterIteration == nOuterRepeatCount-1 &&
+ nInnerIteration == nInnerRepeatCount-1 &&
+ nJobIteration == nJobs-1 )
+ {
+ i_pController->setLastPage( sal_True );
+ }
+ i_pController->printFilteredPage( nPage );
+ }
+ }
+ // FIXME: duplex ?
+ }
+ EndJob();
+
+ if( nJobIteration < nJobs-1 )
+ {
+ mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
+
+ if ( mpPrinter )
+ {
+ maJobName = i_rJobName;
+ mnCurPage = 1;
+ mnCurPrintPage = 1;
+ mbPrinting = TRUE;
+ }
+ else
+ bError = true;
+ }
+ }
+ else
+ bError = true;
+
+ if( bError )
+ {
+ mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() );
+ if ( !mnError )
+ mnError = PRINTER_GENERALERROR;
+ i_pController->setJobState( mnError == PRINTER_ABORT
+ ? view::PrintableState_JOB_ABORTED
+ : view::PrintableState_JOB_FAILED );
+ if( mpPrinter )
+ pSVData->mpDefInst->DestroyPrinter( mpPrinter );
+ mnCurPage = 0;
+ mnCurPrintPage = 0;
+ mbPrinting = FALSE;
+ mpPrinter = NULL;
+
+ return false;
+ }
+ }
+
+ if( i_pController->getJobState() == view::PrintableState_JOB_STARTED )
+ i_pController->setJobState( view::PrintableState_JOB_SPOOLED );
+ }
+
+ // make last used printer persistent for UI jobs
+ if( i_pController->isShowDialogs() && ! i_pController->isDirectPrint() )
+ {
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinterUsed" ) ),
+ GetName()
+ );
+ }
+
+ return true;
+}
+
+PrinterController::~PrinterController()
+{
+ delete mpImplData;
+}
+
+view::PrintableState PrinterController::getJobState() const
+{
+ return mpImplData->meJobState;
+}
+
+void PrinterController::setJobState( view::PrintableState i_eState )
+{
+ mpImplData->meJobState = i_eState;
+}
+
+const boost::shared_ptr<Printer>& PrinterController::getPrinter() const
+{
+ return mpImplData->mpPrinter;
+}
+
+void PrinterController::setPrinter( const boost::shared_ptr<Printer>& i_rPrinter )
+{
+ mpImplData->mpPrinter = i_rPrinter;
+ setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name" ) ),
+ makeAny( rtl::OUString( i_rPrinter->GetName() ) ) );
+ mpImplData->mnDefaultPaperBin = mpImplData->mpPrinter->GetPaperBin();
+}
+
+bool PrinterController::setupPrinter( Window* i_pParent )
+{
+ bool bRet = false;
+ if( mpImplData->mpPrinter.get() )
+ {
+ Size aPaperSize( mpImplData->mpPrinter->PixelToLogic(
+ mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) );
+ bRet = mpImplData->mpPrinter->Setup( i_pParent );
+ if( bRet )
+ {
+ // was the papersize overridden ? if so we need to take action
+ Size aNewPaperSize( mpImplData->mpPrinter->PixelToLogic(
+ mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) );
+ if( aNewPaperSize != aPaperSize )
+ {
+ mpImplData->maFixedPageSize = aNewPaperSize;
+ mpImplData->maPageCache.invalidate();
+ awt::Size aOverrideSize;
+ aOverrideSize.Width = aNewPaperSize.Width();
+ aOverrideSize.Height = aNewPaperSize.Height();
+ setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OverridePageSize" ) ),
+ makeAny( aOverrideSize ) );
+ }
+ }
+ }
+ return bRet;
+}
+
+PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const Sequence< PropertyValue >& i_rProps )
+{
+ PrinterController::PageSize aPageSize;
+ aPageSize.aSize = mpPrinter->GetPaperSize();
+ awt::Size aSetSize, aIsSize;
+ sal_Int32 nPaperBin = mnDefaultPaperBin;
+ for( sal_Int32 nProperty = 0, nPropertyCount = i_rProps.getLength(); nProperty < nPropertyCount; ++nProperty )
+ {
+ if( i_rProps[ nProperty ].Name.equalsAscii( "PreferredPageSize" ) )
+ {
+ i_rProps[ nProperty ].Value >>= aSetSize;
+ }
+ else if( i_rProps[ nProperty ].Name.equalsAscii( "PageSize" ) )
+ {
+ i_rProps[ nProperty ].Value >>= aIsSize;
+ }
+ else if( i_rProps[ nProperty ].Name.equalsAscii( "PageIncludesNonprintableArea" ) )
+ {
+ sal_Bool bVal = sal_False;
+ i_rProps[ nProperty ].Value >>= bVal;
+ aPageSize.bFullPaper = static_cast<bool>(bVal);
+ }
+ else if( i_rProps[ nProperty ].Name.equalsAscii( "PrinterPaperTray" ) )
+ {
+ sal_Int32 nBin = -1;
+ i_rProps[ nProperty ].Value >>= nBin;
+ if( nBin >= 0 && nBin < mpPrinter->GetPaperBinCount() )
+ nPaperBin = nBin;
+ }
+ }
+
+ Size aCurSize( mpPrinter->GetPaperSize() );
+ if( aSetSize.Width && aSetSize.Height )
+ {
+ Size aSetPaperSize( aSetSize.Width, aSetSize.Height );
+ Size aRealPaperSize( getRealPaperSize( aSetPaperSize ) );
+ if( aRealPaperSize != aCurSize )
+ aIsSize = aSetSize;
+ }
+
+ if( aIsSize.Width && aIsSize.Height )
+ {
+ aPageSize.aSize.Width() = aIsSize.Width;
+ aPageSize.aSize.Height() = aIsSize.Height;
+
+ Size aRealPaperSize( getRealPaperSize( aPageSize.aSize ) );
+ if( aRealPaperSize != aCurSize )
+ mpPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() );
+ }
+
+ if( nPaperBin != -1 && nPaperBin != mpPrinter->GetPaperBin() )
+ mpPrinter->SetPaperBin( nPaperBin );
+
+ return aPageSize;
+}
+
+int PrinterController::getPageCountProtected() const
+{
+ const MapMode aMapMode( MAP_100TH_MM );
+
+ mpImplData->mpPrinter->Push();
+ mpImplData->mpPrinter->SetMapMode( aMapMode );
+ int nPages = getPageCount();
+ mpImplData->mpPrinter->Pop();
+ return nPages;
+}
+
+Sequence< beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const
+{
+ const MapMode aMapMode( MAP_100TH_MM );
+
+ mpImplData->mpPrinter->Push();
+ mpImplData->mpPrinter->SetMapMode( aMapMode );
+ Sequence< beans::PropertyValue > aResult( getPageParameters( i_nPage ) );
+ mpImplData->mpPrinter->Pop();
+ return aResult;
+}
+
+PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
+{
+ // update progress if necessary
+ if( mpImplData->mpProgress )
+ {
+ // do nothing if printing is canceled
+ if( mpImplData->mpProgress->isCanceled() )
+ return PrinterController::PageSize();
+ mpImplData->mpProgress->tick();
+ Application::Reschedule( true );
+ }
+
+ if( i_bMayUseCache )
+ {
+ PrinterController::PageSize aPageSize;
+ if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) )
+ {
+ return aPageSize;
+ }
+ }
+ else
+ mpImplData->maPageCache.invalidate();
+
+ o_rMtf.Clear();
+
+ // get page parameters
+ Sequence< PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) );
+ const MapMode aMapMode( MAP_100TH_MM );
+
+ mpImplData->mpPrinter->Push();
+ mpImplData->mpPrinter->SetMapMode( aMapMode );
+
+ // modify job setup if necessary
+ PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm );
+
+ o_rMtf.SetPrefSize( aPageSize.aSize );
+ o_rMtf.SetPrefMapMode( aMapMode );
+
+ mpImplData->mpPrinter->EnableOutput( FALSE );
+
+ o_rMtf.Record( mpImplData->mpPrinter.get() );
+
+ printPage( i_nUnfilteredPage );
+
+ o_rMtf.Stop();
+ o_rMtf.WindStart();
+ mpImplData->mpPrinter->Pop();
+
+ if( i_bMayUseCache )
+ mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize );
+
+ // reset "FirstPage" property to false now we've gotten at least our first one
+ mpImplData->mbFirstPage = sal_False;
+
+ return aPageSize;
+}
+
+static void appendSubPage( GDIMetaFile& o_rMtf, const Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder )
+{
+ // intersect all clipregion actions with our clip rect
+ io_rSubPage.WindStart();
+ io_rSubPage.Clip( i_rClipRect );
+
+ // save gstate
+ o_rMtf.AddAction( new MetaPushAction( PUSH_ALL ) );
+
+ // clip to page rect
+ o_rMtf.AddAction( new MetaClipRegionAction( Region( i_rClipRect ), TRUE ) );
+
+ // append the subpage
+ io_rSubPage.WindStart();
+ io_rSubPage.Play( o_rMtf );
+
+ // restore gstate
+ o_rMtf.AddAction( new MetaPopAction() );
+
+ // draw a border
+ if( i_bDrawBorder )
+ {
+ // save gstate
+ o_rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_CLIPREGION | PUSH_MAPMODE ) );
+ o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) );
+
+ Rectangle aBorderRect( i_rClipRect );
+ o_rMtf.AddAction( new MetaLineColorAction( Color( COL_BLACK ), TRUE ) );
+ o_rMtf.AddAction( new MetaFillColorAction( Color( COL_TRANSPARENT ), FALSE ) );
+ o_rMtf.AddAction( new MetaRectAction( aBorderRect ) );
+
+ // restore gstate
+ o_rMtf.AddAction( new MetaPopAction() );
+ }
+}
+
+PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
+{
+ const MultiPageSetup& rMPS( mpImplData->maMultiPage );
+ int nSubPages = rMPS.nRows * rMPS.nColumns;
+ if( nSubPages < 1 )
+ nSubPages = 1;
+
+ // reverse sheet order
+ if( mpImplData->mbReversePageOrder )
+ {
+ int nDocPages = getFilteredPageCount();
+ i_nFilteredPage = nDocPages - 1 - i_nFilteredPage;
+ }
+
+ // there is no filtering to be done (and possibly the page size of the
+ // original page is to be set), when N-Up is "neutral" that is there is
+ // only one subpage and the margins are 0
+ if( nSubPages == 1 &&
+ rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 &&
+ rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 )
+ {
+ PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache );
+ Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize );
+ mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
+ mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
+ if( aPaperSize != aPageSize.aSize )
+ {
+ // user overridden page size, center Metafile
+ o_rMtf.WindStart();
+ long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2;
+ long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2;
+ o_rMtf.Move( nDX, nDY );
+ o_rMtf.WindStart();
+ o_rMtf.SetPrefSize( aPaperSize );
+ aPageSize.aSize = aPaperSize;
+ }
+ return aPageSize;
+ }
+
+ // set last page property really only on the very last page to be rendered
+ // that is on the last subpage of a NUp run
+ sal_Bool bIsLastPage = mpImplData->mbLastPage;
+ mpImplData->mbLastPage = sal_False;
+
+ Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize ) );
+
+ // multi page area: page size minus margins + one time spacing right and down
+ // the added spacing is so each subpage can be calculated including its spacing
+ Size aMPArea( aPaperSize );
+ aMPArea.Width() -= rMPS.nLeftMargin + rMPS.nRightMargin;
+ aMPArea.Width() += rMPS.nHorizontalSpacing;
+ aMPArea.Height() -= rMPS.nTopMargin + rMPS.nBottomMargin;
+ aMPArea.Height() += rMPS.nVerticalSpacing;
+
+ // determine offsets
+ long nAdvX = aMPArea.Width() / rMPS.nColumns;
+ long nAdvY = aMPArea.Height() / rMPS.nRows;
+
+ // determine size of a "cell" subpage, leave a little space around pages
+ Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing );
+
+ o_rMtf.Clear();
+ o_rMtf.SetPrefSize( aPaperSize );
+ o_rMtf.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
+ o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) );
+
+ int nDocPages = getPageCountProtected();
+ for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ )
+ {
+ // map current sub page to real page
+ int nPage = (i_nFilteredPage * nSubPages + nSubPage) / rMPS.nRepeat;
+ if( nSubPage == nSubPages-1 ||
+ nPage == nDocPages-1 )
+ {
+ mpImplData->mbLastPage = bIsLastPage;
+ }
+ if( nPage >= 0 && nPage < nDocPages )
+ {
+ GDIMetaFile aPageFile;
+ PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache );
+ if( aPageSize.aSize.Width() && aPageSize.aSize.Height() )
+ {
+ long nCellX = 0, nCellY = 0;
+ switch( rMPS.nOrder )
+ {
+ case PrinterController::LRTB:
+ nCellX = (nSubPage % rMPS.nColumns);
+ nCellY = (nSubPage / rMPS.nColumns);
+ break;
+ case PrinterController::TBLR:
+ nCellX = (nSubPage / rMPS.nRows);
+ nCellY = (nSubPage % rMPS.nRows);
+ break;
+ }
+ // scale the metafile down to a sub page size
+ double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width());
+ double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height());
+ double fScale = std::min( fScaleX, fScaleY );
+ aPageFile.Scale( fScale, fScale );
+ aPageFile.WindStart();
+
+ // move the subpage so it is centered in its "cell"
+ long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2;
+ long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2;
+ long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX;
+ long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY;
+ aPageFile.Move( nX, nY );
+ aPageFile.WindStart();
+ // calculate border rectangle
+ Rectangle aSubPageRect( Point( nX, nY ),
+ Size( long(double(aPageSize.aSize.Width())*fScale),
+ long(double(aPageSize.aSize.Height())*fScale) ) );
+
+ // append subpage to page
+ appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder );
+ }
+ }
+ }
+ o_rMtf.WindStart();
+
+ // subsequent getPageFile calls have changed the paper, reset it to current value
+ mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
+ mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
+
+ return PrinterController::PageSize( aPaperSize, true );
+}
+
+int PrinterController::getFilteredPageCount()
+{
+ int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns;
+ if( nDiv < 1 )
+ nDiv = 1;
+ return (getPageCountProtected() * mpImplData->maMultiPage.nRepeat + (nDiv-1)) / nDiv;
+}
+
+ULONG PrinterController::removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut )
+{
+ ULONG nRestoreDrawMode = mpImplData->mpPrinter->GetDrawMode();
+ sal_Int32 nMaxBmpDPIX = mpImplData->mpPrinter->ImplGetDPIX();
+ sal_Int32 nMaxBmpDPIY = mpImplData->mpPrinter->ImplGetDPIY();
+
+ const PrinterOptions& rPrinterOptions = mpImplData->mpPrinter->GetPrinterOptions();
+
+ static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300;
+ static const sal_Int32 NORMAL_BMP_RESOLUTION = 200;
+
+
+ if( rPrinterOptions.IsReduceBitmaps() )
+ {
+ // calculate maximum resolution for bitmap graphics
+ if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() )
+ {
+ nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX );
+ nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY );
+ }
+ else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() )
+ {
+ nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX );
+ nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY );
+ }
+ else
+ {
+ nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX );
+ nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY );
+ }
+ }
+
+ // convert to greysacles
+ if( rPrinterOptions.IsConvertToGreyscales() )
+ {
+ mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() |
+ ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT |
+ DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) );
+ }
+
+ // disable transparency output
+ if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
+ {
+ mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | DRAWMODE_NOTRANSPARENCY );
+ }
+
+ Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic
+ if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 )
+ {
+ // in N-Up printing we have no "page" background operation
+ // we also have no way to determine the paper color
+ // so let's go for white, which will kill 99.9% of the real cases
+ aBg = Color( COL_WHITE );
+ }
+ mpImplData->mpPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY,
+ rPrinterOptions.IsReduceTransparency(),
+ rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO,
+ rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(),
+ aBg
+ );
+ return nRestoreDrawMode;
+}
+
+void PrinterController::printFilteredPage( int i_nPage )
+{
+ if( mpImplData->meJobState != view::PrintableState_JOB_STARTED )
+ return;
+
+ GDIMetaFile aPageFile;
+ PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile );
+
+ if( mpImplData->mpProgress )
+ {
+ // do nothing if printing is canceled
+ if( mpImplData->mpProgress->isCanceled() )
+ {
+ setJobState( view::PrintableState_JOB_ABORTED );
+ return;
+ }
+ }
+
+ // in N-Up printing set the correct page size
+ mpImplData->mpPrinter->SetMapMode( MAP_100TH_MM );
+ // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile()
+ mpImplData->mpPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() );
+
+ // if full paper are is meant, move the output to accomodate for pageoffset
+ if( aPageSize.bFullPaper )
+ {
+ Point aPageOffset( mpImplData->mpPrinter->GetPageOffset() );
+ aPageFile.WindStart();
+ aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y() );
+ }
+
+ GDIMetaFile aCleanedFile;
+ ULONG nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile );
+
+ mpImplData->mpPrinter->EnableOutput( TRUE );
+
+ // actually print the page
+ mpImplData->mpPrinter->ImplStartPage();
+
+ mpImplData->mpPrinter->Push();
+ aCleanedFile.WindStart();
+ aCleanedFile.Play( mpImplData->mpPrinter.get() );
+ mpImplData->mpPrinter->Pop();
+
+ mpImplData->mpPrinter->ImplEndPage();
+
+ mpImplData->mpPrinter->SetDrawMode( nRestoreDrawMode );
+}
+
+void PrinterController::jobStarted()
+{
+}
+
+void PrinterController::jobFinished( view::PrintableState )
+{
+}
+
+void PrinterController::abortJob()
+{
+ setJobState( view::PrintableState_JOB_ABORTED );
+}
+
+void PrinterController::setLastPage( sal_Bool i_bLastPage )
+{
+ mpImplData->mbLastPage = i_bLastPage;
+}
+
+void PrinterController::setReversePrint( sal_Bool i_bReverse )
+{
+ mpImplData->mbReversePageOrder = i_bReverse;
+}
+
+bool PrinterController::getReversePrint() const
+{
+ return mpImplData->mbReversePageOrder;
+}
+
+Sequence< PropertyValue > PrinterController::getJobProperties( const Sequence< PropertyValue >& i_rMergeList ) const
+{
+ std::hash_set< rtl::OUString, rtl::OUStringHash > aMergeSet;
+ size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3;
+ for( int i = 0; i < i_rMergeList.getLength(); i++ )
+ aMergeSet.insert( i_rMergeList[i].Name );
+
+ Sequence< PropertyValue > aResult( nResultLen );
+ for( int i = 0; i < i_rMergeList.getLength(); i++ )
+ aResult[i] = i_rMergeList[i];
+ int nCur = i_rMergeList.getLength();
+ for( size_t i = 0; i < mpImplData->maUIProperties.size(); i++ )
+ {
+ if( aMergeSet.find( mpImplData->maUIProperties[i].Name ) == aMergeSet.end() )
+ aResult[nCur++] = mpImplData->maUIProperties[i];
+ }
+ // append IsFirstPage
+ if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ) ) == aMergeSet.end() )
+ {
+ PropertyValue aVal;
+ aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) );
+ aVal.Value <<= mpImplData->mbFirstPage;
+ aResult[nCur++] = aVal;
+ }
+ // append IsLastPage
+ if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ) ) == aMergeSet.end() )
+ {
+ PropertyValue aVal;
+ aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) );
+ aVal.Value <<= mpImplData->mbLastPage;
+ aResult[nCur++] = aVal;
+ }
+ // append IsPrinter
+ if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ) ) == aMergeSet.end() )
+ {
+ PropertyValue aVal;
+ aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) );
+ aVal.Value <<= sal_True;
+ aResult[nCur++] = aVal;
+ }
+ aResult.realloc( nCur );
+ return aResult;
+}
+
+const Sequence< beans::PropertyValue >& PrinterController::getUIOptions() const
+{
+ return mpImplData->maUIOptions;
+}
+
+beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty )
+{
+ std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
+ mpImplData->maPropertyToIndex.find( i_rProperty );
+ return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL;
+}
+
+const beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) const
+{
+ std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
+ mpImplData->maPropertyToIndex.find( i_rProperty );
+ return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL;
+}
+
+Sequence< beans::PropertyValue > PrinterController::getValues( const Sequence< rtl::OUString >& i_rNames ) const
+{
+ Sequence< beans::PropertyValue > aRet( i_rNames.getLength() );
+ sal_Int32 nFound = 0;
+ for( sal_Int32 i = 0; i < i_rNames.getLength(); i++ )
+ {
+ const beans::PropertyValue* pVal = getValue( i_rNames[i] );
+ if( pVal )
+ aRet[ nFound++ ] = *pVal;
+ }
+ aRet.realloc( nFound );
+ return aRet;
+}
+
+void PrinterController::setValue( const rtl::OUString& i_rName, const Any& i_rValue )
+{
+ beans::PropertyValue aVal;
+ aVal.Name = i_rName;
+ aVal.Value = i_rValue;
+
+ setValue( aVal );
+}
+
+void PrinterController::setValue( const beans::PropertyValue& i_rValue )
+{
+ std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
+ mpImplData->maPropertyToIndex.find( i_rValue.Name );
+ if( it != mpImplData->maPropertyToIndex.end() )
+ mpImplData->maUIProperties[ it->second ] = i_rValue;
+ else
+ {
+ // insert correct index into property map
+ mpImplData->maPropertyToIndex[ i_rValue.Name ] = mpImplData->maUIProperties.size();
+ mpImplData->maUIProperties.push_back( i_rValue );
+ mpImplData->maUIPropertyEnabled.push_back( true );
+ }
+}
+
+void PrinterController::setUIOptions( const Sequence< beans::PropertyValue >& i_rOptions )
+{
+ DBG_ASSERT( mpImplData->maUIOptions.getLength() == 0, "setUIOptions called twice !" );
+
+ mpImplData->maUIOptions = i_rOptions;
+
+ for( int i = 0; i < i_rOptions.getLength(); i++ )
+ {
+ Sequence< beans::PropertyValue > aOptProp;
+ i_rOptions[i].Value >>= aOptProp;
+ bool bIsEnabled = true;
+ bool bHaveProperty = false;
+ rtl::OUString aPropName;
+ vcl::ImplPrinterControllerData::ControlDependency aDep;
+ for( int n = 0; n < aOptProp.getLength(); n++ )
+ {
+ const beans::PropertyValue& rEntry( aOptProp[ n ] );
+ if( rEntry.Name.equalsAscii( "Property" ) )
+ {
+ PropertyValue aVal;
+ rEntry.Value >>= aVal;
+ DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name )
+ == mpImplData->maPropertyToIndex.end(), "duplicate property entry" );
+ setValue( aVal );
+ aPropName = aVal.Name;
+ bHaveProperty = true;
+ }
+ else if( rEntry.Name.equalsAscii( "Enabled" ) )
+ {
+ sal_Bool bValue = sal_True;
+ rEntry.Value >>= bValue;
+ bIsEnabled = bValue;
+ }
+ else if( rEntry.Name.equalsAscii( "DependsOnName" ) )
+ {
+ rEntry.Value >>= aDep.maDependsOnName;
+ }
+ else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) )
+ {
+ rEntry.Value >>= aDep.mnDependsOnEntry;
+ }
+ }
+ if( bHaveProperty )
+ {
+ vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it =
+ mpImplData->maPropertyToIndex.find( aPropName );
+ // sanity check
+ if( it != mpImplData->maPropertyToIndex.end() )
+ {
+ mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled;
+ }
+ if( aDep.maDependsOnName.getLength() > 0 )
+ mpImplData->maControlDependencies[ aPropName ] = aDep;
+ }
+ }
+}
+
+void PrinterController::enableUIOption( const rtl::OUString& i_rProperty, bool i_bEnable )
+{
+ std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
+ mpImplData->maPropertyToIndex.find( i_rProperty );
+ if( it != mpImplData->maPropertyToIndex.end() )
+ {
+ // call handler only for actual changes
+ if( ( mpImplData->maUIPropertyEnabled[ it->second ] && ! i_bEnable ) ||
+ ( ! mpImplData->maUIPropertyEnabled[ it->second ] && i_bEnable ) )
+ {
+ mpImplData->maUIPropertyEnabled[ it->second ] = i_bEnable;
+ rtl::OUString aPropName( i_rProperty );
+ mpImplData->maOptionChangeHdl.Call( &aPropName );
+ }
+ }
+}
+
+bool PrinterController::isUIOptionEnabled( const rtl::OUString& i_rProperty ) const
+{
+ bool bEnabled = false;
+ std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator prop_it =
+ mpImplData->maPropertyToIndex.find( i_rProperty );
+ if( prop_it != mpImplData->maPropertyToIndex.end() )
+ {
+ bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second];
+
+ if( bEnabled )
+ {
+ // check control dependencies
+ vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
+ mpImplData->maControlDependencies.find( i_rProperty );
+ if( it != mpImplData->maControlDependencies.end() )
+ {
+ // check if the dependency is enabled
+ // if the dependency is disabled, we are too
+ bEnabled = isUIOptionEnabled( it->second.maDependsOnName );
+
+ if( bEnabled )
+ {
+ // does the dependency have the correct value ?
+ const com::sun::star::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName );
+ OSL_ENSURE( pVal, "unknown property in dependency" );
+ if( pVal )
+ {
+ sal_Int32 nDepVal = 0;
+ sal_Bool bDepVal = sal_False;
+ if( pVal->Value >>= nDepVal )
+ {
+ bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1);
+ }
+ else if( pVal->Value >>= bDepVal )
+ {
+ // could be a dependency on a checked boolean
+ // in this case the dependency is on a non zero for checked value
+ bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) ||
+ ( ! bDepVal && it->second.mnDependsOnEntry == 0);
+ }
+ else
+ {
+ // if the type does not match something is awry
+ OSL_ENSURE( 0, "strange type in control dependency" );
+ bEnabled = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return bEnabled;
+}
+
+rtl::OUString PrinterController::getDependency( const rtl::OUString& i_rProperty ) const
+{
+ rtl::OUString aDependency;
+
+ vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
+ mpImplData->maControlDependencies.find( i_rProperty );
+ if( it != mpImplData->maControlDependencies.end() )
+ aDependency = it->second.maDependsOnName;
+
+ return aDependency;
+}
+
+rtl::OUString PrinterController::makeEnabled( const rtl::OUString& i_rProperty )
+{
+ rtl::OUString aDependency;
+
+ vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
+ mpImplData->maControlDependencies.find( i_rProperty );
+ if( it != mpImplData->maControlDependencies.end() )
+ {
+ if( isUIOptionEnabled( it->second.maDependsOnName ) )
+ {
+ aDependency = it->second.maDependsOnName;
+ const com::sun::star::beans::PropertyValue* pVal = getValue( aDependency );
+ OSL_ENSURE( pVal, "unknown property in dependency" );
+ if( pVal )
+ {
+ sal_Int32 nDepVal = 0;
+ sal_Bool bDepVal = sal_False;
+ if( pVal->Value >>= nDepVal )
+ {
+ if( it->second.mnDependsOnEntry != -1 )
+ {
+ setValue( aDependency, makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) );
+ }
+ }
+ else if( pVal->Value >>= bDepVal )
+ {
+ setValue( aDependency, makeAny( sal_Bool( it->second.mnDependsOnEntry != 0 ) ) );
+ }
+ else
+ {
+ // if the type does not match something is awry
+ OSL_ENSURE( 0, "strange type in control dependency" );
+ }
+ }
+ }
+ }
+
+ return aDependency;
+}
+
+void PrinterController::setOptionChangeHdl( const Link& i_rHdl )
+{
+ mpImplData->maOptionChangeHdl = i_rHdl;
+}
+
+void PrinterController::createProgressDialog()
+{
+ if( ! mpImplData->mpProgress )
+ {
+ sal_Bool bShow = sal_True;
+ beans::PropertyValue* pMonitor = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) );
+ if( pMonitor )
+ pMonitor->Value >>= bShow;
+ else
+ {
+ const com::sun::star::beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ) );
+ if( pVal )
+ {
+ sal_Bool bApi = sal_False;
+ pVal->Value >>= bApi;
+ bShow = ! bApi;
+ }
+ }
+
+ if( bShow && ! Application::IsHeadlessModeEnabled() )
+ {
+ mpImplData->mpProgress = new PrintProgressDialog( NULL, getPageCountProtected() );
+ mpImplData->mpProgress->Show();
+ }
+ }
+ else
+ mpImplData->mpProgress->reset();
+}
+
+void PrinterController::setMultipage( const MultiPageSetup& i_rMPS )
+{
+ mpImplData->maMultiPage = i_rMPS;
+}
+
+const PrinterController::MultiPageSetup& PrinterController::getMultipage() const
+{
+ return mpImplData->maMultiPage;
+}
+
+void PrinterController::pushPropertiesToPrinter()
+{
+ sal_Int32 nCopyCount = 1;
+ // set copycount and collate
+ const beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) );
+ if( pVal )
+ pVal->Value >>= nCopyCount;
+ sal_Bool bCollate = sal_False;
+ pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) );
+ if( pVal )
+ pVal->Value >>= bCollate;
+ mpImplData->mpPrinter->SetCopyCount( static_cast<USHORT>(nCopyCount), bCollate );
+
+ // duplex mode
+ pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DuplexMode" ) ) );
+ if( pVal )
+ {
+ sal_Int16 nDuplex = view::DuplexMode::UNKNOWN;
+ pVal->Value >>= nDuplex;
+ switch( nDuplex )
+ {
+ case view::DuplexMode::OFF: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_OFF ); break;
+ case view::DuplexMode::LONGEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_LONGEDGE ); break;
+ case view::DuplexMode::SHORTEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_SHORTEDGE ); break;
+ }
+ }
+}
+
+bool PrinterController::isShowDialogs() const
+{
+ sal_Bool bApi = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ), sal_False );
+ return ! bApi && ! Application::IsHeadlessModeEnabled();
+}
+
+bool PrinterController::isDirectPrint() const
+{
+ sal_Bool bDirect = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ), sal_False );
+ return bDirect == sal_True;
+}
+
+sal_Bool PrinterController::getBoolProperty( const rtl::OUString& i_rProperty, sal_Bool i_bFallback ) const
+{
+ sal_Bool bRet = i_bFallback;
+ const com::sun::star::beans::PropertyValue* pVal = getValue( i_rProperty );
+ if( pVal )
+ pVal->Value >>= bRet;
+ return bRet;
+}
+
+/*
+ * PrinterOptionsHelper
+**/
+Any PrinterOptionsHelper::getValue( const rtl::OUString& i_rPropertyName ) const
+{
+ Any aRet;
+ std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it =
+ m_aPropertyMap.find( i_rPropertyName );
+ if( it != m_aPropertyMap.end() )
+ aRet = it->second;
+ return aRet;
+}
+
+void PrinterOptionsHelper::setValue( const rtl::OUString& i_rPropertyName, const Any& i_rValue )
+{
+ m_aPropertyMap[ i_rPropertyName ] = i_rValue;
+}
+
+bool PrinterOptionsHelper::hasProperty( const rtl::OUString& i_rPropertyName ) const
+{
+ Any aRet;
+ std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it =
+ m_aPropertyMap.find( i_rPropertyName );
+ return it != m_aPropertyMap.end();
+}
+
+sal_Bool PrinterOptionsHelper::getBoolValue( const rtl::OUString& i_rPropertyName, sal_Bool i_bDefault ) const
+{
+ sal_Bool bRet = sal_False;
+ Any aVal( getValue( i_rPropertyName ) );
+ return (aVal >>= bRet) ? bRet : i_bDefault;
+}
+
+sal_Int64 PrinterOptionsHelper::getIntValue( const rtl::OUString& i_rPropertyName, sal_Int64 i_nDefault ) const
+{
+ sal_Int64 nRet = 0;
+ Any aVal( getValue( i_rPropertyName ) );
+ return (aVal >>= nRet) ? nRet : i_nDefault;
+}
+
+rtl::OUString PrinterOptionsHelper::getStringValue( const rtl::OUString& i_rPropertyName, const rtl::OUString& i_rDefault ) const
+{
+ rtl::OUString aRet;
+ Any aVal( getValue( i_rPropertyName ) );
+ return (aVal >>= aRet) ? aRet : i_rDefault;
+}
+
+bool PrinterOptionsHelper::processProperties( const Sequence< PropertyValue >& i_rNewProp,
+ std::set< rtl::OUString >* o_pChangeProp )
+{
+ bool bChanged = false;
+
+ // clear the changed set
+ if( o_pChangeProp )
+ o_pChangeProp->clear();
+
+ sal_Int32 nElements = i_rNewProp.getLength();
+ const PropertyValue* pVals = i_rNewProp.getConstArray();
+ for( sal_Int32 i = 0; i < nElements; i++ )
+ {
+ bool bElementChanged = false;
+ std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::iterator it =
+ m_aPropertyMap.find( pVals[ i ].Name );
+ if( it != m_aPropertyMap.end() )
+ {
+ if( it->second != pVals[ i ].Value )
+ bElementChanged = true;
+ }
+ else
+ bElementChanged = true;
+
+ if( bElementChanged )
+ {
+ if( o_pChangeProp )
+ o_pChangeProp->insert( pVals[ i ].Name );
+ m_aPropertyMap[ pVals[i].Name ] = pVals[i].Value;
+ bChanged = true;
+ }
+ }
+ return bChanged;
+}
+
+void PrinterOptionsHelper::appendPrintUIOptions( uno::Sequence< beans::PropertyValue >& io_rProps ) const
+{
+ if( m_aUIProperties.getLength() > 0 )
+ {
+ sal_Int32 nIndex = io_rProps.getLength();
+ io_rProps.realloc( nIndex+1 );
+ PropertyValue aVal;
+ aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExtraPrintUIOptions" ) );
+ aVal.Value = makeAny( m_aUIProperties );
+ io_rProps[ nIndex ] = aVal;
+ }
+}
+
+Any PrinterOptionsHelper::getUIControlOpt( const rtl::OUString& i_rTitle,
+ const Sequence< rtl::OUString >& i_rHelpTexts,
+ const rtl::OUString& i_rType,
+ const PropertyValue* i_pVal,
+ const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
+ )
+{
+ sal_Int32 nElements =
+ 1 // ControlType
+ + (i_rTitle.getLength() ? 1 : 0) // Text
+ + (i_rHelpTexts.getLength() ? 1 : 0) // HelpText
+ + (i_pVal ? 1 : 0) // Property
+ + i_rControlOptions.maAddProps.getLength() // additional props
+ + (i_rControlOptions.maGroupHint.getLength() ? 1 : 0) // grouping
+ + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint
+ + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled
+ ;
+ if( i_rControlOptions.maDependsOnName.getLength() )
+ {
+ nElements += 1;
+ if( i_rControlOptions.mnDependsOnEntry != -1 )
+ nElements += 1;
+ if( i_rControlOptions.mbAttachToDependency )
+ nElements += 1;
+ }
+
+ Sequence< PropertyValue > aCtrl( nElements );
+ sal_Int32 nUsed = 0;
+ if( i_rTitle.getLength() )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) );
+ aCtrl[nUsed++].Value = makeAny( i_rTitle );
+ }
+ if( i_rHelpTexts.getLength() )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpText" ) );
+ aCtrl[nUsed++].Value = makeAny( i_rHelpTexts );
+ }
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlType" ) );
+ aCtrl[nUsed++].Value = makeAny( i_rType );
+ if( i_pVal )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Property" ) );
+ aCtrl[nUsed++].Value = makeAny( *i_pVal );
+ }
+ if( i_rControlOptions.maDependsOnName.getLength() )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnName" ) );
+ aCtrl[nUsed++].Value = makeAny( i_rControlOptions.maDependsOnName );
+ if( i_rControlOptions.mnDependsOnEntry != -1 )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnEntry" ) );
+ aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mnDependsOnEntry );
+ }
+ if( i_rControlOptions.mbAttachToDependency )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AttachToDependency" ) );
+ aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mbAttachToDependency );
+ }
+ }
+ if( i_rControlOptions.maGroupHint.getLength() )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GroupingHint" ) );
+ aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint;
+ }
+ if( i_rControlOptions.mbInternalOnly )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InternalUIOnly" ) );
+ aCtrl[nUsed++].Value <<= sal_True;
+ }
+ if( ! i_rControlOptions.mbEnabled )
+ {
+ aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) );
+ aCtrl[nUsed++].Value <<= sal_False;
+ }
+
+ sal_Int32 nAddProps = i_rControlOptions.maAddProps.getLength();
+ for( sal_Int32 i = 0; i < nAddProps; i++ )
+ aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i];
+
+ DBG_ASSERT( nUsed == nElements, "nUsed != nElements, probable heap corruption" );
+
+ return makeAny( aCtrl );
+}
+
+Any PrinterOptionsHelper::getGroupControlOpt( const rtl::OUString& i_rTitle, const rtl::OUString& i_rHelpText )
+{
+ Sequence< rtl::OUString > aHelpText;
+ if( i_rHelpText.getLength() > 0 )
+ {
+ aHelpText.realloc( 1 );
+ *aHelpText.getArray() = i_rHelpText;
+ }
+ return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Group" ) ) );
+}
+
+Any PrinterOptionsHelper::getSubgroupControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
+ )
+{
+ Sequence< rtl::OUString > aHelpText;
+ if( i_rHelpText.getLength() > 0 )
+ {
+ aHelpText.realloc( 1 );
+ *aHelpText.getArray() = i_rHelpText;
+ }
+ return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Subgroup" ) ),
+ NULL, i_rControlOptions );
+}
+
+Any PrinterOptionsHelper::getBoolControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ sal_Bool i_bValue,
+ const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
+ )
+{
+ Sequence< rtl::OUString > aHelpText;
+ if( i_rHelpText.getLength() > 0 )
+ {
+ aHelpText.realloc( 1 );
+ *aHelpText.getArray() = i_rHelpText;
+ }
+ PropertyValue aVal;
+ aVal.Name = i_rProperty;
+ aVal.Value = makeAny( i_bValue );
+ return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Bool" ) ), &aVal, i_rControlOptions );
+}
+
+Any PrinterOptionsHelper::getChoiceControlOpt( const rtl::OUString& i_rTitle,
+ const Sequence< rtl::OUString >& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ const Sequence< rtl::OUString >& i_rChoices,
+ sal_Int32 i_nValue,
+ const rtl::OUString& i_rType,
+ const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
+ )
+{
+ UIControlOptions aOpt( i_rControlOptions );
+ sal_Int32 nUsed = aOpt.maAddProps.getLength();
+ aOpt.maAddProps.realloc( nUsed + 1 );
+ aOpt.maAddProps[nUsed].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Choices" ) );
+ aOpt.maAddProps[nUsed].Value = makeAny( i_rChoices );
+
+ PropertyValue aVal;
+ aVal.Name = i_rProperty;
+ aVal.Value = makeAny( i_nValue );
+ return getUIControlOpt( i_rTitle, i_rHelpText, i_rType, &aVal, aOpt );
+}
+
+Any PrinterOptionsHelper::getRangeControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ sal_Int32 i_nValue,
+ sal_Int32 i_nMinValue,
+ sal_Int32 i_nMaxValue,
+ const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
+ )
+{
+ UIControlOptions aOpt( i_rControlOptions );
+ if( i_nMaxValue >= i_nMinValue )
+ {
+ sal_Int32 nUsed = aOpt.maAddProps.getLength();
+ aOpt.maAddProps.realloc( nUsed + 2 );
+ aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MinValue" ) );
+ aOpt.maAddProps[nUsed++].Value = makeAny( i_nMinValue );
+ aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxValue" ) );
+ aOpt.maAddProps[nUsed++].Value = makeAny( i_nMaxValue );
+ }
+
+ Sequence< rtl::OUString > aHelpText;
+ if( i_rHelpText.getLength() > 0 )
+ {
+ aHelpText.realloc( 1 );
+ *aHelpText.getArray() = i_rHelpText;
+ }
+ PropertyValue aVal;
+ aVal.Name = i_rProperty;
+ aVal.Value = makeAny( i_nValue );
+ return getUIControlOpt( i_rTitle,
+ aHelpText,
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Range" ) ),
+ &aVal,
+ aOpt
+ );
+}
+
+Any PrinterOptionsHelper::getEditControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ const rtl::OUString& i_rValue,
+ const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
+ )
+{
+ Sequence< rtl::OUString > aHelpText;
+ if( i_rHelpText.getLength() > 0 )
+ {
+ aHelpText.realloc( 1 );
+ *aHelpText.getArray() = i_rHelpText;
+ }
+ PropertyValue aVal;
+ aVal.Name = i_rProperty;
+ aVal.Value = makeAny( i_rValue );
+ return getUIControlOpt( i_rTitle,
+ aHelpText,
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Edit" ) ),
+ &aVal,
+ i_rControlOptions
+ );
+}
diff --git a/vcl/source/gdi/regband.cxx b/vcl/source/gdi/regband.cxx
new file mode 100644
index 000000000000..14f45b4beafd
--- /dev/null
+++ b/vcl/source/gdi/regband.cxx
@@ -0,0 +1,969 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/regband.hxx>
+
+#include <algorithm>
+
+
+// =======================================================================
+//
+// ImplRegionBand
+//
+// Jedes Band enthaelt die zwischen der enthaltenen Ober- und Untergrenze
+// enthaltenen Rechtecke. Bei den Operationen Union, Intersect, XOr und
+// Exclude werden immer Rechtecke der gleichen Hoehe ausgewerte; die
+// Grenzen der Baender sind immer so zu waehlen, dasz dies moeglich ist.
+//
+// Die Rechtecke in den Baendern werden nach Moeglichkeit zusammengefaszt.
+//
+// Bei der Umwandlung von Polygonen werden alle Punkte des Polygons
+// in die einzelnen Baender eingetragen (sie stehen fuer jedes Band als
+// Punkte in einer Liste). Nach dem Eintragen der Punkte werden diese
+// in Rechtecke umgewandelt und die Liste der Punkte geloescht.
+//
+// -----------------------------------------------------------------------
+
+ImplRegionBand::ImplRegionBand( long nTop, long nBottom )
+{
+ // save boundaries
+ mnYTop = nTop;
+ mnYBottom = nBottom;
+
+ // initialize lists
+ mpNextBand = NULL;
+ mpPrevBand = NULL;
+ mpFirstSep = NULL;
+ mpFirstBandPoint = NULL;
+ mbTouched = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegionBand::ImplRegionBand(
+ const ImplRegionBand& rRegionBand,
+ const bool bIgnorePoints)
+{
+ // copy boundaries
+ mnYTop = rRegionBand.mnYTop;
+ mnYBottom = rRegionBand.mnYBottom;
+ mbTouched = rRegionBand.mbTouched;
+
+ // initialisation
+ mpNextBand = NULL;
+ mpPrevBand = NULL;
+ mpFirstSep = NULL;
+ mpFirstBandPoint = NULL;
+
+ // copy all elements of the list with separations
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = rRegionBand.mpFirstSep;
+ while ( pSep )
+ {
+ // create new and copy data
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = pSep->mnXLeft;
+ pNewSep->mnXRight = pSep->mnXRight;
+ pNewSep->mbRemoved = pSep->mbRemoved;
+ pNewSep->mpNextSep = NULL;
+ if ( pSep == rRegionBand.mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+
+ pPrevSep = pNewSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ if ( ! bIgnorePoints)
+ {
+ // Copy points.
+ ImplRegionBandPoint* pPoint = rRegionBand.mpFirstBandPoint;
+ ImplRegionBandPoint* pPrevPointCopy = NULL;
+ while (pPoint != NULL)
+ {
+ ImplRegionBandPoint* pPointCopy = new ImplRegionBandPoint();
+ pPointCopy->mnX = pPoint->mnX;
+ pPointCopy->mnLineId = pPoint->mnLineId;
+ pPointCopy->mbEndPoint = pPoint->mbEndPoint;
+ pPointCopy->meLineType = pPoint->meLineType;
+
+ if (pPrevPointCopy != NULL)
+ pPrevPointCopy->mpNextBandPoint = pPointCopy;
+ else
+ mpFirstBandPoint = pPointCopy;
+
+ pPrevPointCopy = pPointCopy;
+ pPoint = pPoint->mpNextBandPoint;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegionBand::~ImplRegionBand()
+{
+ DBG_ASSERT( mpFirstBandPoint == NULL, "ImplRegionBand::~ImplRegionBand -> pointlist not empty" );
+
+ // delete elements of the list
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ ImplRegionBandSep* pTempSep = pSep->mpNextSep;
+ delete pSep;
+ pSep = pTempSep;
+ }
+
+ // delete elements of the list
+ ImplRegionBandPoint* pPoint = mpFirstBandPoint;
+ while ( pPoint )
+ {
+ ImplRegionBandPoint* pTempPoint = pPoint->mpNextBandPoint;
+ delete pPoint;
+ pPoint = pTempPoint;
+ }
+}
+
+// -----------------------------------------------------------------------
+//
+// generate separations from lines and process union with existing
+// separations
+
+void ImplRegionBand::ProcessPoints()
+{
+ // check Pointlist
+ ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
+ while ( pRegionBandPoint )
+ {
+ // within list?
+ if ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
+ {
+ // start/stop?
+ if ( pRegionBandPoint->mbEndPoint && pRegionBandPoint->mpNextBandPoint->mbEndPoint )
+ {
+ // same direction? -> remove next point!
+ if ( pRegionBandPoint->meLineType == pRegionBandPoint->mpNextBandPoint->meLineType )
+ {
+ ImplRegionBandPoint* pSaveRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ pRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
+ delete pSaveRegionBandPoint;
+ }
+ }
+ }
+
+ // continue with next element in the list
+ pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ }
+
+ pRegionBandPoint = mpFirstBandPoint;
+ while ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
+ {
+ Union( pRegionBandPoint->mnX, pRegionBandPoint->mpNextBandPoint->mnX );
+
+ ImplRegionBandPoint* pNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
+
+ // remove allready processed points
+ delete pRegionBandPoint->mpNextBandPoint;
+ delete pRegionBandPoint;
+
+ // continue with next element in the list
+ pRegionBandPoint = pNextBandPoint;
+ }
+
+ // remove last element if necessary
+ if ( pRegionBandPoint )
+ delete pRegionBandPoint;
+
+ // list is now empty
+ mpFirstBandPoint = NULL;
+}
+
+// -----------------------------------------------------------------------
+//
+// generate separations from lines and process union with existing
+// separations
+
+BOOL ImplRegionBand::InsertPoint( long nX, long nLineId,
+ BOOL bEndPoint, LineType eLineType )
+{
+ if ( !mpFirstBandPoint )
+ {
+ mpFirstBandPoint = new ImplRegionBandPoint;
+ mpFirstBandPoint->mnX = nX;
+ mpFirstBandPoint->mnLineId = nLineId;
+ mpFirstBandPoint->mbEndPoint = bEndPoint;
+ mpFirstBandPoint->meLineType = eLineType;
+ mpFirstBandPoint->mpNextBandPoint = NULL;
+ return TRUE;
+ }
+
+ // look if line allready touched the band
+ ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
+ ImplRegionBandPoint* pLastTestedRegionBandPoint = NULL;
+ while( pRegionBandPoint )
+ {
+ if ( pRegionBandPoint->mnLineId == nLineId )
+ {
+ if ( bEndPoint )
+ {
+ if( !pRegionBandPoint->mbEndPoint )
+ {
+ // remove old band point
+ if( !mpFirstBandPoint->mpNextBandPoint )
+ {
+ // if we've only got one point => replace first point
+ pRegionBandPoint->mnX = nX;
+ pRegionBandPoint->mbEndPoint = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ // remove current point
+ if( !pLastTestedRegionBandPoint )
+ {
+ // remove and delete old first point
+ ImplRegionBandPoint* pSaveBandPoint = mpFirstBandPoint;
+ mpFirstBandPoint = mpFirstBandPoint->mpNextBandPoint;
+ delete pSaveBandPoint;
+ }
+ else
+ {
+ // remove and delete current band point
+ pLastTestedRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint;
+ delete pRegionBandPoint;
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ return FALSE;
+ }
+
+ // use next element
+ pLastTestedRegionBandPoint = pRegionBandPoint;
+ pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ }
+
+ // search appropriate position and insert point into the list
+ ImplRegionBandPoint* pNewRegionBandPoint;
+
+ pRegionBandPoint = mpFirstBandPoint;
+ pLastTestedRegionBandPoint = NULL;
+ while ( pRegionBandPoint )
+ {
+ // new point completly left? -> insert as first point
+ if ( nX <= pRegionBandPoint->mnX )
+ {
+ pNewRegionBandPoint = new ImplRegionBandPoint;
+ pNewRegionBandPoint->mnX = nX;
+ pNewRegionBandPoint->mnLineId = nLineId;
+ pNewRegionBandPoint->mbEndPoint = bEndPoint;
+ pNewRegionBandPoint->meLineType = eLineType;
+ pNewRegionBandPoint->mpNextBandPoint = pRegionBandPoint;
+
+ // connections to the new point
+ if ( !pLastTestedRegionBandPoint )
+ mpFirstBandPoint = pNewRegionBandPoint;
+ else
+ pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
+
+ return TRUE;
+ }
+
+ // use next element
+ pLastTestedRegionBandPoint = pRegionBandPoint;
+ pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ }
+
+ // not inserted -> add to the end of the list
+ pNewRegionBandPoint = new ImplRegionBandPoint;
+ pNewRegionBandPoint->mnX = nX;
+ pNewRegionBandPoint->mnLineId = nLineId;
+ pNewRegionBandPoint->mbEndPoint = bEndPoint;
+ pNewRegionBandPoint->meLineType = eLineType;
+ pNewRegionBandPoint->mpNextBandPoint = NULL;
+
+ // connections to the new point
+ pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::MoveX( long nHorzMove )
+{
+ // move all x-separations
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ pSep->mnXLeft += nHorzMove;
+ pSep->mnXRight += nHorzMove;
+ pSep = pSep->mpNextSep;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::ScaleX( double fHorzScale )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ pSep->mnXLeft = FRound( pSep->mnXLeft * fHorzScale );
+ pSep->mnXRight = FRound( pSep->mnXRight * fHorzScale );
+ pSep = pSep->mpNextSep;
+ }
+}
+
+// -----------------------------------------------------------------------
+//
+// combine overlaping sparations
+
+BOOL ImplRegionBand::OptimizeBand()
+{
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ // remove?
+ if ( pSep->mbRemoved || (pSep->mnXRight < pSep->mnXLeft) )
+ {
+ ImplRegionBandSep* pOldSep = pSep;
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pSep->mpNextSep;
+ else
+ pPrevSep->mpNextSep = pSep->mpNextSep;
+ pSep = pSep->mpNextSep;
+ delete pOldSep;
+ continue;
+ }
+
+ // overlaping separations? -> combine!
+ if ( pSep->mpNextSep )
+ {
+ if ( (pSep->mnXRight+1) >= pSep->mpNextSep->mnXLeft )
+ {
+ if ( pSep->mpNextSep->mnXRight > pSep->mnXRight )
+ pSep->mnXRight = pSep->mpNextSep->mnXRight;
+
+ ImplRegionBandSep* pOldSep = pSep->mpNextSep;
+ pSep->mpNextSep = pOldSep->mpNextSep;
+ delete pOldSep;
+ continue;
+ }
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::Union( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Union(): nxLeft > nXRight" );
+
+ // band empty? -> add element
+ if ( !mpFirstSep )
+ {
+ mpFirstSep = new ImplRegionBandSep;
+ mpFirstSep->mnXLeft = nXLeft;
+ mpFirstSep->mnXRight = nXRight;
+ mpFirstSep->mbRemoved = FALSE;
+ mpFirstSep->mpNextSep = NULL;
+ return;
+ }
+
+ // process real union
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ // new separation completely inside? nothing to do!
+ if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
+ return;
+
+ // new separation completly left? -> new separation!
+ if ( nXRight < pSep->mnXLeft )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mbRemoved = FALSE;
+
+ pNewSep->mpNextSep = pSep;
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+ break;
+ }
+
+ // new separation overlaping from left? -> extend boundary
+ if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
+ pSep->mnXLeft = nXLeft;
+
+ // new separation overlaping from right? -> extend boundary
+ if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
+ {
+ pSep->mnXRight = nXRight;
+ break;
+ }
+
+ // not inserted, but last element? -> add to the end of the list
+ if ( !pSep->mpNextSep && (nXLeft > pSep->mnXRight) )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mbRemoved = FALSE;
+
+ pSep->mpNextSep = pNewSep;
+ pNewSep->mpNextSep = NULL;
+ break;
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::Intersect( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Intersect(): nxLeft > nXRight" );
+
+ // band has been touched
+ mbTouched = TRUE;
+
+ // band empty? -> nothing to do
+ if ( !mpFirstSep )
+ return;
+
+ // process real intersection
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ // new separation completly outside? -> remove separation
+ if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) )
+ // will be removed from the optimizer
+ pSep->mbRemoved = TRUE;
+
+ // new separation overlaping from left? -> reduce right boundary
+ if ( (nXLeft <= pSep->mnXLeft) &&
+ (nXRight <= pSep->mnXRight) &&
+ (nXRight >= pSep->mnXLeft) )
+ pSep->mnXRight = nXRight;
+
+ // new separation overlaping from right? -> reduce right boundary
+ if ( (nXLeft >= pSep->mnXLeft) &&
+ (nXLeft <= pSep->mnXRight) &&
+ (nXRight >= pSep->mnXRight) )
+ pSep->mnXLeft = nXLeft;
+
+ // new separation within the actual one? -> reduce both boundaries
+ if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
+ {
+ pSep->mnXRight = nXRight;
+ pSep->mnXLeft = nXLeft;
+ }
+
+ pSep = pSep->mpNextSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::Exclude( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Exclude(): nxLeft > nXRight" );
+
+ // band has been touched
+ mbTouched = TRUE;
+
+ // band empty? -> nothing to do
+ if ( !mpFirstSep )
+ return;
+
+ // process real exclusion
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ BOOL bSepProcessed = FALSE;
+
+ // new separation completely overlapping? -> remove separation
+ if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) )
+ {
+ // will be removed from the optimizer
+ pSep->mbRemoved = TRUE;
+ bSepProcessed = TRUE;
+ }
+
+ // new separation overlaping from left? -> reduce boundary
+ if ( !bSepProcessed )
+ {
+ if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
+ {
+ pSep->mnXLeft = nXRight+1;
+ bSepProcessed = TRUE;
+ }
+ }
+
+ // new separation overlaping from right? -> reduce boundary
+ if ( !bSepProcessed )
+ {
+ if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
+ {
+ pSep->mnXRight = nXLeft-1;
+ bSepProcessed = TRUE;
+ }
+ }
+
+ // new separation within the actual one? -> reduce boundary
+ // and add new entry for reminder
+ if ( !bSepProcessed )
+ {
+ if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = pSep->mnXLeft;
+ pNewSep->mnXRight = nXLeft-1;
+ pNewSep->mbRemoved = FALSE;
+
+ pSep->mnXLeft = nXRight+1;
+
+ // connections from the new separation
+ pNewSep->mpNextSep = pSep;
+
+ // connections to the new separation
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+ }
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::XOr( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::XOr(): nxLeft > nXRight" );
+
+ // #i46602# Reworked rectangle Xor
+ //
+ // In general, we can distinguish 11 cases of intersection
+ // (details below). The old implementation explicitely handled 7
+ // cases (numbered in the order of appearance, use CVS to get your
+ // hands on the old version), therefore, I've sticked to that
+ // order, and added four more cases. The code below references
+ // those numbers via #1, #2, etc.
+ //
+ // Num Mnem newX:oldX newY:oldY Description Result Can quit?
+ //
+ // #1 Empty band - - The band is empty, thus, simply add new bandSep just add Yes
+ //
+ // #2 apart - - The rectangles are disjunct, add new one as is just add Yes
+ //
+ // #3 atop == == The rectangles are _exactly_ the same, remove existing just remove Yes
+ //
+ // #4 around < > The new rectangle extends the old to both sides intersect No
+ //
+ // #5 left < < The new rectangle is left of the old (but intersects) intersect Yes
+ //
+ // #5b left-atop < == The new is left of the old, and coincides on the right intersect Yes
+ //
+ // #6 right > > The new is right of the old (but intersects) intersect No
+ //
+ // #6b right-atop == > The new is right of the old, and coincides on the left intersect No
+ //
+ // #7 inside > < The new is fully inside the old intersect Yes
+ //
+ // #8 inside-right > == The new is fully inside the old, coincides on the right intersect Yes
+ //
+ // #9 inside-left == < The new is fully inside the old, coincides on the left intersect Yes
+ //
+ //
+ // Then, to correctly perform XOr, the segment that's switched off
+ // (i.e. the overlapping part of the old and the new segment) must
+ // be extended by one pixel value at each border:
+ // 1 1
+ // 0 4 0 4
+ // 111100000001111
+ //
+ // Clearly, the leading band sep now goes from 0 to 3, and the
+ // trailing band sep from 11 to 14. This mimicks the xor look of a
+ // bitmap operation.
+ //
+
+ // band empty? -> add element
+ if ( !mpFirstSep )
+ {
+ mpFirstSep = new ImplRegionBandSep;
+ mpFirstSep->mnXLeft = nXLeft;
+ mpFirstSep->mnXRight = nXRight;
+ mpFirstSep->mbRemoved = FALSE;
+ mpFirstSep->mpNextSep = NULL;
+ return;
+ }
+
+ // process real xor
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+
+ while ( pSep )
+ {
+ long nOldLeft( pSep->mnXLeft );
+ long nOldRight( pSep->mnXRight );
+
+ // did the current segment actually touch the new rect? If
+ // not, skip all comparisons, go on, loop and try to find
+ // intersecting bandSep
+ if( nXLeft <= nOldRight )
+ {
+ if( nXRight < nOldLeft )
+ {
+ // #2
+
+ // add _before_ current bandSep
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mpNextSep = pSep;
+ pNewSep->mbRemoved = FALSE;
+
+ // connections from the new separation
+ pNewSep->mpNextSep = pSep;
+
+ // connections to the new separation
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ else if( nXLeft == nOldLeft && nXRight == nOldRight )
+ {
+ // #3
+ pSep->mbRemoved = TRUE;
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ else if( nXLeft != nOldLeft && nXRight == nOldRight )
+ {
+ // # 5b, 8
+ if( nXLeft < nOldLeft )
+ {
+ nXRight = nOldLeft; // 5b
+ }
+ else
+ {
+ nXRight = nXLeft; // 8
+ nXLeft = nOldLeft;
+ }
+
+ pSep->mnXLeft = nXLeft;
+ pSep->mnXRight = nXRight-1;
+
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ else if( nXLeft == nOldLeft && nXRight != nOldRight )
+ {
+ // # 6b, 9
+
+ if( nXRight > nOldRight )
+ {
+ nXLeft = nOldRight+1; // 6b
+
+ // cannot break here, simply mark segment as removed,
+ // and go on with adapted nXLeft/nXRight
+ pSep->mbRemoved = TRUE;
+ }
+ else
+ {
+ pSep->mnXLeft = nXRight+1; // 9
+
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ }
+ else // if( nXLeft != nOldLeft && nXRight != nOldRight ) follows automatically
+ {
+ // #4,5,6,7
+ DBG_ASSERT( nXLeft != nOldLeft && nXRight != nOldRight,
+ "ImplRegionBand::XOr(): Case 4,5,6,7 expected all coordinates to be not equal!" );
+
+ // The plain-jane check would look like this:
+ //
+ // if( nXLeft < nOldLeft )
+ // {
+ // // #4,5
+ // if( nXRight > nOldRight )
+ // {
+ // // #4
+ // }
+ // else
+ // {
+ // // #5 done!
+ // }
+ // }
+ // else
+ // {
+ // // #6,7
+ // if( nXRight > nOldRight )
+ // {
+ // // #6
+ // }
+ // else
+ // {
+ // // #7 done!
+ // }
+ // }
+ //
+ // but since we generally don't have to care whether
+ // it's 4 or 6 (only that we must not stop processing
+ // here), condensed that in such a way that only the
+ // coordinates get shuffled into correct ordering.
+
+ if( nXLeft < nOldLeft )
+ ::std::swap( nOldLeft, nXLeft );
+
+ bool bDone( false );
+
+ if( nXRight < nOldRight )
+ {
+ ::std::swap( nOldRight, nXRight );
+ bDone = true;
+ }
+
+ // now, nOldLeft<nXLeft<=nOldRight<nXRight always
+ // holds. Note that we need the nXLeft<=nOldRight here, as
+ // the intersection part might be only one pixel (original
+ // nXLeft==nXRight)
+ DBG_ASSERT( nOldLeft<nXLeft && nXLeft<=nOldRight && nOldRight<nXRight,
+ "ImplRegionBand::XOr(): Case 4,5,6,7 expected coordinates to be ordered now!" );
+
+ pSep->mnXLeft = nOldLeft;
+ pSep->mnXRight = nXLeft-1;
+
+ nXLeft = nOldRight+1;
+ // nxRight is already setup correctly
+
+ if( bDone )
+ {
+ // add behind current bandSep
+ pNewSep = new ImplRegionBandSep;
+
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mpNextSep = pSep->mpNextSep;
+ pNewSep->mbRemoved = FALSE;
+
+ // connections from the new separation
+ pSep->mpNextSep = pNewSep;
+
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ }
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ // new separation completely right of existing bandSeps ?
+ if( pPrevSep && nXLeft >= pPrevSep->mnXRight )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mpNextSep = NULL;
+ pNewSep->mbRemoved = FALSE;
+
+ // connections from the new separation
+ pPrevSep->mpNextSep = pNewSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::IsInside( long nX )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ if ( (pSep->mnXLeft <= nX) && (pSep->mnXRight >= nX) )
+ return TRUE;
+
+ pSep = pSep->mpNextSep;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::IsOver( long nLeft, long nRight )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ if ( (pSep->mnXLeft < nRight) && (pSep->mnXRight > nLeft) )
+ return TRUE;
+
+ pSep = pSep->mpNextSep;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::IsInside( long nLeft, long nRight )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ if ( (pSep->mnXLeft >= nLeft) && (nRight <= pSep->mnXRight) )
+ return TRUE;
+
+ pSep = pSep->mpNextSep;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplRegionBand::GetXLeftBoundary() const
+{
+ DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XLeftBoundary -> no separation in band!" );
+
+ return mpFirstSep->mnXLeft;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplRegionBand::GetXRightBoundary() const
+{
+ DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XRightBoundary -> no separation in band!" );
+
+ // search last separation
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep->mpNextSep )
+ pSep = pSep->mpNextSep;
+ return pSep->mnXRight;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const
+{
+ ImplRegionBandSep* pOwnRectBandSep = mpFirstSep;
+ ImplRegionBandSep* pSecondRectBandSep = rRegionBand.mpFirstSep;
+ while ( pOwnRectBandSep && pSecondRectBandSep )
+ {
+ // get boundaries of current rectangle
+ long nOwnXLeft = pOwnRectBandSep->mnXLeft;
+ long nSecondXLeft = pSecondRectBandSep->mnXLeft;
+ if ( nOwnXLeft != nSecondXLeft )
+ return FALSE;
+
+ long nOwnXRight = pOwnRectBandSep->mnXRight;
+ long nSecondXRight = pSecondRectBandSep->mnXRight;
+ if ( nOwnXRight != nSecondXRight )
+ return FALSE;
+
+ // get next separation from current band
+ pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
+
+ // get next separation from current band
+ pSecondRectBandSep = pSecondRectBandSep->mpNextSep;
+ }
+
+ // differnt number of separations?
+ if ( pOwnRectBandSep || pSecondRectBandSep )
+ return FALSE;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegionBand* ImplRegionBand::SplitBand (const sal_Int32 nY)
+{
+ OSL_ASSERT(nY>mnYTop);
+ OSL_ASSERT(nY<=mnYBottom);
+
+ // Create a copy of the given band (we tell the constructor to copy the points together
+ // with the seps.)
+ ImplRegionBand* pLowerBand = new ImplRegionBand(*this, false);
+
+ // Adapt vertical coordinates.
+ mnYBottom = nY-1;
+ pLowerBand->mnYTop = nY;
+
+ // Insert new band into list of bands.
+ pLowerBand->mpNextBand = mpNextBand;
+ mpNextBand = pLowerBand;
+ pLowerBand->mpPrevBand = this;
+ if (pLowerBand->mpNextBand != NULL)
+ pLowerBand->mpNextBand->mpPrevBand = pLowerBand;
+
+ return pLowerBand;
+}
diff --git a/vcl/source/gdi/region.cxx b/vcl/source/gdi/region.cxx
new file mode 100644
index 000000000000..4931ee66e93f
--- /dev/null
+++ b/vcl/source/gdi/region.cxx
@@ -0,0 +1,2932 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <limits.h>
+#include <tools/vcompat.hxx>
+#include <vcl/salbtype.hxx>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+#ifndef _REGION_H
+#include <vcl/region.h>
+#endif
+#ifndef _REGION_HXX
+#include <vcl/region.hxx>
+#endif
+#ifndef _REGBAND_HXX
+#include <vcl/regband.hxx>
+#endif
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+// =======================================================================
+//
+// ImplRegionBand
+//
+// Die Klassen RegionBand/ImplRegionBand speichert Regionen in Form von
+// Rechtecken ab. Die Region ist in Y-Richtung in Baendern unterteilt, die
+// wiederum ein oder mehrere Rechtecke mit der Hoehe des Bandes enthalten.
+//
+// Leere Baender werden entfernt.
+//
+// Polygone und PolyPolygone werden ebenfalls in Rechtecke zerlegt und in
+// der Baendern abgelegt. Hierzu werden alle Punkte der einzelnen Polygone
+// mit dem Bresenham-Algorithmus berechnet und in die Baender eingetragen.
+// Nach der vollstaendigen Berechung aller Kanten werden die entsprechenden
+// Rechntecke berechnet
+
+// =======================================================================
+
+static ImplRegionBase aImplNullRegion( 0 );
+static ImplRegionBase aImplEmptyRegion( 0 );
+
+// =======================================================================
+
+DBG_NAME( Region )
+DBG_NAMEEX( Polygon )
+DBG_NAMEEX( PolyPolygon )
+
+namespace {
+
+/** Return <TRUE/> when the given polygon is rectiliner and oriented so that
+ all sides are either horizontal or vertical.
+*/
+bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly)
+{
+ // Iterate over all polygons.
+ const USHORT nPolyCount = rPolyPoly.Count();
+ for (USHORT nPoly = 0; nPoly < nPolyCount; ++nPoly)
+ {
+ const Polygon& aPoly = rPolyPoly.GetObject(nPoly);
+
+ // Iterate over all edges of the current polygon.
+ const USHORT nSize = aPoly.GetSize();
+
+ if (nSize < 2)
+ continue;
+ Point aPoint (aPoly.GetPoint(0));
+ const Point aLastPoint (aPoint);
+ for (USHORT nPoint = 1; nPoint < nSize; ++nPoint)
+ {
+ const Point aNextPoint (aPoly.GetPoint(nPoint));
+ // When there is at least one edge that is neither vertical nor
+ // horizontal then the entire polygon is not rectilinear (and
+ // oriented along primary axes.)
+ if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y())
+ return false;
+
+ aPoint = aNextPoint;
+ }
+ // Compare closing edge.
+ if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y())
+ return false;
+ }
+ return true;
+}
+
+
+
+/** This function is similar to the ImplRegion::InsertBands() method.
+ It creates a minimal set of missing bands so that the entire vertical
+ interval from nTop to nBottom is covered by bands.
+*/
+void ImplAddMissingBands (
+ ImplRegion* pImplRegion,
+ const long nTop,
+ const long nBottom)
+{
+ // Iterate over already existing bands and add missing bands atop the
+ // first and between two bands.
+ ImplRegionBand* pPreviousBand = NULL;
+ ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand();
+ long nCurrentTop (nTop);
+ while (pBand != NULL && nCurrentTop<nBottom)
+ {
+ if (nCurrentTop < pBand->mnYTop)
+ {
+ // Create new band above the current band.
+ ImplRegionBand* pAboveBand = new ImplRegionBand(
+ nCurrentTop,
+ ::std::min(nBottom,pBand->mnYTop-1));
+ pImplRegion->InsertBand(pPreviousBand, pAboveBand);
+ }
+
+ // Adapt the top of the interval to prevent overlapping bands.
+ nCurrentTop = ::std::max(nTop, pBand->mnYBottom+1);
+
+ // Advance to next band.
+ pPreviousBand = pBand;
+ pBand = pBand->mpNextBand;
+ }
+
+ // We still have to cover two cases:
+ // 1. The region does not yet contain any bands.
+ // 2. The intervall nTop->nBottom extends past the bottom most band.
+ if (nCurrentTop <= nBottom
+ && (pBand==NULL || nBottom>pBand->mnYBottom))
+ {
+ // When there is no previous band then the new one will be the
+ // first. Otherwise the new band is inserted behind the last band.
+ pImplRegion->InsertBand(
+ pPreviousBand,
+ new ImplRegionBand(
+ nCurrentTop,
+ nBottom));
+ }
+}
+
+
+
+/** Convert a rectilinear polygon (that is oriented along the primary axes)
+ to a list of bands. For this special form of polygon we can use an
+ optimization that prevents the creation of one band per y value.
+ However, it still is possible that some temporary bands are created that
+ later can be optimized away.
+ @param rPolyPolygon
+ A set of zero, one, or more polygons, nested or not, that are
+ converted into a list of bands.
+ @return
+ A new ImplRegion object is returned that contains the bands that
+ represent the given poly-polygon.
+*/
+ImplRegion* ImplRectilinearPolygonToBands (const PolyPolygon& rPolyPoly)
+{
+ OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly));
+
+ // Create a new ImplRegion object as container of the bands.
+ ImplRegion* pImplRegion = new ImplRegion();
+ long nLineId = 0L;
+
+ // Iterate over all polygons.
+ const USHORT nPolyCount = rPolyPoly.Count();
+ for (USHORT nPoly = 0; nPoly < nPolyCount; ++nPoly)
+ {
+ const Polygon& aPoly = rPolyPoly.GetObject(nPoly);
+
+ // Iterate over all edges of the current polygon.
+ const USHORT nSize = aPoly.GetSize();
+ if (nSize < 2)
+ continue;
+ // Avoid fetching every point twice (each point is the start point
+ // of one and the end point of another edge.)
+ Point aStart (aPoly.GetPoint(0));
+ Point aEnd;
+ for (USHORT nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd)
+ {
+ // We take the implicit closing edge into account by mapping
+ // index nSize to 0.
+ aEnd = aPoly.GetPoint(nPoint%nSize);
+ if (aStart.Y() == aEnd.Y())
+ {
+ // Horizontal lines are ignored.
+ continue;
+ }
+
+ // At this point the line has to be vertical.
+ OSL_ASSERT(aStart.X() == aEnd.X());
+
+ // Sort y-coordinates to simplify the algorithm and store the
+ // direction seperately. The direction is calculated as it is
+ // in other places (but seems to be the wrong way.)
+ const long nTop (::std::min(aStart.Y(), aEnd.Y()));
+ const long nBottom (::std::max(aStart.Y(), aEnd.Y()));
+ const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING);
+
+ // Make sure that the current line is covered by bands.
+ ImplAddMissingBands(pImplRegion, nTop,nBottom);
+
+ // Find top-most band that may contain nTop.
+ ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand();
+ while (pBand!=NULL && pBand->mnYBottom < nTop)
+ pBand = pBand->mpNextBand;
+ ImplRegionBand* pTopBand = pBand;
+ // If necessary split the band at nTop so that nTop is contained
+ // in the lower band.
+ if (pBand!=NULL
+ // Prevent the current band from becoming 0 pixel high
+ && pBand->mnYTop<nTop
+ // this allows the lowest pixel of the band to be split off
+ && pBand->mnYBottom>=nTop
+ // do not split a band that is just one pixel high
+ && pBand->mnYTop<pBand->mnYBottom)
+ {
+ // Split the top band.
+ pTopBand = pBand->SplitBand(nTop);
+ }
+
+ // Advance to band that may contain nBottom.
+ while (pBand!=NULL && pBand->mnYBottom < nBottom)
+ pBand = pBand->mpNextBand;
+ // The lowest band may have to be split at nBottom so that
+ // nBottom itself remains in the upper band.
+ if (pBand!=NULL
+ // allow the current band becoming 1 pixel high
+ && pBand->mnYTop<=nBottom
+ // prevent splitting off a band that is 0 pixel high
+ && pBand->mnYBottom>nBottom
+ // do not split a band that is just one pixel high
+ && pBand->mnYTop<pBand->mnYBottom)
+ {
+ // Split the bottom band.
+ pBand->SplitBand(nBottom+1);
+ }
+
+ // Note that we remember the top band (in pTopBand) but not the
+ // bottom band. The later can be determined by comparing y
+ // coordinates.
+
+ // Add the x-value as point to all bands in the nTop->nBottom range.
+ for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand)
+ pBand->InsertPoint(aStart.X(), nLineId++, TRUE, eLineType);
+ }
+ }
+
+ return pImplRegion;
+}
+
+
+
+
+/** Convert a general polygon (one for which ImplIsPolygonRectilinear()
+ returns <FALSE/>) to bands.
+*/
+ImplRegion* ImplGeneralPolygonToBands (
+ const PolyPolygon& rPolyPoly,
+ const Rectangle& rPolygonBoundingBox)
+{
+ long nLineID = 0L;
+
+ // initialisation and creation of Bands
+ ImplRegion* pImplRegion = new ImplRegion();
+ pImplRegion->CreateBandRange( rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom() );
+
+ // insert polygons
+ const USHORT nPolyCount = rPolyPoly.Count();
+ for ( USHORT nPoly = 0; nPoly < nPolyCount; nPoly++ )
+ {
+ // get reference to current polygon
+ const Polygon& aPoly = rPolyPoly.GetObject( nPoly );
+ const USHORT nSize = aPoly.GetSize();
+
+ // not enough points ( <= 2 )? -> nothing to do!
+ if ( nSize <= 2 )
+ continue;
+
+ // band the polygon
+ for ( USHORT nPoint = 1; nPoint < nSize; nPoint++ )
+ pImplRegion->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ );
+
+ // close polygon with line from first point to last point, if neccesary
+ const Point rLastPoint = aPoly.GetPoint(nSize-1);
+ const Point rFirstPoint = aPoly.GetPoint(0);
+ if ( rLastPoint != rFirstPoint )
+ pImplRegion->InsertLine( rLastPoint, rFirstPoint, nLineID++ );
+ }
+
+ return pImplRegion;
+}
+
+
+} // end of anonymous namespace
+
+
+// -----------------------------------------------------------------------
+
+#ifdef DBG_UTIL
+const char* ImplDbgTestRegion( const void* pObj )
+{
+ Region* pRegion = (Region*)pObj;
+ ImplRegion* pImplRegion = pRegion->ImplGetImplRegion();
+
+ if ( aImplNullRegion.mnRefCount )
+ return "Null-Region-RefCount modified";
+ if ( aImplNullRegion.mnRectCount )
+ return "Null-Region-RectCount modified";
+ if ( aImplNullRegion.mpPolyPoly )
+ return "Null-Region-PolyPoly modified";
+ if ( aImplEmptyRegion.mnRefCount )
+ return "Emptry-Region-RefCount modified";
+ if ( aImplEmptyRegion.mnRectCount )
+ return "Emptry-Region-RectCount modified";
+ if ( aImplEmptyRegion.mpPolyPoly )
+ return "Emptry-Region-PolyPoly modified";
+
+ if ( (pImplRegion != &aImplEmptyRegion) && (pImplRegion != &aImplNullRegion) )
+ {
+ ULONG nCount = 0;
+ const ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand();
+ while ( pBand )
+ {
+ if ( pBand->mnYBottom < pBand->mnYTop )
+ return "YBottom < YTop";
+ if ( pBand->mpNextBand )
+ {
+ if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop )
+ return "overlapping bands in region";
+ }
+ if ( pBand->mbTouched > 1 )
+ return "Band-mbTouched overwrite";
+
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while ( pSep )
+ {
+ if ( pSep->mnXRight < pSep->mnXLeft )
+ return "XLeft < XRight";
+ if ( pSep->mpNextSep )
+ {
+ if ( pSep->mnXRight >= pSep->mpNextSep->mnXLeft )
+ return "overlapping separations in region";
+ }
+ if ( pSep->mbRemoved > 1 )
+ return "Sep-mbRemoved overwrite";
+
+ nCount++;
+ pSep = pSep->mpNextSep;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+
+ if ( pImplRegion->mnRectCount != nCount )
+ return "mnRetCount is not valid";
+ }
+
+ return NULL;
+}
+
+void TraceBands (const ImplRegionBand* pFirstBand)
+{
+ int nBandIndex (0);
+ const ImplRegionBand* pBand = pFirstBand;
+ while (pBand != NULL)
+ {
+ OSL_TRACE(" band %d %d->%d : ", nBandIndex++,
+ pBand->mnYTop, pBand->mnYBottom);
+
+ ImplRegionBandPoint* pPoint = pBand->mpFirstBandPoint;
+ while (pPoint != NULL)
+ {
+ OSL_TRACE(" %d ", pPoint->mnX);
+ pPoint = pPoint->mpNextBandPoint;
+ }
+ OSL_TRACE(" | ");
+
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while (pSep != NULL)
+ {
+ OSL_TRACE(" %d->%d ", pSep->mnXLeft, pSep->mnXRight);
+ pSep = pSep->mpNextSep;
+ }
+ OSL_TRACE("\n");
+
+ pBand = pBand->mpNextBand;
+ }
+}
+#endif
+
+// =======================================================================
+
+inline void Region::ImplPolyPolyRegionToBandRegion()
+{
+ if( mpImplRegion->mpPolyPoly || mpImplRegion->mpB2DPolyPoly )
+ ImplPolyPolyRegionToBandRegionFunc();
+}
+
+// =======================================================================
+
+ImplRegionBase::ImplRegionBase( int nRefCount )
+: mnRefCount( nRefCount )
+, mnRectCount( 0 )
+, mpPolyPoly( NULL )
+, mpB2DPolyPoly( NULL )
+{}
+
+// ------------------------------------------------------------------------
+
+ImplRegion::ImplRegion()
+{
+ mpFirstBand = NULL;
+ mpLastCheckedBand = NULL;
+}
+
+// ------------------------------------------------------------------------
+
+ImplRegion::ImplRegion( const PolyPolygon& rPolyPoly )
+{
+ mpFirstBand = NULL;
+ mpLastCheckedBand = NULL;
+ mpPolyPoly = new PolyPolygon( rPolyPoly );
+}
+
+// ------------------------------------------------------------------------
+
+ImplRegion::ImplRegion( const basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ mpFirstBand = NULL;
+ mpLastCheckedBand = NULL;
+ mpB2DPolyPoly = new basegfx::B2DPolyPolygon( rPolyPoly );
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegion::ImplRegion( const ImplRegion& rImplRegion )
+: ImplRegionBase()
+{
+ mpFirstBand = NULL;
+ mpLastCheckedBand = NULL;
+ mnRectCount = rImplRegion.mnRectCount;
+
+ if ( rImplRegion.mpPolyPoly )
+ mpPolyPoly = new PolyPolygon( *rImplRegion.mpPolyPoly );
+ else if( rImplRegion.mpB2DPolyPoly )
+ mpB2DPolyPoly = new basegfx::B2DPolyPolygon( *rImplRegion.mpB2DPolyPoly );
+
+ // insert band(s) into the list
+ ImplRegionBand* pNewBand;
+ ImplRegionBand* pPrevBand = 0;
+ ImplRegionBand* pBand = rImplRegion.mpFirstBand;
+ while ( pBand )
+ {
+ pNewBand = new ImplRegionBand( *pBand );
+
+ // first element? -> set as first into the list
+ if ( pBand == rImplRegion.mpFirstBand )
+ mpFirstBand = pNewBand;
+ else
+ pPrevBand->mpNextBand = pNewBand;
+
+ pPrevBand = pNewBand;
+ pBand = pBand->mpNextBand;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegion::~ImplRegion()
+{
+ DBG_ASSERT( (this != &aImplEmptyRegion) && (this != &aImplNullRegion),
+ "ImplRegion::~ImplRegion() - Empty oder NULL-Region" );
+
+ ImplRegionBand* pBand = mpFirstBand;
+ while ( pBand )
+ {
+ ImplRegionBand* pTempBand = pBand->mpNextBand;
+ delete pBand;
+ pBand = pTempBand;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegionBase::~ImplRegionBase()
+{
+ delete mpPolyPoly;
+ delete mpB2DPolyPoly;
+}
+
+// -----------------------------------------------------------------------
+//
+// create complete range of bands in single steps
+
+void ImplRegion::CreateBandRange( long nYTop, long nYBottom )
+{
+ // add top band
+ mpFirstBand = new ImplRegionBand( nYTop-1, nYTop-1 );
+
+ // begin first search from the first element
+ mpLastCheckedBand = mpFirstBand;
+
+ ImplRegionBand* pBand = mpFirstBand;
+ for ( int i = nYTop; i <= nYBottom+1; i++ )
+ {
+ // create new band
+ ImplRegionBand* pNewBand = new ImplRegionBand( i, i );
+ pBand->mpNextBand = pNewBand;
+ if ( pBand != mpFirstBand )
+ pNewBand->mpPrevBand = pBand;
+
+ pBand = pBand->mpNextBand;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegion::InsertLine( const Point& rStartPt, const Point& rEndPt,
+ long nLineId )
+{
+ long nX, nY;
+
+ // lines consisting of a single point do not interest here
+ if ( rStartPt == rEndPt )
+ return TRUE;
+
+ LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LINE_DESCENDING : LINE_ASCENDING;
+ if ( rStartPt.X() == rEndPt.X() )
+ {
+ // vertical line
+ const long nEndY = rEndPt.Y();
+
+ nX = rStartPt.X();
+ nY = rStartPt.Y();
+
+ if( nEndY > nY )
+ {
+ for ( ; nY <= nEndY; nY++ )
+ {
+ Point aNewPoint( nX, nY );
+ InsertPoint( aNewPoint, nLineId,
+ (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
+ eLineType );
+ }
+ }
+ else
+ {
+ for ( ; nY >= nEndY; nY-- )
+ {
+ Point aNewPoint( nX, nY );
+ InsertPoint( aNewPoint, nLineId,
+ (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
+ eLineType );
+ }
+ }
+ }
+ else if ( rStartPt.Y() != rEndPt.Y() )
+ {
+ const long nDX = labs( rEndPt.X() - rStartPt.X() );
+ const long nDY = labs( rEndPt.Y() - rStartPt.Y() );
+ const long nStartX = rStartPt.X();
+ const long nStartY = rStartPt.Y();
+ const long nEndX = rEndPt.X();
+ const long nEndY = rEndPt.Y();
+ const long nXInc = ( nStartX < nEndX ) ? 1L : -1L;
+ const long nYInc = ( nStartY < nEndY ) ? 1L : -1L;
+
+ if ( nDX >= nDY )
+ {
+ const long nDYX = ( nDY - nDX ) << 1;
+ const long nDY2 = nDY << 1;
+ long nD = nDY2 - nDX;
+
+ for ( nX = nStartX, nY = nStartY; nX != nEndX; nX += nXInc )
+ {
+ InsertPoint( Point( nX, nY ), nLineId, nStartX == nX, eLineType );
+
+ if ( nD < 0L )
+ nD += nDY2;
+ else
+ nD += nDYX, nY += nYInc;
+ }
+ }
+ else
+ {
+ const long nDYX = ( nDX - nDY ) << 1;
+ const long nDY2 = nDX << 1;
+ long nD = nDY2 - nDY;
+
+ for ( nX = nStartX, nY = nStartY; nY != nEndY; nY += nYInc )
+ {
+ InsertPoint( Point( nX, nY ), nLineId, nStartY == nY, eLineType );
+
+ if ( nD < 0L )
+ nD += nDY2;
+ else
+ nD += nDYX, nX += nXInc;
+ }
+ }
+
+ // last point
+ InsertPoint( Point( nEndX, nEndY ), nLineId, TRUE, eLineType );
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+//
+// search for appropriate place for the new point
+
+BOOL ImplRegion::InsertPoint( const Point &rPoint, long nLineID,
+ BOOL bEndPoint, LineType eLineType )
+{
+ DBG_ASSERT( mpFirstBand != NULL, "ImplRegion::InsertPoint - no bands available!" );
+
+ if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
+ {
+ mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
+ return TRUE;
+ }
+
+ if ( rPoint.Y() > mpLastCheckedBand->mnYTop )
+ {
+ // Search ascending
+ while ( mpLastCheckedBand )
+ {
+ // Insert point if possible
+ if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
+ {
+ mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
+ return TRUE;
+ }
+
+ mpLastCheckedBand = mpLastCheckedBand->mpNextBand;
+ }
+
+ DBG_ERROR( "ImplRegion::InsertPoint reached the end of the list!" );
+ }
+ else
+ {
+ // Search descending
+ while ( mpLastCheckedBand )
+ {
+ // Insert point if possible
+ if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
+ {
+ mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
+ return TRUE;
+ }
+
+ mpLastCheckedBand = mpLastCheckedBand->mpPrevBand;
+ }
+
+ DBG_ERROR( "ImplRegion::InsertPoint reached the beginning of the list!" );
+ }
+
+ DBG_ERROR( "ImplRegion::InsertPoint point not inserted!" );
+
+ // reinitialize pointer (should never be reached!)
+ mpLastCheckedBand = mpFirstBand;
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+//
+// search for appropriate places for the new bands
+
+void ImplRegion::InsertBands( long nTop, long nBottom )
+{
+ // region empty? -> set rectagle as first entry!
+ if ( !mpFirstBand )
+ {
+ // add band with boundaries of the rectangle
+ mpFirstBand = new ImplRegionBand( nTop, nBottom );
+ return;
+ }
+
+ // find/insert bands for the boundaries of the rectangle
+ BOOL bTopBoundaryInserted = FALSE;
+ BOOL bTop2BoundaryInserted = FALSE;
+ BOOL bBottomBoundaryInserted = FALSE;
+
+ // special case: top boundary is above the first band
+ ImplRegionBand* pNewBand;
+ if ( nTop < mpFirstBand->mnYTop )
+ {
+ // create new band above the first in the list
+ pNewBand = new ImplRegionBand( nTop, mpFirstBand->mnYTop );
+ if ( nBottom < mpFirstBand->mnYTop )
+ pNewBand->mnYBottom = nBottom;
+
+ // insert band into the list
+ pNewBand->mpNextBand = mpFirstBand;
+ mpFirstBand = pNewBand;
+
+ bTopBoundaryInserted = TRUE;
+ }
+
+ // insert band(s) into the list
+ ImplRegionBand* pBand = mpFirstBand;
+ while ( pBand )
+ {
+ // Insert Bands if possible
+ if ( !bTopBoundaryInserted )
+ bTopBoundaryInserted = InsertSingleBand( pBand, nTop - 1 );
+
+ if ( !bTop2BoundaryInserted )
+ bTop2BoundaryInserted = InsertSingleBand( pBand, nTop );
+
+ if ( !bBottomBoundaryInserted && (nTop != nBottom) )
+ bBottomBoundaryInserted = InsertSingleBand( pBand, nBottom );
+
+ // both boundaries inserted? -> nothing more to do
+ if ( bTopBoundaryInserted && bTop2BoundaryInserted && bBottomBoundaryInserted )
+ break;
+
+ // insert bands between two bands if neccessary
+ if ( pBand->mpNextBand )
+ {
+ if ( (pBand->mnYBottom + 1) < pBand->mpNextBand->mnYTop )
+ {
+ // copy band with list and set new boundary
+ pNewBand = new ImplRegionBand( pBand->mnYBottom+1,
+ pBand->mpNextBand->mnYTop-1 );
+
+ // insert band into the list
+ pNewBand->mpNextBand = pBand->mpNextBand;
+ pBand->mpNextBand = pNewBand;
+ }
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+}
+
+// -----------------------------------------------------------------------
+//
+// create new band and insert it into the list
+
+BOOL ImplRegion::InsertSingleBand( ImplRegionBand* pBand,
+ long nYBandPosition )
+{
+ // boundary already included in band with height 1? -> nothing to do!
+ if ( (pBand->mnYTop == pBand->mnYBottom) &&
+ (nYBandPosition == pBand->mnYTop) )
+ return TRUE;
+
+ // insert single height band on top?
+ ImplRegionBand* pNewBand;
+ if ( nYBandPosition == pBand->mnYTop )
+ {
+ // copy band with list and set new boundary
+ pNewBand = new ImplRegionBand( *pBand );
+ pNewBand->mnYTop = nYBandPosition+1;
+
+ // insert band into the list
+ pNewBand->mpNextBand = pBand->mpNextBand;
+ pBand->mnYBottom = nYBandPosition;
+ pBand->mpNextBand = pNewBand;
+
+ return TRUE;
+ }
+
+ // top of new rectangle within the current band? -> insert new band and copy data
+ if ( (nYBandPosition > pBand->mnYTop) &&
+ (nYBandPosition < pBand->mnYBottom) )
+ {
+ // copy band with list and set new boundary
+ pNewBand = new ImplRegionBand( *pBand );
+ pNewBand->mnYTop = nYBandPosition;
+
+ // insert band into the list
+ pNewBand->mpNextBand = pBand->mpNextBand;
+ pBand->mnYBottom = nYBandPosition;
+ pBand->mpNextBand = pNewBand;
+
+ // copy band with list and set new boundary
+ pNewBand = new ImplRegionBand( *pBand );
+ pNewBand->mnYTop = nYBandPosition;
+
+ // insert band into the list
+ pBand->mpNextBand->mnYTop = nYBandPosition+1;
+
+ pNewBand->mpNextBand = pBand->mpNextBand;
+ pBand->mnYBottom = nYBandPosition - 1;
+ pBand->mpNextBand = pNewBand;
+
+ return TRUE;
+ }
+
+ // create new band behind the current in the list
+ if ( !pBand->mpNextBand )
+ {
+ if ( nYBandPosition == pBand->mnYBottom )
+ {
+ // copy band with list and set new boundary
+ pNewBand = new ImplRegionBand( *pBand );
+ pNewBand->mnYTop = pBand->mnYBottom;
+ pNewBand->mnYBottom = nYBandPosition;
+
+ pBand->mnYBottom = nYBandPosition-1;
+
+ // append band to the list
+ pBand->mpNextBand = pNewBand;
+ return TRUE;
+ }
+
+ if ( nYBandPosition > pBand->mnYBottom )
+ {
+ // create new band
+ pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition );
+
+ // append band to the list
+ pBand->mpNextBand = pNewBand;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplRegion::InsertBand (ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert)
+{
+ OSL_ASSERT(pBandToInsert!=NULL);
+
+ if (pPreviousBand == NULL)
+ {
+ // Insert band before all others.
+ if (mpFirstBand != NULL)
+ mpFirstBand->mpPrevBand = pBandToInsert;
+ pBandToInsert->mpNextBand = mpFirstBand;
+ mpFirstBand = pBandToInsert;
+ }
+ else
+ {
+ // Insert band directly after pPreviousBand.
+ pBandToInsert->mpNextBand = pPreviousBand->mpNextBand;
+ pPreviousBand->mpNextBand = pBandToInsert;
+ pBandToInsert->mpPrevBand = pPreviousBand;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImplRegion::Union( long nLeft, long nTop, long nRight, long nBottom )
+{
+ DBG_ASSERT( nLeft <= nRight, "ImplRegion::Union() - nLeft > nRight" );
+ DBG_ASSERT( nTop <= nBottom, "ImplRegion::Union() - nTop > nBottom" );
+
+ // process union
+ ImplRegionBand* pBand = mpFirstBand;
+ while ( pBand )
+ {
+ if ( pBand->mnYTop >= nTop )
+ {
+ if ( pBand->mnYBottom <= nBottom )
+ pBand->Union( nLeft, nRight );
+ else
+ {
+#ifdef DBG_UTIL
+ long nCurY = pBand->mnYBottom;
+ pBand = pBand->mpNextBand;
+ while ( pBand )
+ {
+ if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
+ {
+ DBG_ERROR( "ImplRegion::Union() - Bands not sorted!" );
+ }
+ pBand = pBand->mpNextBand;
+ }
+#endif
+ break;
+ }
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegion::Exclude( long nLeft, long nTop, long nRight, long nBottom )
+{
+ DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" );
+ DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" );
+
+ // process exclude
+ ImplRegionBand* pBand = mpFirstBand;
+ while ( pBand )
+ {
+ if ( pBand->mnYTop >= nTop )
+ {
+ if ( pBand->mnYBottom <= nBottom )
+ pBand->Exclude( nLeft, nRight );
+ else
+ {
+#ifdef DBG_UTIL
+ long nCurY = pBand->mnYBottom;
+ pBand = pBand->mpNextBand;
+ while ( pBand )
+ {
+ if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
+ {
+ DBG_ERROR( "ImplRegion::Exclude() - Bands not sorted!" );
+ }
+ pBand = pBand->mpNextBand;
+ }
+#endif
+ break;
+ }
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegion::XOr( long nLeft, long nTop, long nRight, long nBottom )
+{
+ DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" );
+ DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" );
+
+ // process xor
+ ImplRegionBand* pBand = mpFirstBand;
+ while ( pBand )
+ {
+ if ( pBand->mnYTop >= nTop )
+ {
+ if ( pBand->mnYBottom <= nBottom )
+ pBand->XOr( nLeft, nRight );
+ else
+ {
+#ifdef DBG_UTIL
+ long nCurY = pBand->mnYBottom;
+ pBand = pBand->mpNextBand;
+ while ( pBand )
+ {
+ if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
+ {
+ DBG_ERROR( "ImplRegion::XOr() - Bands not sorted!" );
+ }
+ pBand = pBand->mpNextBand;
+ }
+#endif
+ break;
+ }
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+}
+
+// -----------------------------------------------------------------------
+//
+// remove empty bands
+
+BOOL ImplRegion::OptimizeBandList()
+{
+ DBG_ASSERT( (this != &aImplNullRegion) && (this != &aImplEmptyRegion),
+ "ImplRegion::OptimizeBandList() - Empty oder NULL-Region" );
+
+ mnRectCount = 0;
+
+ ImplRegionBand* pPrevBand = 0;
+ ImplRegionBand* pBand = mpFirstBand;
+ while ( pBand )
+ {
+ const BOOL bBTEqual = pBand->mpNextBand &&
+ (pBand->mnYBottom == pBand->mpNextBand->mnYTop);
+
+ // no separation? -> remove!
+ if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) )
+ {
+ // save pointer
+ ImplRegionBand* pOldBand = pBand;
+
+ // previous element of the list
+ if ( pBand == mpFirstBand )
+ mpFirstBand = pBand->mpNextBand;
+ else
+ pPrevBand->mpNextBand = pBand->mpNextBand;
+
+ pBand = pBand->mpNextBand;
+ delete pOldBand;
+ }
+ else
+ {
+ // fixup
+ if ( bBTEqual )
+ pBand->mnYBottom = pBand->mpNextBand->mnYTop-1;
+
+ // this and next band with equal separations? -> combine!
+ if ( pBand->mpNextBand &&
+ ((pBand->mnYBottom+1) == pBand->mpNextBand->mnYTop) &&
+ (*pBand == *pBand->mpNextBand) )
+ {
+ // expand current height
+ pBand->mnYBottom = pBand->mpNextBand->mnYBottom;
+
+ // remove next band from list
+ ImplRegionBand* pDeletedBand = pBand->mpNextBand;
+ pBand->mpNextBand = pDeletedBand->mpNextBand;
+ delete pDeletedBand;
+
+ // check band again!
+ }
+ else
+ {
+ // count rectangles within band
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while ( pSep )
+ {
+ mnRectCount++;
+ pSep = pSep->mpNextSep;
+ }
+
+ pPrevBand = pBand;
+ pBand = pBand->mpNextBand;
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ pBand = mpFirstBand;
+ while ( pBand )
+ {
+ DBG_ASSERT( pBand->mpFirstSep != NULL,
+ "Exiting ImplRegion::OptimizeBandList(): empty band in region!" );
+
+ if ( pBand->mnYBottom < pBand->mnYTop )
+ DBG_ERROR( "ImplRegion::OptimizeBandList(): YBottomBoundary < YTopBoundary" );
+
+ if ( pBand->mpNextBand )
+ {
+ if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop )
+ DBG_ERROR( "ImplRegion::OptimizeBandList(): overlapping bands in region!" );
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+#endif
+
+ return (mnRectCount != 0);
+}
+
+// =======================================================================
+
+void Region::ImplCopyData()
+{
+ mpImplRegion->mnRefCount--;
+ mpImplRegion = new ImplRegion( *mpImplRegion );
+}
+
+// =======================================================================
+
+Region::Region()
+{
+ DBG_CTOR( Region, ImplDbgTestRegion );
+
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+}
+
+// -----------------------------------------------------------------------
+
+Region::Region( RegionType eType )
+{
+ DBG_CTOR( Region, ImplDbgTestRegion );
+ DBG_ASSERT( (eType == REGION_NULL) || (eType == REGION_EMPTY),
+ "Region( RegionType ) - RegionType != EMPTY/NULL" );
+
+ if ( eType == REGION_NULL )
+ mpImplRegion = (ImplRegion*)(&aImplNullRegion);
+ else
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+}
+
+// -----------------------------------------------------------------------
+
+Region::Region( const Rectangle& rRect )
+{
+ DBG_CTOR( Region, ImplDbgTestRegion );
+
+ ImplCreateRectRegion( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+Region::Region( const Polygon& rPolygon )
+{
+ DBG_CTOR( Region, ImplDbgTestRegion );
+ DBG_CHKOBJ( &rPolygon, Polygon, NULL );
+
+ ImplCreatePolyPolyRegion( rPolygon );
+}
+
+// -----------------------------------------------------------------------
+
+Region::Region( const PolyPolygon& rPolyPoly )
+{
+ DBG_CTOR( Region, ImplDbgTestRegion );
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+
+ ImplCreatePolyPolyRegion( rPolyPoly );
+}
+
+// -----------------------------------------------------------------------
+
+Region::Region( const basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ DBG_CTOR( Region, ImplDbgTestRegion );
+ DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
+
+ mpImplRegion = new ImplRegion( rPolyPoly );
+}
+
+// -----------------------------------------------------------------------
+
+Region::Region( const Region& rRegion )
+{
+ DBG_CTOR( Region, ImplDbgTestRegion );
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+ DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" );
+
+ // copy pointer to instance of implementation
+ mpImplRegion = rRegion.mpImplRegion;
+ if ( mpImplRegion->mnRefCount )
+ mpImplRegion->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+Region::~Region()
+{
+ DBG_DTOR( Region, ImplDbgTestRegion );
+
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Region::ImplCreateRectRegion( const Rectangle& rRect )
+{
+ if ( rRect.IsEmpty() )
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ else
+ {
+ // get justified rectangle
+ long nTop = Min( rRect.Top(), rRect.Bottom() );
+ long nBottom = Max( rRect.Top(), rRect.Bottom() );
+ long nLeft = Min( rRect.Left(), rRect.Right() );
+ long nRight = Max( rRect.Left(), rRect.Right() );
+
+ // create instance of implementation class
+ mpImplRegion = new ImplRegion();
+
+ // add band with boundaries of the rectangle
+ mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom );
+
+ // Set left and right boundaries of the band
+ mpImplRegion->mpFirstBand->Union( nLeft, nRight );
+ mpImplRegion->mnRectCount = 1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly )
+{
+ const USHORT nPolyCount = rPolyPoly.Count();
+ if ( nPolyCount )
+ {
+ // polypolygon empty? -> empty region
+ const Rectangle aRect( rPolyPoly.GetBoundRect() );
+
+ if ( !aRect.IsEmpty() )
+ {
+ // width OR height == 1 ? => Rectangular region
+ if ( (aRect.GetWidth() == 1)
+ || (aRect.GetHeight() == 1)
+ || rPolyPoly.IsRect() )
+ {
+ ImplCreateRectRegion( aRect );
+ }
+ else
+ mpImplRegion = new ImplRegion( rPolyPoly );
+ }
+ else
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+ else
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+}
+
+// -----------------------------------------------------------------------
+
+void Region::ImplPolyPolyRegionToBandRegionFunc()
+{
+ // ensure to subdivide when bezier segemnts are used, it's going to
+ // be expanded to rectangles
+ PolyPolygon aPolyPoly;
+ GetPolyPolygon().AdaptiveSubdivide(aPolyPoly);
+
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+
+ if ( aPolyPoly.Count() )
+ {
+ // polypolygon empty? -> empty region
+ const Rectangle aRect( aPolyPoly.GetBoundRect() );
+
+ if ( !aRect.IsEmpty() )
+ {
+ if (ImplIsPolygonRectilinear(aPolyPoly))
+ {
+ // For rectilinear polygons there is an optimized band conversion.
+ mpImplRegion = ImplRectilinearPolygonToBands(aPolyPoly);
+ }
+ else
+ {
+ mpImplRegion = ImplGeneralPolygonToBands(aPolyPoly, aRect);
+ }
+
+ // Convert points into seps.
+ ImplRegionBand* pRegionBand = mpImplRegion->mpFirstBand;
+ while ( pRegionBand )
+ {
+ // generate separations from the lines and process union
+ pRegionBand->ProcessPoints();
+ pRegionBand = pRegionBand->mpNextBand;
+ }
+
+ // Optimize list of bands. Adjacent bands with identical lists
+ // of seps are joined.
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+ }
+ else
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+ else
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+}
+
+// -----------------------------------------------------------------------
+
+void Region::Move( long nHorzMove, long nVertMove )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // no region data? -> nothing to do
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return;
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ if ( mpImplRegion->mpPolyPoly )
+ mpImplRegion->mpPolyPoly->Move( nHorzMove, nVertMove );
+ else if( mpImplRegion->mpB2DPolyPoly )
+ {
+ mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove));
+ }
+ else
+ {
+ ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // process the vertical move
+ if ( nVertMove != 0)
+ {
+ pBand->mnYTop = pBand->mnYTop + nVertMove;
+ pBand->mnYBottom = pBand->mnYBottom + nVertMove;
+ }
+
+ // process the horizontal move
+ if ( nHorzMove != 0)
+ pBand->MoveX( nHorzMove );
+
+ pBand = pBand->mpNextBand;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Region::Scale( double fScaleX, double fScaleY )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // no region data? -> nothing to do
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return;
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ if ( mpImplRegion->mpPolyPoly )
+ mpImplRegion->mpPolyPoly->Scale( fScaleX, fScaleY );
+ else if( mpImplRegion->mpB2DPolyPoly )
+ {
+ mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY));
+ }
+ else
+ {
+ ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // process the vertical move
+ if ( fScaleY != 0.0 )
+ {
+ pBand->mnYTop = FRound( pBand->mnYTop * fScaleY );
+ pBand->mnYBottom = FRound( pBand->mnYBottom * fScaleY );
+ }
+
+ // process the horizontal move
+ if ( fScaleX != 0.0 )
+ pBand->ScaleX( fScaleX );
+
+ pBand = pBand->mpNextBand;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::Union( const Rectangle& rRect )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // is rectangle empty? -> nothing to do
+ if ( rRect.IsEmpty() )
+ return TRUE;
+
+ ImplPolyPolyRegionToBandRegion();
+
+ // no instance data? -> create!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ mpImplRegion = new ImplRegion();
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // get justified rectangle
+ long nLeft = Min( rRect.Left(), rRect.Right() );
+ long nTop = Min( rRect.Top(), rRect.Bottom() );
+ long nRight = Max( rRect.Left(), rRect.Right() );
+ long nBottom = Max( rRect.Top(), rRect.Bottom() );
+
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( nTop, nBottom );
+
+ // process union
+ mpImplRegion->Union( nLeft, nTop, nRight, nBottom );
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::Intersect( const Rectangle& rRect )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // is rectangle empty? -> nothing to do
+ if ( rRect.IsEmpty() )
+ {
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ return TRUE;
+ }
+
+ // #103137# Avoid banding for special cases
+ if ( mpImplRegion->mpPolyPoly )
+ {
+ // #127431# make ImplRegion unique, if not already.
+ if( mpImplRegion->mnRefCount > 1 )
+ {
+ mpImplRegion->mnRefCount--;
+ mpImplRegion = new ImplRegion( *mpImplRegion->mpPolyPoly );
+ }
+
+ // use the PolyPolygon::Clip method for rectangles, this is
+ // fairly simple (does not even use GPC) and saves us from
+ // unnecessary banding
+ mpImplRegion->mpPolyPoly->Clip( rRect );
+
+ return TRUE;
+ }
+ else
+ ImplPolyPolyRegionToBandRegion();
+
+ // is region empty? -> nothing to do!
+ if ( mpImplRegion == &aImplEmptyRegion )
+ return TRUE;
+
+ // get justified rectangle
+ long nLeft = Min( rRect.Left(), rRect.Right() );
+ long nTop = Min( rRect.Top(), rRect.Bottom() );
+ long nRight = Max( rRect.Left(), rRect.Right() );
+ long nBottom = Max( rRect.Top(), rRect.Bottom() );
+
+ // is own region NULL-region? -> copy data!
+ if ( mpImplRegion == &aImplNullRegion )
+ {
+ // create instance of implementation class
+ mpImplRegion = new ImplRegion();
+
+ // add band with boundaries of the rectangle
+ mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom );
+
+ // Set left and right boundaries of the band
+ mpImplRegion->mpFirstBand->Union( nLeft, nRight );
+ mpImplRegion->mnRectCount = 1;
+
+ return TRUE;
+ }
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( nTop, nBottom );
+
+ // process intersections
+ ImplRegionBand* pPrevBand = 0;
+ ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // band within intersection boundary? -> process. otherwise remove
+ if ( (pBand->mnYTop >= nTop) &&
+ (pBand->mnYBottom <= nBottom) )
+ {
+ // process intersection
+ pBand->Intersect( nLeft, nRight );
+
+ pPrevBand = pBand;
+ pBand = pBand->mpNextBand;
+ }
+ else
+ {
+ ImplRegionBand* pOldBand = pBand;
+ if ( pBand == mpImplRegion->mpFirstBand )
+ mpImplRegion->mpFirstBand = pBand->mpNextBand;
+ else
+ pPrevBand->mpNextBand = pBand->mpNextBand;
+ pBand = pBand->mpNextBand;
+ delete pOldBand;
+ }
+ }
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::Exclude( const Rectangle& rRect )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // is rectangle empty? -> nothing to do
+ if ( rRect.IsEmpty() )
+ return TRUE;
+
+ ImplPolyPolyRegionToBandRegion();
+
+ // no instance data? -> create!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return TRUE;
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // get justified rectangle
+ long nLeft = Min( rRect.Left(), rRect.Right() );
+ long nTop = Min( rRect.Top(), rRect.Bottom() );
+ long nRight = Max( rRect.Left(), rRect.Right() );
+ long nBottom = Max( rRect.Top(), rRect.Bottom() );
+
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( nTop, nBottom );
+
+ // process exclude
+ mpImplRegion->Exclude( nLeft, nTop, nRight, nBottom );
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::XOr( const Rectangle& rRect )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // is rectangle empty? -> nothing to do
+ if ( rRect.IsEmpty() )
+ return TRUE;
+
+ ImplPolyPolyRegionToBandRegion();
+
+ // no instance data? -> create!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ mpImplRegion = new ImplRegion();
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // get justified rectangle
+ long nLeft = Min( rRect.Left(), rRect.Right() );
+ long nTop = Min( rRect.Top(), rRect.Bottom() );
+ long nRight = Max( rRect.Left(), rRect.Right() );
+ long nBottom = Max( rRect.Top(), rRect.Bottom() );
+
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( nTop, nBottom );
+
+ // process xor
+ mpImplRegion->XOr( nLeft, nTop, nRight, nBottom );
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::Union( const Region& rRegion )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ImplPolyPolyRegionToBandRegion();
+ ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
+
+ // is region empty or null? -> nothing to do
+ if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
+ return TRUE;
+
+ // no instance data? -> create!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ mpImplRegion = new ImplRegion();
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
+ ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
+
+ // process all elements of the list
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while ( pSep )
+ {
+ mpImplRegion->Union( pSep->mnXLeft, pBand->mnYTop,
+ pSep->mnXRight, pBand->mnYBottom );
+ pSep = pSep->mpNextSep;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::Intersect( const Region& rRegion )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // same instance data? -> nothing to do!
+ if ( mpImplRegion == rRegion.mpImplRegion )
+ return TRUE;
+
+ ImplPolyPolyRegionToBandRegion();
+ ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
+
+ if ( mpImplRegion == &aImplEmptyRegion )
+ return TRUE;
+
+ // is region null? -> nothing to do
+ if ( rRegion.mpImplRegion == &aImplNullRegion )
+ return TRUE;
+
+ // is rectangle empty? -> nothing to do
+ if ( rRegion.mpImplRegion == &aImplEmptyRegion )
+ {
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ return TRUE;
+ }
+
+ // is own region NULL-region? -> copy data!
+ if ( mpImplRegion == &aImplNullRegion)
+ {
+ mpImplRegion = rRegion.mpImplRegion;
+ rRegion.mpImplRegion->mnRefCount++;
+ return TRUE;
+ }
+
+ // Wenn wir weniger Rechtecke haben, drehen wir den Intersect-Aufruf um
+ if ( mpImplRegion->mnRectCount+2 < rRegion.mpImplRegion->mnRectCount )
+ {
+ Region aTempRegion = rRegion;
+ aTempRegion.Intersect( *this );
+ *this = aTempRegion;
+ }
+ else
+ {
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // mark all bands as untouched
+ ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ pBand->mbTouched = FALSE;
+ pBand = pBand->mpNextBand;
+ }
+
+ pBand = rRegion.mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
+
+ // process all elements of the list
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while ( pSep )
+ {
+ // left boundary?
+ if ( pSep == pBand->mpFirstSep )
+ {
+ // process intersection and do not remove untouched bands
+ mpImplRegion->Exclude( LONG_MIN+1, pBand->mnYTop,
+ pSep->mnXLeft-1, pBand->mnYBottom );
+ }
+
+ // right boundary?
+ if ( pSep->mpNextSep == NULL )
+ {
+ // process intersection and do not remove untouched bands
+ mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop,
+ LONG_MAX-1, pBand->mnYBottom );
+ }
+ else
+ {
+ // process intersection and do not remove untouched bands
+ mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop,
+ pSep->mpNextSep->mnXLeft-1, pBand->mnYBottom );
+ }
+
+ pSep = pSep->mpNextSep;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+
+ // remove all untouched bands if bands allready left
+ ImplRegionBand* pPrevBand = 0;
+ pBand = mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ if ( !pBand->mbTouched )
+ {
+ // save pointer
+ ImplRegionBand* pOldBand = pBand;
+
+ // previous element of the list
+ if ( pBand == mpImplRegion->mpFirstBand )
+ mpImplRegion->mpFirstBand = pBand->mpNextBand;
+ else
+ pPrevBand->mpNextBand = pBand->mpNextBand;
+
+ pBand = pBand->mpNextBand;
+ delete pOldBand;
+ }
+ else
+ {
+ pPrevBand = pBand;
+ pBand = pBand->mpNextBand;
+ }
+ }
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::Exclude( const Region& rRegion )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ImplPolyPolyRegionToBandRegion();
+ ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
+
+ // is region empty or null? -> nothing to do
+ if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
+ return TRUE;
+
+ // no instance data? -> nothing to do
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return TRUE;
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
+ ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
+
+ // process all elements of the list
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while ( pSep )
+ {
+ mpImplRegion->Exclude( pSep->mnXLeft, pBand->mnYTop,
+ pSep->mnXRight, pBand->mnYBottom );
+ pSep = pSep->mpNextSep;
+ }
+
+ // Wir optimieren schon in der Schleife, da wir davon
+ // ausgehen, das wir insgesammt weniger Baender ueberpruefen
+ // muessen
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ break;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::XOr( const Region& rRegion )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ImplPolyPolyRegionToBandRegion();
+ ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
+
+ // is region empty or null? -> nothing to do
+ if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
+ return TRUE;
+
+ // no own instance data? -> XOr = copy
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ {
+ *this = rRegion;
+ return TRUE;
+ }
+
+ // no own instance data? -> make own copy!
+ if ( mpImplRegion->mnRefCount > 1 )
+ ImplCopyData();
+
+ // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
+ ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // insert bands if the boundaries are not allready in the list
+ mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
+
+ // process all elements of the list
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while ( pSep )
+ {
+ mpImplRegion->XOr( pSep->mnXLeft, pBand->mnYTop,
+ pSep->mnXRight, pBand->mnYBottom );
+ pSep = pSep->mpNextSep;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle Region::GetBoundRect() const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ Rectangle aRect;
+
+ // no internal data? -> region is empty!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return aRect;
+
+ // PolyPolygon data im Imp structure?
+ if ( mpImplRegion->mpPolyPoly )
+ return mpImplRegion->mpPolyPoly->GetBoundRect();
+ if( mpImplRegion->mpB2DPolyPoly )
+ {
+ const basegfx::B2DRange aRange = basegfx::tools::getRange( *mpImplRegion->mpB2DPolyPoly );
+ aRect.SetPos( Point( (int)aRange.getMinX(), (int)aRange.getMinY() ) );
+ aRect.SetSize( Size( (int)aRange.getWidth(), (int)aRange.getHeight() ) );
+ return aRect;
+ }
+
+ // no band in the list? -> region is empty!
+ if ( !mpImplRegion->mpFirstBand )
+ return aRect;
+
+ // get the boundaries of the first band
+ long nYTop = mpImplRegion->mpFirstBand->mnYTop;
+ long nYBottom = mpImplRegion->mpFirstBand->mnYBottom;
+ long nXLeft = mpImplRegion->mpFirstBand->GetXLeftBoundary();
+ long nXRight = mpImplRegion->mpFirstBand->GetXRightBoundary();
+
+ // look in the band list (don't test first band again!)
+ ImplRegionBand* pBand = mpImplRegion->mpFirstBand->mpNextBand;
+ while ( pBand )
+ {
+ nYBottom = pBand->mnYBottom;
+ nXLeft = Min( nXLeft, pBand->GetXLeftBoundary() );
+ nXRight = Max( nXRight, pBand->GetXRightBoundary() );
+
+ pBand = pBand->mpNextBand;
+ }
+
+ // set rectangle
+ aRect = Rectangle( nXLeft, nYTop, nXRight, nYBottom );
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::HasPolyPolygon() const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+ if( !mpImplRegion )
+ return false;
+ if( mpImplRegion->mpPolyPoly )
+ return true;
+ if( mpImplRegion->mpB2DPolyPoly )
+ return true;
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+PolyPolygon Region::GetPolyPolygon() const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ PolyPolygon aRet;
+
+ if( mpImplRegion->mpPolyPoly )
+ aRet = *mpImplRegion->mpPolyPoly;
+ else if( mpImplRegion->mpB2DPolyPoly )
+ {
+ // the polygon needs to be converted
+ aRet = PolyPolygon( *mpImplRegion->mpB2DPolyPoly );
+ // TODO: cache the converted polygon?
+ // mpImplRegion->mpB2DPolyPoly = aRet;
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+const basegfx::B2DPolyPolygon Region::GetB2DPolyPolygon() const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ basegfx::B2DPolyPolygon aRet;
+
+ if( mpImplRegion->mpB2DPolyPoly )
+ aRet = *mpImplRegion->mpB2DPolyPoly;
+ else if( mpImplRegion->mpPolyPoly )
+ {
+ // the polygon needs to be converted
+ aRet = mpImplRegion->mpPolyPoly->getB2DPolyPolygon();
+ // TODO: cache the converted polygon?
+ // mpImplRegion->mpB2DPolyPoly = aRet;
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+basegfx::B2DPolyPolygon Region::ConvertToB2DPolyPolygon()
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ basegfx::B2DPolyPolygon aRet;
+
+ if( HasPolyPolygon() )
+ aRet = GetB2DPolyPolygon();
+ else
+ {
+ RegionHandle aHdl = BeginEnumRects();
+ Rectangle aSubRect;
+ while( GetNextEnumRect( aHdl, aSubRect ) )
+ {
+ basegfx::B2DPolygon aPoly( basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRectangle( aSubRect.Left(), aSubRect.Top(), aSubRect.Right(), aSubRect.Bottom() ) ) );
+ aRet.append( aPoly );
+ }
+ EndEnumRects( aHdl );
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo,
+ long& rX, long& rY,
+ long& rWidth, long& rHeight ) const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ((Region*)this)->ImplPolyPolyRegionToBandRegion();
+
+ // no internal data? -> region is empty!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return FALSE;
+
+ // no band in the list? -> region is empty!
+ if ( mpImplRegion->mpFirstBand == NULL )
+ return FALSE;
+
+ // initialise pointer for first access
+ ImplRegionBand* pCurrRectBand = mpImplRegion->mpFirstBand;
+ ImplRegionBandSep* pCurrRectBandSep = pCurrRectBand->mpFirstSep;
+
+ DBG_ASSERT( pCurrRectBandSep != NULL, "Erstes Band wurde nicht optimiert." );
+ if ( !pCurrRectBandSep )
+ return FALSE;
+
+ // get boundaries of current rectangle
+ rX = pCurrRectBandSep->mnXLeft;
+ rY = pCurrRectBand->mnYTop;
+ rWidth = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1;
+ rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1;
+
+ // save pointers
+ rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand;
+ rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo,
+ long& rX, long& rY,
+ long& rWidth, long& rHeight ) const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // no internal data? -> region is empty!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return FALSE;
+
+ // get last pointers
+ ImplRegionBand* pCurrRectBand = (ImplRegionBand*)rImplRegionInfo.mpVoidCurrRectBand;
+ ImplRegionBandSep* pCurrRectBandSep = (ImplRegionBandSep*)rImplRegionInfo.mpVoidCurrRectBandSep;
+
+ // get next separation from current band
+ pCurrRectBandSep = pCurrRectBandSep->mpNextSep;
+
+ // no separation found? -> go to next band!
+ if ( !pCurrRectBandSep )
+ {
+ // get next band
+ pCurrRectBand = pCurrRectBand->mpNextBand;
+
+ // no band found? -> not further rectangles!
+ if( !pCurrRectBand )
+ return FALSE;
+
+ // get first separation in current band
+ pCurrRectBandSep = pCurrRectBand->mpFirstSep;
+ }
+
+ // get boundaries of current rectangle
+ rX = pCurrRectBandSep->mnXLeft;
+ rY = pCurrRectBand->mnYTop;
+ rWidth = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1;
+ rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1;
+
+ // save new pointers
+ rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand;
+ rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+RegionType Region::GetType() const
+{
+ if ( mpImplRegion == &aImplEmptyRegion )
+ return REGION_EMPTY;
+ else if ( mpImplRegion == &aImplNullRegion )
+ return REGION_NULL;
+ else if ( mpImplRegion->mnRectCount == 1 )
+ return REGION_RECTANGLE;
+ else
+ return REGION_COMPLEX;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::IsInside( const Point& rPoint ) const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // PolyPolygon data im Imp structure?
+ ((Region*)this)->ImplPolyPolyRegionToBandRegion();
+/*
+ if ( mpImplRegion->mpPolyPoly )
+ return mpImplRegion->mpPolyPoly->IsInside( rPoint );
+*/
+
+ // no instance data? -> not inside
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return FALSE;
+
+ // search band list
+ ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // is point within band?
+ if ( (pBand->mnYTop <= rPoint.Y()) &&
+ (pBand->mnYBottom >= rPoint.Y()) )
+ {
+ // is point within separation of the band?
+ if ( pBand->IsInside( rPoint.X() ) )
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::IsInside( const Rectangle& rRect ) const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // is rectangle empty? -> not inside
+ if ( rRect.IsEmpty() )
+ return FALSE;
+
+ // no instance data? -> not inside
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return FALSE;
+
+ // create region from rectangle and intersect own region
+ Region aRegion = rRect;
+ aRegion.Exclude( *this );
+
+ // rectangle is inside if exclusion is empty
+ return aRegion.IsEmpty();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::IsOver( const Rectangle& rRect ) const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return FALSE;
+
+ // Can we optimize this ??? - is used in StarDraw for brushes pointers
+ // Why we have no IsOver for Regions ???
+ // create region from rectangle and intersect own region
+ Region aRegion = rRect;
+ aRegion.Intersect( *this );
+
+ // rectangle is over if include is not empty
+ return !aRegion.IsEmpty();
+}
+
+// -----------------------------------------------------------------------
+
+void Region::SetNull()
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+
+ // set new type
+ mpImplRegion = (ImplRegion*)(&aImplNullRegion);
+}
+
+// -----------------------------------------------------------------------
+
+void Region::SetEmpty()
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+
+ // set new type
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+}
+
+// -----------------------------------------------------------------------
+
+Region& Region::operator=( const Region& rRegion )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+ DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ // RefCount == 0 fuer statische Objekte
+ if ( rRegion.mpImplRegion->mnRefCount )
+ rRegion.mpImplRegion->mnRefCount++;
+
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+
+ mpImplRegion = rRegion.mpImplRegion;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Region& Region::operator=( const Rectangle& rRect )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+
+ ImplCreateRectRegion( rRect );
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::operator==( const Region& rRegion ) const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+
+ // reference to same object? -> equal!
+ if ( mpImplRegion == rRegion.mpImplRegion )
+ return TRUE;
+
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return FALSE;
+
+ if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
+ return FALSE;
+
+ if ( rRegion.mpImplRegion->mpPolyPoly && mpImplRegion->mpPolyPoly )
+ return *rRegion.mpImplRegion->mpPolyPoly == *mpImplRegion->mpPolyPoly;
+ else
+ {
+ ((Region*)this)->ImplPolyPolyRegionToBandRegion();
+ ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
+
+ // Eine der beiden Regions kann jetzt Empty sein
+ if ( mpImplRegion == rRegion.mpImplRegion )
+ return TRUE;
+
+ if ( mpImplRegion == &aImplEmptyRegion )
+ return FALSE;
+
+ if ( rRegion.mpImplRegion == &aImplEmptyRegion )
+ return FALSE;
+ }
+
+ // initialise pointers
+ ImplRegionBand* pOwnRectBand = mpImplRegion->mpFirstBand;
+ ImplRegionBandSep* pOwnRectBandSep = pOwnRectBand->mpFirstSep;
+ ImplRegionBand* pSecondRectBand = rRegion.mpImplRegion->mpFirstBand;
+ ImplRegionBandSep* pSecondRectBandSep = pSecondRectBand->mpFirstSep;
+ while ( pOwnRectBandSep && pSecondRectBandSep )
+ {
+ // get boundaries of current rectangle
+ long nOwnXLeft = pOwnRectBandSep->mnXLeft;
+ long nSecondXLeft = pSecondRectBandSep->mnXLeft;
+ if ( nOwnXLeft != nSecondXLeft )
+ return FALSE;
+
+ long nOwnYTop = pOwnRectBand->mnYTop;
+ long nSecondYTop = pSecondRectBand->mnYTop;
+ if ( nOwnYTop != nSecondYTop )
+ return FALSE;
+
+ long nOwnXRight = pOwnRectBandSep->mnXRight;
+ long nSecondXRight = pSecondRectBandSep->mnXRight;
+ if ( nOwnXRight != nSecondXRight )
+ return FALSE;
+
+ long nOwnYBottom = pOwnRectBand->mnYBottom;
+ long nSecondYBottom = pSecondRectBand->mnYBottom;
+ if ( nOwnYBottom != nSecondYBottom )
+ return FALSE;
+
+ // get next separation from current band
+ pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
+
+ // no separation found? -> go to next band!
+ if ( !pOwnRectBandSep )
+ {
+ // get next band
+ pOwnRectBand = pOwnRectBand->mpNextBand;
+
+ // get first separation in current band
+ if( pOwnRectBand )
+ pOwnRectBandSep = pOwnRectBand->mpFirstSep;
+ }
+
+ // get next separation from current band
+ pSecondRectBandSep = pSecondRectBandSep->mpNextSep;
+
+ // no separation found? -> go to next band!
+ if ( !pSecondRectBandSep )
+ {
+ // get next band
+ pSecondRectBand = pSecondRectBand->mpNextBand;
+
+ // get first separation in current band
+ if( pSecondRectBand )
+ pSecondRectBandSep = pSecondRectBand->mpFirstSep;
+ }
+
+ if ( pOwnRectBandSep && !pSecondRectBandSep )
+ return FALSE;
+
+ if ( !pOwnRectBandSep && pSecondRectBandSep )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END };
+
+SvStream& operator>>( SvStream& rIStrm, Region& rRegion )
+{
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+
+ VersionCompat aCompat( rIStrm, STREAM_READ );
+ UINT16 nVersion;
+ UINT16 nTmp16;
+
+ // statische Object haben RefCount von 0
+ if ( rRegion.mpImplRegion->mnRefCount )
+ {
+ if ( rRegion.mpImplRegion->mnRefCount > 1 )
+ rRegion.mpImplRegion->mnRefCount--;
+ else
+ delete rRegion.mpImplRegion;
+ }
+
+ // get version of streamed region
+ rIStrm >> nVersion;
+
+ // get type of region
+ rIStrm >> nTmp16;
+
+ RegionType meStreamedType = (RegionType)nTmp16;
+
+ switch( meStreamedType )
+ {
+ case REGION_NULL:
+ rRegion.mpImplRegion = (ImplRegion*)&aImplNullRegion;
+ break;
+
+ case REGION_EMPTY:
+ rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion;
+ break;
+
+ default:
+ {
+ // create instance of implementation class
+ rRegion.mpImplRegion = new ImplRegion();
+
+ // get header from first element
+ rIStrm >> nTmp16;
+
+ // get all bands
+ rRegion.mpImplRegion->mnRectCount = 0;
+ ImplRegionBand* pCurrBand = NULL;
+ while ( (StreamEntryType)nTmp16 != STREAMENTRY_END )
+ {
+ // insert new band or new separation?
+ if ( (StreamEntryType)nTmp16 == STREAMENTRY_BANDHEADER )
+ {
+ long nYTop;
+ long nYBottom;
+
+ rIStrm >> nYTop;
+ rIStrm >> nYBottom;
+
+ // create band
+ ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom );
+
+ // first element? -> set as first into the list
+ if ( !pCurrBand )
+ rRegion.mpImplRegion->mpFirstBand = pNewBand;
+ else
+ pCurrBand->mpNextBand = pNewBand;
+
+ // save pointer for next creation
+ pCurrBand = pNewBand;
+ }
+ else
+ {
+ long nXLeft;
+ long nXRight;
+
+ rIStrm >> nXLeft;
+ rIStrm >> nXRight;
+
+ // add separation
+ if ( pCurrBand )
+ {
+ pCurrBand->Union( nXLeft, nXRight );
+ rRegion.mpImplRegion->mnRectCount++;
+ }
+ }
+
+ if( rIStrm.IsEof() )
+ {
+ DBG_ERROR( "premature end of region stream" );
+ delete rRegion.mpImplRegion;
+ rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion;
+ return rIStrm;
+ }
+
+ // get next header
+ rIStrm >> nTmp16;
+ }
+
+ if( aCompat.GetVersion() >= 2 )
+ {
+ BOOL bHasPolyPolygon;
+
+ rIStrm >> bHasPolyPolygon;
+
+ if( bHasPolyPolygon )
+ {
+ delete rRegion.mpImplRegion->mpPolyPoly;
+ rRegion.mpImplRegion->mpPolyPoly = new PolyPolygon;
+ rIStrm >> *( rRegion.mpImplRegion->mpPolyPoly );
+ }
+ }
+ }
+ break;
+ }
+
+ return rIStrm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStrm, const Region& rRegion )
+{
+ DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
+
+ UINT16 nVersion = 2;
+ VersionCompat aCompat( rOStrm, STREAM_WRITE, nVersion );
+ Region aTmpRegion( rRegion );
+
+ // use tmp region to avoid destruction of internal region (polypolygon) of rRegion
+ aTmpRegion.ImplPolyPolyRegionToBandRegion();
+
+ // put version
+ rOStrm << nVersion;
+
+ // put type
+ rOStrm << (UINT16)aTmpRegion.GetType();
+
+ // put all bands if not null or empty
+ if ( (aTmpRegion.mpImplRegion != &aImplEmptyRegion) && (aTmpRegion.mpImplRegion != &aImplNullRegion) )
+ {
+ ImplRegionBand* pBand = aTmpRegion.mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ // put boundaries
+ rOStrm << (UINT16) STREAMENTRY_BANDHEADER;
+ rOStrm << pBand->mnYTop;
+ rOStrm << pBand->mnYBottom;
+
+ // put separations of current band
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while ( pSep )
+ {
+ // put separation
+ rOStrm << (UINT16) STREAMENTRY_SEPARATION;
+ rOStrm << pSep->mnXLeft;
+ rOStrm << pSep->mnXRight;
+
+ // next separation from current band
+ pSep = pSep->mpNextSep;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+
+ // put endmarker
+ rOStrm << (UINT16) STREAMENTRY_END;
+
+ // write polypolygon if available
+ const BOOL bHasPolyPolygon = rRegion.HasPolyPolygon();
+ rOStrm << bHasPolyPolygon;
+
+ if( bHasPolyPolygon )
+ {
+ // #i105373#
+ PolyPolygon aNoCurvePolyPolygon;
+ rRegion.GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
+
+ rOStrm << aNoCurvePolyPolygon;
+ }
+ }
+
+ return rOStrm;
+}
+
+// -----------------------------------------------------------------------
+
+void Region::ImplBeginAddRect()
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ // statische Object haben RefCount von 0
+ if ( mpImplRegion->mnRefCount )
+ {
+ if ( mpImplRegion->mnRefCount > 1 )
+ mpImplRegion->mnRefCount--;
+ else
+ delete mpImplRegion;
+ }
+
+ // create fresh region
+ mpImplRegion = new ImplRegion();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::ImplAddRect( const Rectangle& rRect )
+{
+ // Hier kein CheckThis, da nicht alle Daten auf Stand
+
+ if ( rRect.IsEmpty() )
+ return TRUE;
+
+ // get justified rectangle
+ long nTop;
+ long nBottom;
+ long nLeft;
+ long nRight;
+ if ( rRect.Top() <= rRect.Bottom() )
+ {
+ nTop = rRect.Top();
+ nBottom = rRect.Bottom();
+ }
+ else
+ {
+ nTop = rRect.Bottom();
+ nBottom = rRect.Top();
+ }
+ if ( rRect.Left() <= rRect.Right() )
+ {
+ nLeft = rRect.Left();
+ nRight = rRect.Right();
+ }
+ else
+ {
+ nLeft = rRect.Right();
+ nRight = rRect.Left();
+ }
+
+ if ( !mpImplRegion->mpLastCheckedBand )
+ {
+ // create new band
+ mpImplRegion->mpLastCheckedBand = new ImplRegionBand( nTop, nBottom );
+
+ // set band as current
+ mpImplRegion->mpFirstBand = mpImplRegion->mpLastCheckedBand;
+ mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight );
+ }
+ else
+ {
+ DBG_ASSERT( nTop >= mpImplRegion->mpLastCheckedBand->mnYTop,
+ "Region::ImplAddRect() - nTopY < nLastTopY" );
+
+ // new band? create it!
+ if ( (nTop != mpImplRegion->mpLastCheckedBand->mnYTop) ||
+ (nBottom != mpImplRegion->mpLastCheckedBand->mnYBottom) )
+ {
+ // create new band
+ ImplRegionBand* pNewRegionBand = new ImplRegionBand( nTop, nBottom );
+
+ // append band to the end
+ mpImplRegion->mpLastCheckedBand->mpNextBand = pNewRegionBand;
+
+ // skip to the new band
+ mpImplRegion->mpLastCheckedBand = mpImplRegion->mpLastCheckedBand->mpNextBand;
+ }
+
+ // Insert Sep
+ mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight );
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Region::ImplEndAddRect()
+{
+ // check if we are empty
+ if ( !mpImplRegion->mpFirstBand )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ return;
+ }
+
+ // check if we have somthing to optimize
+ if ( !mpImplRegion->mpFirstBand->mpNextBand )
+ {
+ // update mpImplRegion->mnRectCount, because no OptimizeBandList is called
+ ImplRegionBandSep* pSep = mpImplRegion->mpFirstBand->mpFirstSep;
+ mpImplRegion->mnRectCount = 0;
+ while( pSep )
+ {
+ mpImplRegion->mnRectCount++;
+ pSep = pSep->mpNextSep;
+ }
+
+ // Erst hier testen, da hier die Daten wieder stimmen
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+ return;
+ }
+
+ // have to revert list? -> do it now!
+ if ( mpImplRegion->mpFirstBand->mnYTop >
+ mpImplRegion->mpFirstBand->mpNextBand->mnYTop )
+ {
+ ImplRegionBand * pNewFirstRegionBand;
+
+ // initialize temp list with first element
+ pNewFirstRegionBand = mpImplRegion->mpFirstBand;
+ mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand;
+ pNewFirstRegionBand->mpNextBand = NULL;
+
+ // insert elements to the temp list
+ while ( mpImplRegion->mpFirstBand )
+ {
+ ImplRegionBand * pSavedRegionBand = pNewFirstRegionBand;
+ pNewFirstRegionBand = mpImplRegion->mpFirstBand;
+ mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand;
+ pNewFirstRegionBand->mpNextBand = pSavedRegionBand;
+ }
+
+ // set temp list as new list
+ mpImplRegion->mpFirstBand = pNewFirstRegionBand;
+ }
+
+ // cleanup
+ if ( !mpImplRegion->OptimizeBandList() )
+ {
+ delete mpImplRegion;
+ mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
+ }
+
+ // Erst hier testen, da hier die Daten wieder stimmen
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Region::GetRectCount() const
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ((Region*)this)->ImplPolyPolyRegionToBandRegion();
+
+#ifdef DBG_UTIL
+ ULONG nCount = 0;
+
+ // all bands if not null or empty
+ if ( (mpImplRegion != &aImplEmptyRegion) && (mpImplRegion != &aImplNullRegion) )
+ {
+ ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
+ while ( pBand )
+ {
+ ImplRegionBandSep* pSep = pBand->mpFirstSep;
+ while( pSep )
+ {
+ nCount++;
+ pSep = pSep->mpNextSep;
+ }
+
+ pBand = pBand->mpNextBand;
+ }
+ }
+
+ DBG_ASSERT( mpImplRegion->mnRectCount == nCount, "Region: invalid mnRectCount!" );
+#endif
+
+ return mpImplRegion->mnRectCount;
+}
+
+// -----------------------------------------------------------------------
+
+RegionHandle Region::BeginEnumRects()
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ImplPolyPolyRegionToBandRegion();
+
+ // no internal data? -> region is empty!
+ if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
+ return 0;
+
+ // no band in the list? -> region is empty!
+ if ( mpImplRegion->mpFirstBand == NULL )
+ {
+ DBG_ASSERT( mpImplRegion->mpFirstBand, "Region::BeginEnumRects() First Band is Empty!" );
+ return 0;
+ }
+
+ ImplRegionHandle* pData = new ImplRegionHandle;
+ pData->mpRegion = new Region( *this );
+ pData->mbFirst = TRUE;
+
+ // save pointers
+ pData->mpCurrRectBand = pData->mpRegion->mpImplRegion->mpFirstBand;
+ pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep;
+
+ return (RegionHandle)pData;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Region::GetEnumRects( RegionHandle pVoidData, Rectangle& rRect )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData;
+ if ( !pData )
+ return FALSE;
+
+ if ( pData->mbFirst )
+ pData->mbFirst = FALSE;
+ else
+ {
+ // get next separation from current band
+ pData->mpCurrRectBandSep = pData->mpCurrRectBandSep->mpNextSep;
+
+ // no separation found? -> go to next band!
+ if ( !pData->mpCurrRectBandSep )
+ {
+ // get next band
+ pData->mpCurrRectBand = pData->mpCurrRectBand->mpNextBand;
+
+ // no band found? -> not further rectangles!
+ if ( !pData->mpCurrRectBand )
+ return FALSE;
+
+ // get first separation in current band
+ pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep;
+ }
+ }
+
+ // get boundaries of current rectangle
+ rRect.Top() = pData->mpCurrRectBand->mnYTop;
+ rRect.Bottom() = pData->mpCurrRectBand->mnYBottom;
+ rRect.Left() = pData->mpCurrRectBandSep->mnXLeft;
+ rRect.Right() = pData->mpCurrRectBandSep->mnXRight;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Region::EndEnumRects( RegionHandle pVoidData )
+{
+ DBG_CHKTHIS( Region, ImplDbgTestRegion );
+
+ ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData;
+ if ( !pData )
+ return;
+
+ // cleanup
+ delete pData->mpRegion;
+ delete pData;
+}
+
+// -----------------------------------------------------------------------
+
+static inline bool ImplPolygonRectTest( const Polygon& rPoly, Rectangle* pRectOut = NULL )
+{
+ bool bIsRect = false;
+ const Point* pPoints = rPoly.GetConstPointAry();
+ USHORT nPoints = rPoly.GetSize();
+ if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) )
+ {
+ long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(),
+ nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y();
+ if( ( (pPoints[1].X() == nX1 && pPoints[3].X() == nX2) &&
+ (pPoints[1].Y() == nY2 && pPoints[3].Y() == nY1) )
+ ||
+ ( (pPoints[1].X() == nX2 && pPoints[3].X() == nX1) &&
+ (pPoints[1].Y() == nY1 && pPoints[3].Y() == nY2) ) )
+ {
+ bIsRect = true;
+ if( pRectOut )
+ {
+ long nSwap;
+ if( nX2 < nX1 )
+ {
+ nSwap = nX2;
+ nX2 = nX1;
+ nX1 = nSwap;
+ }
+ if( nY2 < nY1 )
+ {
+ nSwap = nY2;
+ nY2 = nY1;
+ nY1 = nSwap;
+ }
+ if( nX2 != nX1 )
+ nX2--;
+ if( nY2 != nY1 )
+ nY2--;
+ pRectOut->Left() = nX1;
+ pRectOut->Right() = nX2;
+ pRectOut->Top() = nY1;
+ pRectOut->Bottom() = nY2;
+ }
+ }
+ }
+ return bIsRect;
+}
+
+Region Region::GetRegionFromPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ //return Region( rPolyPoly );
+
+ // check if it's worth extracting the XOr'ing the Rectangles
+ // empiricism shows that break even between XOr'ing rectangles separately
+ // and ImplPolyPolyRegionToBandRegion is at half rectangles/half polygons
+ int nPolygonRects = 0, nPolygonPolygons = 0;
+ int nPolygons = rPolyPoly.Count();
+
+ for( USHORT i = 0; i < nPolygons; i++ )
+ {
+ const Polygon& rPoly = rPolyPoly[i];
+ if( ImplPolygonRectTest( rPoly ) )
+ nPolygonRects++;
+ else
+ nPolygonPolygons++;
+ }
+ if( nPolygonPolygons > nPolygonRects )
+ return Region( rPolyPoly );
+
+ Region aResult;
+ Rectangle aRect;
+ for( USHORT i = 0; i < nPolygons; i++ )
+ {
+ const Polygon& rPoly = rPolyPoly[i];
+ if( ImplPolygonRectTest( rPoly, &aRect ) )
+ aResult.XOr( aRect );
+ else
+ aResult.XOr( Region(rPoly) );
+ }
+ return aResult;
+}
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
new file mode 100755
index 000000000000..97e11c5a6aa4
--- /dev/null
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -0,0 +1,820 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/ref.hxx>
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salgdi.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/salvd.hxx>
+#include <vcl/salprn.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/poly.hxx>
+#include <vcl/region.hxx>
+#include <vcl/region.h>
+#include <vcl/virdev.hxx>
+#include <vcl/window.h>
+#include <vcl/window.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/outdata.hxx>
+#include <vcl/print.hxx>
+#include <vcl/outdev.h>
+#include <vcl/outdev.hxx>
+#include <vcl/unowrap.hxx>
+#include <vcl/sallayout.hxx>
+#include "basegfx/polygon/b2dpolygon.hxx"
+
+// ----------------------------------------------------------------------------
+// The only common SalFrame method
+// ----------------------------------------------------------------------------
+
+SalFrameGeometry SalFrame::GetGeometry()
+{
+ // mirror frame coordinates at parent
+ SalFrame *pParent = GetParent();
+ if( pParent && Application::GetSettings().GetLayoutRTL() )
+ {
+ SalFrameGeometry aGeom = maGeometry;
+ int parent_x = aGeom.nX - pParent->maGeometry.nX;
+ aGeom.nX = pParent->maGeometry.nX + pParent->maGeometry.nWidth - maGeometry.nWidth - parent_x;
+ return aGeom;
+ }
+ else
+ return maGeometry;
+}
+
+// ----------------------------------------------------------------------------
+
+SalGraphics::SalGraphics()
+: m_nLayout( 0 ),
+ m_bAntiAliasB2DDraw(false)
+{
+ // read global RTL settings
+ if( Application::GetSettings().GetLayoutRTL() )
+ m_nLayout = SAL_LAYOUT_BIDI_RTL;
+}
+
+SalGraphics::~SalGraphics()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+bool SalGraphics::drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap&, const SalBitmap& )
+{
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+void SalGraphics::mirror( long& x, const OutputDevice *pOutDev, bool bBack ) const
+{
+ long w;
+ if( pOutDev && pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
+ w = pOutDev->GetOutputWidthPixel();
+ else
+ w = GetGraphicsWidth();
+
+ if( w )
+ {
+ if( pOutDev && pOutDev->ImplIsAntiparallel() )
+ {
+ OutputDevice *pOutDevRef = (OutputDevice*) pOutDev;
+ // mirror this window back
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ long devX = w-pOutDevRef->GetOutputWidthPixel()-pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX
+ if( bBack )
+ x = x - devX + pOutDevRef->GetOutOffXPixel();
+ else
+ x = devX + (x - pOutDevRef->GetOutOffXPixel());
+ }
+ else
+ {
+ long devX = pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX
+ if( bBack )
+ x = x - pOutDevRef->GetOutputWidthPixel() + devX - pOutDevRef->GetOutOffXPixel() + 1;
+ else
+ x = pOutDevRef->GetOutputWidthPixel() - (x - devX) + pOutDevRef->GetOutOffXPixel() - 1;
+ }
+ }
+ else if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ x = w-1-x;
+ }
+}
+
+void SalGraphics::mirror( long& x, long& nWidth, const OutputDevice *pOutDev, bool bBack ) const
+{
+ long w;
+ if( pOutDev && pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
+ w = pOutDev->GetOutputWidthPixel();
+ else
+ w = GetGraphicsWidth();
+
+ if( w )
+ {
+ if( pOutDev && pOutDev->ImplIsAntiparallel() )
+ {
+ OutputDevice *pOutDevRef = (OutputDevice*) pOutDev;
+ // mirror this window back
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ long devX = w-pOutDevRef->GetOutputWidthPixel()-pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX
+ if( bBack )
+ x = x - devX + pOutDevRef->GetOutOffXPixel();
+ else
+ x = devX + (x - pOutDevRef->GetOutOffXPixel());
+ }
+ else
+ {
+ long devX = pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX
+ if( bBack )
+ x = x - pOutDevRef->GetOutputWidthPixel() + devX - pOutDevRef->GetOutOffXPixel() + nWidth;
+ else
+ x = pOutDevRef->GetOutputWidthPixel() - (x - devX) + pOutDevRef->GetOutOffXPixel() - nWidth;
+ }
+ }
+ else if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ x = w-nWidth-x;
+
+ }
+}
+
+BOOL SalGraphics::mirror( sal_uInt32 nPoints, const SalPoint *pPtAry, SalPoint *pPtAry2, const OutputDevice *pOutDev, bool bBack ) const
+{
+ long w;
+ if( pOutDev && pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
+ w = pOutDev->GetOutputWidthPixel();
+ else
+ w = GetGraphicsWidth();
+
+ if( w )
+ {
+ sal_uInt32 i, j;
+
+ if( pOutDev && pOutDev->ImplIsAntiparallel() )
+ {
+ OutputDevice *pOutDevRef = (OutputDevice*) pOutDev;
+ // mirror this window back
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ long devX = w-pOutDevRef->GetOutputWidthPixel()-pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX
+ if( bBack )
+ {
+ for( i=0, j=nPoints-1; i<nPoints; i++,j-- )
+ {
+ //long x = w-1-pPtAry[i].mnX;
+ //pPtAry2[j].mnX = devX + ( pOutDevRef->mnOutWidth - 1 - (x - devX) );
+ pPtAry2[j].mnX = pOutDevRef->GetOutOffXPixel() + (pPtAry[i].mnX - devX);
+ pPtAry2[j].mnY = pPtAry[i].mnY;
+ }
+ }
+ else
+ {
+ for( i=0, j=nPoints-1; i<nPoints; i++,j-- )
+ {
+ //long x = w-1-pPtAry[i].mnX;
+ //pPtAry2[j].mnX = devX + ( pOutDevRef->mnOutWidth - 1 - (x - devX) );
+ pPtAry2[j].mnX = devX + (pPtAry[i].mnX - pOutDevRef->GetOutOffXPixel());
+ pPtAry2[j].mnY = pPtAry[i].mnY;
+ }
+ }
+ }
+ else
+ {
+ long devX = pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX
+ if( bBack )
+ {
+ for( i=0, j=nPoints-1; i<nPoints; i++,j-- )
+ {
+ //long x = w-1-pPtAry[i].mnX;
+ //pPtAry2[j].mnX = devX + ( pOutDevRef->mnOutWidth - 1 - (x - devX) );
+ pPtAry2[j].mnX = pPtAry[i].mnX - pOutDevRef->GetOutputWidthPixel() + devX - pOutDevRef->GetOutOffXPixel() + 1;
+ pPtAry2[j].mnY = pPtAry[i].mnY;
+ }
+ }
+ else
+ {
+ for( i=0, j=nPoints-1; i<nPoints; i++,j-- )
+ {
+ //long x = w-1-pPtAry[i].mnX;
+ //pPtAry2[j].mnX = devX + ( pOutDevRef->mnOutWidth - 1 - (x - devX) );
+ pPtAry2[j].mnX = pOutDevRef->GetOutputWidthPixel() - (pPtAry[i].mnX - devX) + pOutDevRef->GetOutOffXPixel() - 1;
+ pPtAry2[j].mnY = pPtAry[i].mnY;
+ }
+ }
+ }
+ }
+ else if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ for( i=0, j=nPoints-1; i<nPoints; i++,j-- )
+ {
+ pPtAry2[j].mnX = w-1-pPtAry[i].mnX;
+ pPtAry2[j].mnY = pPtAry[i].mnY;
+ }
+ }
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+void SalGraphics::mirror( Region& rRgn, const OutputDevice *pOutDev, bool bBack ) const
+{
+ // mirror the bounding rect and move Region by resulting offset
+ Rectangle aRect( rRgn.GetBoundRect() );
+ long nWidth = aRect.GetWidth();
+ long x = aRect.Left();
+ long x_org = x;
+
+ mirror( x, nWidth, pOutDev, bBack );
+ rRgn.Move( x - x_org, 0 );
+}
+
+void SalGraphics::mirror( Rectangle& rRect, const OutputDevice *pOutDev, bool bBack ) const
+{
+ long nWidth = rRect.GetWidth();
+ long x = rRect.Left();
+ long x_org = x;
+
+ mirror( x, nWidth, pOutDev, bBack );
+ rRect.Move( x - x_org, 0 );
+}
+
+basegfx::B2DPoint SalGraphics::mirror( const basegfx::B2DPoint& i_rPoint, const OutputDevice *i_pOutDev, bool i_bBack ) const
+{
+ long w;
+ if( i_pOutDev && i_pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
+ w = i_pOutDev->GetOutputWidthPixel();
+ else
+ w = GetGraphicsWidth();
+
+ DBG_ASSERT( w, "missing graphics width" );
+
+ basegfx::B2DPoint aRet( i_rPoint );
+ if( w )
+ {
+ if( i_pOutDev && !i_pOutDev->IsRTLEnabled() )
+ {
+ OutputDevice *pOutDevRef = (OutputDevice*)i_pOutDev;
+ // mirror this window back
+ double devX = w-pOutDevRef->GetOutputWidthPixel()-pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX
+ if( i_bBack )
+ aRet.setX( i_rPoint.getX() - devX + pOutDevRef->GetOutOffXPixel() );
+ else
+ aRet.setX( devX + (i_rPoint.getX() - pOutDevRef->GetOutOffXPixel()) );
+ }
+ else
+ aRet.setX( w-1-i_rPoint.getX() );
+ }
+ return aRet;
+}
+
+basegfx::B2DPolygon SalGraphics::mirror( const basegfx::B2DPolygon& i_rPoly, const OutputDevice *i_pOutDev, bool i_bBack ) const
+{
+ long w;
+ if( i_pOutDev && i_pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
+ w = i_pOutDev->GetOutputWidthPixel();
+ else
+ w = GetGraphicsWidth();
+
+ DBG_ASSERT( w, "missing graphics width" );
+
+ basegfx::B2DPolygon aRet;
+ if( w )
+ {
+ sal_Int32 nPoints = i_rPoly.count();
+ for( sal_Int32 i = 0; i < nPoints; i++ )
+ {
+ aRet.append( mirror( i_rPoly.getB2DPoint( i ), i_pOutDev, i_bBack ) );
+ if( i_rPoly.isPrevControlPointUsed( i ) )
+ aRet.setPrevControlPoint( i, mirror( i_rPoly.getPrevControlPoint( i ), i_pOutDev, i_bBack ) );
+ if( i_rPoly.isNextControlPointUsed( i ) )
+ aRet.setNextControlPoint( i, mirror( i_rPoly.getNextControlPoint( i ), i_pOutDev, i_bBack ) );
+ }
+ aRet.setClosed( i_rPoly.isClosed() );
+ aRet.flip();
+ }
+ else
+ aRet = i_rPoly;
+ return aRet;
+}
+
+basegfx::B2DPolyPolygon SalGraphics::mirror( const basegfx::B2DPolyPolygon& i_rPoly, const OutputDevice *i_pOutDev, bool i_bBack ) const
+{
+ long w;
+ if( i_pOutDev && i_pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
+ w = i_pOutDev->GetOutputWidthPixel();
+ else
+ w = GetGraphicsWidth();
+
+ DBG_ASSERT( w, "missing graphics width" );
+
+ basegfx::B2DPolyPolygon aRet;
+ if( w )
+ {
+ sal_Int32 nPoly = i_rPoly.count();
+ for( sal_Int32 i = 0; i < nPoly; i++ )
+ aRet.append( mirror( i_rPoly.getB2DPolygon( i ), i_pOutDev, i_bBack ) );
+ aRet.setClosed( i_rPoly.isClosed() );
+ aRet.flip();
+ }
+ else
+ aRet = i_rPoly;
+ return aRet;
+}
+
+// ----------------------------------------------------------------------------
+
+BOOL SalGraphics::UnionClipRegion( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, nWidth, pOutDev );
+ return unionClipRegion( nX, nY, nWidth, nHeight );
+}
+
+bool SalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ return false;
+}
+
+BOOL SalGraphics::UnionClipRegion( const ::basegfx::B2DPolyPolygon& rPoly, const OutputDevice* pOutDev )
+{
+ (void)pOutDev;// TODO: SAL_LAYOUT_BIDI_RTL
+ return unionClipRegion( rPoly );
+}
+
+void SalGraphics::DrawPixel( long nX, long nY, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, pOutDev );
+ drawPixel( nX, nY );
+}
+void SalGraphics::DrawPixel( long nX, long nY, SalColor nSalColor, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, pOutDev );
+ drawPixel( nX, nY, nSalColor );
+}
+void SalGraphics::DrawLine( long nX1, long nY1, long nX2, long nY2, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ mirror( nX1, pOutDev );
+ mirror( nX2, pOutDev );
+ }
+ drawLine( nX1, nY1, nX2, nY2 );
+}
+void SalGraphics::DrawRect( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, nWidth, pOutDev );
+ drawRect( nX, nY, nWidth, nHeight );
+}
+bool SalGraphics::drawPolyLine(
+ const basegfx::B2DPolygon& /*rPolyPolygon*/,
+ double /*fTransparency*/,
+ const basegfx::B2DVector& /*rLineWidths*/,
+ basegfx::B2DLineJoin /*eLineJoin*/)
+{
+ return false;
+}
+
+void SalGraphics::DrawPolyLine( ULONG nPoints, const SalPoint* pPtAry, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalPoint* pPtAry2 = new SalPoint[nPoints];
+ BOOL bCopied = mirror( nPoints, pPtAry, pPtAry2, pOutDev );
+ drawPolyLine( nPoints, bCopied ? pPtAry2 : pPtAry );
+ delete [] pPtAry2;
+ }
+ else
+ drawPolyLine( nPoints, pPtAry );
+}
+
+void SalGraphics::DrawPolygon( ULONG nPoints, const SalPoint* pPtAry, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalPoint* pPtAry2 = new SalPoint[nPoints];
+ BOOL bCopied = mirror( nPoints, pPtAry, pPtAry2, pOutDev );
+ drawPolygon( nPoints, bCopied ? pPtAry2 : pPtAry );
+ delete [] pPtAry2;
+ }
+ else
+ drawPolygon( nPoints, pPtAry );
+}
+
+void SalGraphics::DrawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ // TODO: optimize, reduce new/delete calls
+ SalPoint **pPtAry2 = new SalPoint*[nPoly];
+ ULONG i;
+ for(i=0; i<nPoly; i++)
+ {
+ ULONG nPoints = pPoints[i];
+ pPtAry2[i] = new SalPoint[ nPoints ];
+ mirror( nPoints, pPtAry[i], pPtAry2[i], pOutDev );
+ }
+
+ drawPolyPolygon( nPoly, pPoints, (PCONSTSALPOINT*)pPtAry2 );
+
+ for(i=0; i<nPoly; i++)
+ delete [] pPtAry2[i];
+ delete [] pPtAry2;
+ }
+ else
+ drawPolyPolygon( nPoly, pPoints, pPtAry );
+}
+
+bool SalGraphics::DrawPolyPolygon( const ::basegfx::B2DPolyPolygon& i_rPolyPolygon, double i_fTransparency, const OutputDevice* i_pOutDev )
+{
+ bool bRet = false;
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ basegfx::B2DPolyPolygon aMirror( mirror( i_rPolyPolygon, i_pOutDev ) );
+ bRet = drawPolyPolygon( aMirror, i_fTransparency );
+ }
+ else
+ bRet = drawPolyPolygon( i_rPolyPolygon, i_fTransparency );
+ return bRet;
+}
+
+bool SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fTransparency*/)
+{
+ return false;
+}
+
+sal_Bool SalGraphics::DrawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry, const OutputDevice* pOutDev )
+{
+ sal_Bool bResult = sal_False;
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ SalPoint* pPtAry2 = new SalPoint[nPoints];
+ BOOL bCopied = mirror( nPoints, pPtAry, pPtAry2, pOutDev );
+ bResult = drawPolyLineBezier( nPoints, bCopied ? pPtAry2 : pPtAry, pFlgAry );
+ delete [] pPtAry2;
+ }
+ else
+ bResult = drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
+ return bResult;
+}
+
+sal_Bool SalGraphics::DrawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry, const OutputDevice* pOutDev )
+{
+ sal_Bool bResult = sal_False;
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ SalPoint* pPtAry2 = new SalPoint[nPoints];
+ BOOL bCopied = mirror( nPoints, pPtAry, pPtAry2, pOutDev );
+ bResult = drawPolygonBezier( nPoints, bCopied ? pPtAry2 : pPtAry, pFlgAry );
+ delete [] pPtAry2;
+ }
+ else
+ bResult = drawPolygonBezier( nPoints, pPtAry, pFlgAry );
+ return bResult;
+}
+
+sal_Bool SalGraphics::DrawPolyPolygonBezier( sal_uInt32 i_nPoly, const sal_uInt32* i_pPoints,
+ const SalPoint* const* i_pPtAry, const BYTE* const* i_pFlgAry, const OutputDevice* i_pOutDev )
+{
+ sal_Bool bRet = sal_False;
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ // TODO: optimize, reduce new/delete calls
+ SalPoint **pPtAry2 = new SalPoint*[i_nPoly];
+ ULONG i;
+ for(i=0; i<i_nPoly; i++)
+ {
+ ULONG nPoints = i_pPoints[i];
+ pPtAry2[i] = new SalPoint[ nPoints ];
+ mirror( nPoints, i_pPtAry[i], pPtAry2[i], i_pOutDev );
+ }
+
+ bRet = drawPolyPolygonBezier( i_nPoly, i_pPoints, (PCONSTSALPOINT*)pPtAry2, i_pFlgAry );
+
+ for(i=0; i<i_nPoly; i++)
+ delete [] pPtAry2[i];
+ delete [] pPtAry2;
+ }
+ else
+ bRet = drawPolyPolygonBezier( i_nPoly, i_pPoints, i_pPtAry, i_pFlgAry );
+ return bRet;
+}
+
+bool SalGraphics::DrawPolyLine( const ::basegfx::B2DPolygon& i_rPolygon, double fTransparency,
+ const ::basegfx::B2DVector& i_rLineWidth, basegfx::B2DLineJoin i_eLineJoin,
+ const OutputDevice* i_pOutDev )
+{
+ bool bRet = false;
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) )
+ {
+ basegfx::B2DPolygon aMirror( mirror( i_rPolygon, i_pOutDev ) );
+ bRet = drawPolyLine( aMirror, fTransparency, i_rLineWidth, i_eLineJoin );
+ }
+ else
+ bRet = drawPolyLine( i_rPolygon, fTransparency, i_rLineWidth, i_eLineJoin );
+ return bRet;
+}
+
+void SalGraphics::CopyArea( long nDestX, long nDestY,
+ long nSrcX, long nSrcY,
+ long nSrcWidth, long nSrcHeight,
+ USHORT nFlags, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ mirror( nDestX, nSrcWidth, pOutDev );
+ mirror( nSrcX, nSrcWidth, pOutDev );
+ }
+ copyArea( nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, nFlags );
+}
+void SalGraphics::CopyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics, const OutputDevice *pOutDev, const OutputDevice *pSrcOutDev )
+{
+ if( ( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) ) ||
+ (pSrcGraphics && ( (pSrcGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) || (pSrcOutDev && pSrcOutDev->IsRTLEnabled()) ) ) )
+ {
+ SalTwoRect pPosAry2 = *pPosAry;
+ if( (pSrcGraphics && (pSrcGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL)) || (pSrcOutDev && pSrcOutDev->IsRTLEnabled()) )
+ mirror( pPosAry2.mnSrcX, pPosAry2.mnSrcWidth, pSrcOutDev );
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( pPosAry2.mnDestX, pPosAry2.mnDestWidth, pOutDev );
+ copyBits( &pPosAry2, pSrcGraphics );
+ }
+ else
+ copyBits( pPosAry, pSrcGraphics );
+}
+void SalGraphics::DrawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalTwoRect pPosAry2 = *pPosAry;
+ mirror( pPosAry2.mnDestX, pPosAry2.mnDestWidth, pOutDev );
+ drawBitmap( &pPosAry2, rSalBitmap );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap );
+}
+void SalGraphics::DrawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalTwoRect pPosAry2 = *pPosAry;
+ mirror( pPosAry2.mnDestX, pPosAry2.mnDestWidth, pOutDev );
+ drawBitmap( &pPosAry2, rSalBitmap, nTransparentColor );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap, nTransparentColor );
+}
+void SalGraphics::DrawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalTwoRect pPosAry2 = *pPosAry;
+ mirror( pPosAry2.mnDestX, pPosAry2.mnDestWidth, pOutDev );
+ drawBitmap( &pPosAry2, rSalBitmap, rTransparentBitmap );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap, rTransparentBitmap );
+}
+void SalGraphics::DrawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalTwoRect pPosAry2 = *pPosAry;
+ mirror( pPosAry2.mnDestX, pPosAry2.mnDestWidth, pOutDev );
+ drawMask( &pPosAry2, rSalBitmap, nMaskColor );
+ }
+ else
+ drawMask( pPosAry, rSalBitmap, nMaskColor );
+}
+SalBitmap* SalGraphics::GetBitmap( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, nWidth, pOutDev );
+ return getBitmap( nX, nY, nWidth, nHeight );
+}
+SalColor SalGraphics::GetPixel( long nX, long nY, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, pOutDev );
+ return getPixel( nX, nY );
+}
+void SalGraphics::Invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, nWidth, pOutDev );
+ invert( nX, nY, nWidth, nHeight, nFlags );
+}
+void SalGraphics::Invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalPoint* pPtAry2 = new SalPoint[nPoints];
+ BOOL bCopied = mirror( nPoints, pPtAry, pPtAry2, pOutDev );
+ invert( nPoints, bCopied ? pPtAry2 : pPtAry, nFlags );
+ delete [] pPtAry2;
+ }
+ else
+ invert( nPoints, pPtAry, nFlags );
+}
+
+BOOL SalGraphics::DrawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, nWidth, pOutDev );
+ return drawEPS( nX, nY, nWidth, nHeight, pPtr, nSize );
+}
+
+BOOL SalGraphics::HitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ const Point& aPos, BOOL& rIsInside, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Point pt( aPos );
+ Rectangle rgn( rControlRegion );
+ mirror( pt.X(), pOutDev );
+ mirror( rgn, pOutDev );
+ return hitTestNativeControl( nType, nPart, rgn, pt, rIsInside );
+ }
+ else
+ return hitTestNativeControl( nType, nPart, rControlRegion, aPos, rIsInside );
+}
+
+void SalGraphics::mirror( ControlType , const ImplControlValue& rVal, const OutputDevice* pOutDev, bool bBack ) const
+{
+ switch( rVal.getType() )
+ {
+ case CTRL_SLIDER:
+ {
+ SliderValue* pSlVal = static_cast<SliderValue*>(const_cast<ImplControlValue*>(&rVal));
+ mirror(pSlVal->maThumbRect,pOutDev,bBack);
+ }
+ break;
+ case CTRL_SCROLLBAR:
+ {
+ ScrollbarValue* pScVal = static_cast<ScrollbarValue*>(const_cast<ImplControlValue*>(&rVal));
+ mirror(pScVal->maThumbRect,pOutDev,bBack);
+ mirror(pScVal->maButton1Rect,pOutDev,bBack);
+ mirror(pScVal->maButton2Rect,pOutDev,bBack);
+ }
+ break;
+ case CTRL_SPINBOX:
+ case CTRL_SPINBUTTONS:
+ {
+ SpinbuttonValue* pSpVal = static_cast<SpinbuttonValue*>(const_cast<ImplControlValue*>(&rVal));
+ mirror(pSpVal->maUpperRect,pOutDev,bBack);
+ mirror(pSpVal->maLowerRect,pOutDev,bBack);
+ }
+ break;
+ case CTRL_TOOLBAR:
+ {
+ ToolbarValue* pTVal = static_cast<ToolbarValue*>(const_cast<ImplControlValue*>(&rVal));
+ mirror(pTVal->maGripRect,pOutDev,bBack);
+ }
+ break;
+ }
+}
+
+BOOL SalGraphics::DrawNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& aCaption, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Rectangle rgn( rControlRegion );
+ mirror( rgn, pOutDev );
+ mirror( nType, aValue, pOutDev );
+ BOOL bRet = drawNativeControl( nType, nPart, rgn, nState, aValue, aCaption );
+ mirror( nType, aValue, pOutDev, true );
+ return bRet;
+ }
+ else
+ return drawNativeControl( nType, nPart, rControlRegion, nState, aValue, aCaption );
+}
+
+BOOL SalGraphics::DrawNativeControlText( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& aCaption, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Rectangle rgn( rControlRegion );
+ mirror( rgn, pOutDev );
+ mirror( nType, aValue, pOutDev );
+ BOOL bRet = drawNativeControlText( nType, nPart, rgn, nState, aValue, aCaption );
+ mirror( nType, aValue, pOutDev, true );
+ return bRet;
+ }
+ else
+ return drawNativeControlText( nType, nPart, rControlRegion, nState, aValue, aCaption );
+}
+
+BOOL SalGraphics::GetNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const OUString& aCaption,
+ Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Rectangle rgn( rControlRegion );
+ mirror( rgn, pOutDev );
+ mirror( nType, aValue, pOutDev );
+ if( getNativeControlRegion( nType, nPart, rgn, nState, aValue, aCaption,
+ rNativeBoundingRegion, rNativeContentRegion ) )
+ {
+ mirror( rNativeBoundingRegion, pOutDev, true );
+ mirror( rNativeContentRegion, pOutDev, true );
+ mirror( nType, aValue, pOutDev, true );
+ return TRUE;
+ }
+ else
+ {
+ mirror( nType, aValue, pOutDev, true );
+ return FALSE;
+ }
+ }
+ else
+ return getNativeControlRegion( nType, nPart, rControlRegion, nState, aValue, aCaption,
+ rNativeBoundingRegion, rNativeContentRegion );
+}
+
+bool SalGraphics::DrawAlphaBitmap( const SalTwoRect& rPosAry,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap,
+ const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ SalTwoRect pPosAry2 = rPosAry;
+ mirror( pPosAry2.mnDestX, pPosAry2.mnDestWidth, pOutDev );
+ return drawAlphaBitmap( pPosAry2, rSourceBitmap, rAlphaBitmap );
+ }
+ else
+ return drawAlphaBitmap( rPosAry, rSourceBitmap, rAlphaBitmap );
+}
+
+bool SalGraphics::DrawAlphaRect( long nX, long nY, long nWidth, long nHeight,
+ sal_uInt8 nTransparency, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ mirror( nX, nWidth, pOutDev );
+
+ return drawAlphaRect( nX, nY, nWidth, nHeight, nTransparency );
+}
+
+bool SalGraphics::filterText( const String&, String&, xub_StrLen, xub_StrLen&, xub_StrLen&, xub_StrLen& )
+{
+ return false;
+}
+
+void SalGraphics::AddDevFontSubstitute( OutputDevice* pOutDev,
+ const String& rFontName,
+ const String& rReplaceFontName,
+ USHORT nFlags )
+{
+ pOutDev->ImplAddDevFontSubstitute( rFontName, rReplaceFontName, nFlags );
+}
+
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
new file mode 100755
index 000000000000..5e187944c706
--- /dev/null
+++ b/vcl/source/gdi/sallayout.cxx
@@ -0,0 +1,2326 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <cstdio>
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <sal/alloca.h>
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salgdi.hxx>
+#include <vcl/sallayout.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <i18npool/lang.h>
+
+#ifndef _TL_DEBUG_HXX
+#include <tools/debug.hxx>
+#endif
+
+#include <limits.h>
+
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#endif
+#include <unicode/ubidi.h>
+#include <unicode/uchar.h>
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <algorithm>
+
+#ifdef DEBUG
+//#define MULTI_SL_DEBUG
+#endif
+
+#ifdef MULTI_SL_DEBUG
+#include <string>
+FILE * mslLogFile = NULL;
+FILE * mslLog()
+{
+#ifdef MSC
+ std::string logFileName(getenv("TEMP"));
+ logFileName.append("\\msllayout.log");
+ if (mslLogFile == NULL) mslLogFile = fopen(logFileName.c_str(),"w");
+ else fflush(mslLogFile);
+ return mslLogFile;
+#else
+ return stdout;
+#endif
+}
+#endif
+// =======================================================================
+
+// TODO: ask the glyph directly, for now we need this method because of #i99367#
+// true if a codepoint doesn't influence the logical text width
+bool IsDiacritic( sal_UCS4 nChar )
+{
+ // shortcut abvious non-diacritics
+ if( nChar < 0x0300 )
+ return false;
+ if( nChar >= 0x2100 )
+ return false;
+
+ // TODO: #i105058# use icu uchar.h's character classification instead of the handcrafted table
+ struct DiaRange { sal_UCS4 mnMin, mnEnd;};
+ static const DiaRange aRanges[] = {
+ {0x0300, 0x0370},
+ {0x0590, 0x05BE}, {0x05BF, 0x05C0}, {0x05C1, 0x05C3}, {0x05C4, 0x05C6}, {0x05C7, 0x05C8},
+ {0x0610, 0x061B}, {0x064B, 0x0660}, {0x0670, 0x0671}, {0x06D6, 0x06DD}, {0x06DF, 0x06E5}, {0x06E7, 0x06E9}, {0x06EA,0x06EF},
+ {0x0730, 0x074D}, {0x07A6, 0x07B1}, {0x07EB, 0x07F4},
+#if 0 // all known fonts have zero-width diacritics already, so no need to query it
+ {0x0900, 0x0904}, {0x093C, 0x093D}, {0x0941, 0x0948}, {0x094D, 0x0950}, {0x0951, 0x0958},
+ {0x0980, 0x0985}, {0x09BC, 0x09BD}, {0x09C1, 0x09C7}, {0x09CD, 0x09CE}, {0x09E2, 0x09E6},
+ {0x0A00, 0x0A05}, {0x0A3C, 0x0A59}, //...
+#endif
+ {0x1DC0, 0x1E00},
+ {0x205F, 0x2070}, {0x20D0, 0x2100},
+ {0xFB1E, 0xFB1F}
+ };
+
+ // TODO: almost anything is faster than an O(n) search
+ static const int nCount = sizeof(aRanges) / sizeof(*aRanges);
+ const DiaRange* pRange = &aRanges[0];
+ for( int i = nCount; --i >= 0; ++pRange )
+ if( (pRange->mnMin <= nChar) && (nChar < pRange->mnEnd) )
+ return true;
+
+ return false;
+}
+
+// =======================================================================
+
+int GetVerticalFlags( sal_UCS4 nChar )
+{
+ if( (nChar >= 0x1100 && nChar <= 0x11f9) // Hangul Jamo
+ || (nChar == 0x2030 || nChar == 0x2031) // per mille sign
+ || (nChar >= 0x3000 && nChar <= 0xfaff) // unified CJK
+ || (nChar >= 0xfe20 && nChar <= 0xfe6f) // CJK compatibility
+ || (nChar >= 0xff00 && nChar <= 0xfffd) ) // other CJK
+ {
+ /* #i52932# remember:
+ nChar == 0x2010 || nChar == 0x2015
+ nChar == 0x2016 || nChar == 0x2026
+ are GF_NONE also, but already handled in the outer if condition
+ */
+ if((nChar >= 0x3008 && nChar <= 0x301C && nChar != 0x3012)
+ || (nChar == 0xFF3B || nChar == 0xFF3D)
+ || (nChar >= 0xFF5B && nChar <= 0xFF9F) // halfwidth forms
+ || (nChar == 0xFFE3) )
+ return GF_NONE; // not rotated
+ else if( nChar == 0x30fc )
+ return GF_ROTR; // right
+ return GF_ROTL; // left
+ }
+ else if( (nChar >= 0x20000) && (nChar <= 0x3FFFF) ) // all SIP/TIP ideographs
+ return GF_ROTL; // left
+
+ return GF_NONE; // not rotated as default
+}
+
+// -----------------------------------------------------------------------
+
+sal_UCS4 GetVerticalChar( sal_UCS4 )
+{
+ return 0; // #i14788# input method is responsible vertical char changes
+
+#if 0
+ int nVert = 0;
+ switch( nChar )
+ {
+ // #104627# special treatment for some unicodes
+ case 0x002C: nVert = 0x3001; break;
+ case 0x002E: nVert = 0x3002; break;
+ /*
+ // to few fonts have the compatibility forms, using
+ // them will then cause more trouble than good
+ // TODO: decide on a font specific basis
+ case 0x2018: nVert = 0xFE41; break;
+ case 0x2019: nVert = 0xFE42; break;
+ case 0x201C: nVert = 0xFE43; break;
+ case 0x201D: nVert = 0xFE44; break;
+ // CJK compatibility forms
+ case 0x2025: nVert = 0xFE30; break;
+ case 0x2014: nVert = 0xFE31; break;
+ case 0x2013: nVert = 0xFE32; break;
+ case 0x005F: nVert = 0xFE33; break;
+ case 0x0028: nVert = 0xFE35; break;
+ case 0x0029: nVert = 0xFE36; break;
+ case 0x007B: nVert = 0xFE37; break;
+ case 0x007D: nVert = 0xFE38; break;
+ case 0x3014: nVert = 0xFE39; break;
+ case 0x3015: nVert = 0xFE3A; break;
+ case 0x3010: nVert = 0xFE3B; break;
+ case 0x3011: nVert = 0xFE3C; break;
+ case 0x300A: nVert = 0xFE3D; break;
+ case 0x300B: nVert = 0xFE3E; break;
+ case 0x3008: nVert = 0xFE3F; break;
+ case 0x3009: nVert = 0xFE40; break;
+ case 0x300C: nVert = 0xFE41; break;
+ case 0x300D: nVert = 0xFE42; break;
+ case 0x300E: nVert = 0xFE43; break;
+ case 0x300F: nVert = 0xFE44; break;
+ */
+ }
+
+ return nVert;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+VCL_DLLPUBLIC sal_UCS4 GetMirroredChar( sal_UCS4 nChar )
+{
+ nChar = u_charMirror( nChar );
+ return nChar;
+}
+
+// -----------------------------------------------------------------------
+
+// Get simple approximations for unicodes
+const char* GetAutofallback( sal_UCS4 nChar )
+{
+ const char* pStr = NULL;
+ switch( nChar )
+ {
+ case 0x01C0:
+ case 0x2223:
+ case 0x2758:
+ pStr = "|"; break;
+ case 0x02DC:
+ pStr = "~"; break;
+ case 0x037E:
+ pStr = ";"; break;
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2007:
+ case 0x2008:
+ case 0x2009:
+ case 0x200A:
+ case 0x202F:
+ pStr = " "; break;
+ case 0x2010:
+ case 0x2011:
+ case 0x2012:
+ case 0x2013:
+ case 0x2014:
+ pStr = "-"; break;
+ case 0x2015:
+ pStr = "--"; break;
+ case 0x2016:
+ pStr = "||"; break;
+ case 0x2017:
+ pStr = "_"; break;
+ case 0x2018:
+ case 0x2019:
+ case 0x201B:
+ pStr = "\'"; break;
+ case 0x201A:
+ pStr = ","; break;
+ case 0x201C:
+ case 0x201D:
+ case 0x201E:
+ case 0x201F:
+ case 0x2033:
+ pStr = "\""; break;
+ case 0x2039:
+ pStr = "<"; break;
+ case 0x203A:
+ pStr = ">"; break;
+ case 0x203C:
+ pStr = "!!"; break;
+ case 0x203D:
+ pStr = "?"; break;
+ case 0x2044:
+ case 0x2215:
+ pStr = "/"; break;
+ case 0x2048:
+ pStr = "?!"; break;
+ case 0x2049:
+ pStr = "!?"; break;
+ case 0x2216:
+ pStr = "\\"; break;
+ case 0x2217:
+ pStr = "*"; break;
+ case 0x2236:
+ pStr = ":"; break;
+ case 0x2264:
+ pStr = "<="; break;
+ case 0x2265:
+ pStr = "<="; break;
+ case 0x2303:
+ pStr = "^"; break;
+ }
+
+ return pStr;
+}
+
+// -----------------------------------------------------------------------
+
+sal_UCS4 GetLocalizedChar( sal_UCS4 nChar, LanguageType eLang )
+{
+ // currently only conversion from ASCII digits is interesting
+ if( (nChar < '0') || ('9' < nChar) )
+ return nChar;
+
+ int nOffset;
+ // eLang & LANGUAGE_MASK_PRIMARY catches language independent of region.
+ // CAVEAT! To some like Mongolian MS assigned the same primary language
+ // although the script type is different!
+ switch( eLang & LANGUAGE_MASK_PRIMARY )
+ {
+ default:
+ nOffset = 0;
+ break;
+ case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0660 - '0'; // arabic-indic digits
+ break;
+ case LANGUAGE_FARSI & LANGUAGE_MASK_PRIMARY:
+ case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY:
+ case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //???
+ case LANGUAGE_SINDHI & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x06F0 - '0'; // eastern arabic-indic digits
+ break;
+ case LANGUAGE_BENGALI & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x09E6 - '0'; // bengali
+ break;
+ case LANGUAGE_HINDI & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0966 - '0'; // devanagari
+ break;
+ case LANGUAGE_AMHARIC_ETHIOPIA & LANGUAGE_MASK_PRIMARY:
+ case LANGUAGE_TIGRIGNA_ETHIOPIA & LANGUAGE_MASK_PRIMARY:
+ // TODO case:
+ nOffset = 0x1369 - '0'; // ethiopic
+ break;
+ case LANGUAGE_GUJARATI & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0AE6 - '0'; // gujarati
+ break;
+#ifdef LANGUAGE_GURMUKHI // TODO case:
+ case LANGUAGE_GURMUKHI & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0A66 - '0'; // gurmukhi
+ break;
+#endif
+ case LANGUAGE_KANNADA & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0CE6 - '0'; // kannada
+ break;
+ case LANGUAGE_KHMER & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x17E0 - '0'; // khmer
+ break;
+ case LANGUAGE_LAO & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0ED0 - '0'; // lao
+ break;
+ case LANGUAGE_MALAYALAM & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0D66 - '0'; // malayalam
+ break;
+ case LANGUAGE_MONGOLIAN & LANGUAGE_MASK_PRIMARY:
+ if (eLang == LANGUAGE_MONGOLIAN_MONGOLIAN)
+ nOffset = 0x1810 - '0'; // mongolian
+ else
+ nOffset = 0; // mongolian cyrillic
+ break;
+ case LANGUAGE_BURMESE & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x1040 - '0'; // myanmar
+ break;
+ case LANGUAGE_ORIYA & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0B66 - '0'; // oriya
+ break;
+ case LANGUAGE_TAMIL & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0BE7 - '0'; // tamil
+ break;
+ case LANGUAGE_TELUGU & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0C66 - '0'; // telugu
+ break;
+ case LANGUAGE_THAI & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0E50 - '0'; // thai
+ break;
+ case LANGUAGE_TIBETAN & LANGUAGE_MASK_PRIMARY:
+ nOffset = 0x0F20 - '0'; // tibetan
+ break;
+#if 0 // TODO: use language type for these digit substitutions?
+ // TODO case:
+ nOffset = 0x2776 - '0'; // dingbat circled
+ break;
+ // TODO case:
+ nOffset = 0x2070 - '0'; // superscript
+ break;
+ // TODO case:
+ nOffset = 0x2080 - '0'; // subscript
+ break;
+#endif
+ }
+
+ nChar += nOffset;
+ return nChar;
+}
+
+// -----------------------------------------------------------------------
+
+inline bool IsControlChar( sal_UCS4 cChar )
+{
+ // C0 control characters
+ if( (0x0001 <= cChar) && (cChar <= 0x001F) )
+ return true;
+ // formatting characters
+ if( (0x200E <= cChar) && (cChar <= 0x200F) )
+ return true;
+ if( (0x2028 <= cChar) && (cChar <= 0x202E) )
+ return true;
+ // deprecated formatting characters
+ if( (0x206A <= cChar) && (cChar <= 0x206F) )
+ return true;
+ if( (0x2060 == cChar) )
+ return true;
+ // byte order markers and invalid unicode
+ if( (cChar == 0xFEFF) || (cChar == 0xFFFE) || (cChar == 0xFFFF) )
+ return true;
+ return false;
+}
+
+// =======================================================================
+
+bool ImplLayoutRuns::AddPos( int nCharPos, bool bRTL )
+{
+ // check if charpos could extend current run
+ int nIndex = maRuns.size();
+ if( nIndex >= 2 )
+ {
+ int nRunPos0 = maRuns[ nIndex-2 ];
+ int nRunPos1 = maRuns[ nIndex-1 ];
+ if( ((nCharPos + bRTL) == nRunPos1)
+ && ((nRunPos0 > nRunPos1) == bRTL) )
+ {
+ // extend current run by new charpos
+ maRuns[ nIndex-1 ] = nCharPos + !bRTL;
+ return false;
+ }
+ // ignore new charpos when it is in current run
+ if( (nRunPos0 <= nCharPos) && (nCharPos < nRunPos1) )
+ return false;
+ if( (nRunPos1 <= nCharPos) && (nCharPos < nRunPos0) )
+ return false;
+ }
+
+ // else append a new run consisting of the new charpos
+ maRuns.push_back( nCharPos + (bRTL ? 1 : 0) );
+ maRuns.push_back( nCharPos + (bRTL ? 0 : 1) );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplLayoutRuns::AddRun( int nCharPos0, int nCharPos1, bool bRTL )
+{
+ if( nCharPos0 == nCharPos1 )
+ return false;
+
+ // swap if needed
+ if( bRTL == (nCharPos0 < nCharPos1) )
+ {
+ int nTemp = nCharPos0;
+ nCharPos0 = nCharPos1;
+ nCharPos1 = nTemp;
+ }
+
+ // append new run
+ maRuns.push_back( nCharPos0 );
+ maRuns.push_back( nCharPos1 );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplLayoutRuns::PosIsInRun( int nCharPos ) const
+{
+ if( mnRunIndex >= (int)maRuns.size() )
+ return false;
+
+ int nMinCharPos = maRuns[ mnRunIndex+0 ];
+ int nEndCharPos = maRuns[ mnRunIndex+1 ];
+ if( nMinCharPos > nEndCharPos ) // reversed in RTL case
+ {
+ int nTemp = nMinCharPos;
+ nMinCharPos = nEndCharPos;
+ nEndCharPos = nTemp;
+ }
+
+ if( nCharPos < nMinCharPos )
+ return false;
+ if( nCharPos >= nEndCharPos )
+ return false;
+ return true;
+}
+
+bool ImplLayoutRuns::PosIsInAnyRun( int nCharPos ) const
+{
+ bool bRet = false;
+ int nRunIndex = mnRunIndex;
+
+ ImplLayoutRuns *pThis = const_cast<ImplLayoutRuns*>(this);
+
+ pThis->ResetPos();
+
+ for (size_t i = 0; i < maRuns.size(); i+=2)
+ {
+ if( (bRet = PosIsInRun( nCharPos )) == true )
+ break;
+ pThis->NextRun();
+ }
+
+ pThis->mnRunIndex = nRunIndex;
+ return bRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+bool ImplLayoutRuns::GetNextPos( int* nCharPos, bool* bRightToLeft )
+{
+ // negative nCharPos => reset to first run
+ if( *nCharPos < 0 )
+ mnRunIndex = 0;
+
+ // return false when all runs completed
+ if( mnRunIndex >= (int)maRuns.size() )
+ return false;
+
+ int nRunPos0 = maRuns[ mnRunIndex+0 ];
+ int nRunPos1 = maRuns[ mnRunIndex+1 ];
+ *bRightToLeft = (nRunPos0 > nRunPos1);
+
+ if( *nCharPos < 0 )
+ {
+ // get first valid nCharPos in run
+ *nCharPos = nRunPos0;
+ }
+ else
+ {
+ // advance to next nCharPos for LTR case
+ if( !*bRightToLeft )
+ ++(*nCharPos);
+
+ // advance to next run if current run is completed
+ if( *nCharPos == nRunPos1 )
+ {
+ if( (mnRunIndex += 2) >= (int)maRuns.size() )
+ return false;
+ nRunPos0 = maRuns[ mnRunIndex+0 ];
+ nRunPos1 = maRuns[ mnRunIndex+1 ];
+ *bRightToLeft = (nRunPos0 > nRunPos1);
+ *nCharPos = nRunPos0;
+ }
+ }
+
+ // advance to next nCharPos for RTL case
+ if( *bRightToLeft )
+ --(*nCharPos);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplLayoutRuns::GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRightToLeft ) const
+{
+ if( mnRunIndex >= (int)maRuns.size() )
+ return false;
+
+ int nRunPos0 = maRuns[ mnRunIndex+0 ];
+ int nRunPos1 = maRuns[ mnRunIndex+1 ];
+ *bRightToLeft = (nRunPos1 < nRunPos0) ;
+ if( !*bRightToLeft )
+ {
+ *nMinRunPos = nRunPos0;
+ *nEndRunPos = nRunPos1;
+ }
+ else
+ {
+ *nMinRunPos = nRunPos1;
+ *nEndRunPos = nRunPos0;
+ }
+ return true;
+}
+
+// =======================================================================
+
+ImplLayoutArgs::ImplLayoutArgs( const xub_Unicode* pStr, int nLen,
+ int nMinCharPos, int nEndCharPos, int nFlags )
+:
+ mnFlags( nFlags ),
+ mnLength( nLen ),
+ mnMinCharPos( nMinCharPos ),
+ mnEndCharPos( nEndCharPos ),
+ mpStr( pStr ),
+ mpDXArray( NULL ),
+ mnLayoutWidth( 0 ),
+ mnOrientation( 0 )
+{
+ if( mnFlags & SAL_LAYOUT_BIDI_STRONG )
+ {
+ // handle strong BiDi mode
+
+ // do not bother to BiDi analyze strong LTR/RTL
+ // TODO: can we assume these strings do not have unicode control chars?
+ // if not remove the control characters from the runs
+ bool bRTL = ((mnFlags & SAL_LAYOUT_BIDI_RTL) != 0);
+ AddRun( mnMinCharPos, mnEndCharPos, bRTL );
+ }
+ else
+ {
+ // handle weak BiDi mode
+
+ UBiDiLevel nLevel = UBIDI_DEFAULT_LTR;
+ if( mnFlags & SAL_LAYOUT_BIDI_RTL )
+ nLevel = UBIDI_DEFAULT_RTL;
+
+ // prepare substring for BiDi analysis
+ // TODO: reuse allocated pParaBidi
+ UErrorCode rcI18n = U_ZERO_ERROR;
+ UBiDi* pParaBidi = ubidi_openSized( mnLength, 0, &rcI18n );
+ if( !pParaBidi )
+ return;
+ ubidi_setPara( pParaBidi, reinterpret_cast<const UChar *>(mpStr), mnLength, nLevel, NULL, &rcI18n ); // UChar != sal_Unicode in MinGW
+
+ UBiDi* pLineBidi = pParaBidi;
+ int nSubLength = mnEndCharPos - mnMinCharPos;
+ if( nSubLength != mnLength )
+ {
+ pLineBidi = ubidi_openSized( nSubLength, 0, &rcI18n );
+ ubidi_setLine( pParaBidi, mnMinCharPos, mnEndCharPos, pLineBidi, &rcI18n );
+ }
+
+ // run BiDi algorithm
+ const int nRunCount = ubidi_countRuns( pLineBidi, &rcI18n );
+ //maRuns.resize( 2 * nRunCount );
+ for( int i = 0; i < nRunCount; ++i )
+ {
+ int32_t nMinPos, nLength;
+ const UBiDiDirection nDir = ubidi_getVisualRun( pLineBidi, i, &nMinPos, &nLength );
+ const int nPos0 = nMinPos + mnMinCharPos;
+ const int nPos1 = nPos0 + nLength;
+
+ const bool bRTL = (nDir == UBIDI_RTL);
+ AddRun( nPos0, nPos1, bRTL );
+ }
+
+ // cleanup BiDi engine
+ if( pLineBidi != pParaBidi )
+ ubidi_close( pLineBidi );
+ ubidi_close( pParaBidi );
+ }
+
+ // prepare calls to GetNextPos/GetNextRun
+ maRuns.ResetPos();
+}
+
+// -----------------------------------------------------------------------
+
+// add a run after splitting it up to get rid of control chars
+void ImplLayoutArgs::AddRun( int nCharPos0, int nCharPos1, bool bRTL )
+{
+ DBG_ASSERT( nCharPos0 <= nCharPos1, "ImplLayoutArgs::AddRun() nCharPos0>=nCharPos1" );
+
+ // remove control characters from runs by splitting them up
+ if( !bRTL )
+ {
+ for( int i = nCharPos0; i < nCharPos1; ++i )
+ if( IsControlChar( mpStr[i] ) )
+ {
+ // add run until control char
+ maRuns.AddRun( nCharPos0, i, bRTL );
+ nCharPos0 = i + 1;
+ }
+ }
+ else
+ {
+ for( int i = nCharPos1; --i >= nCharPos0; )
+ if( IsControlChar( mpStr[i] ) )
+ {
+ // add run until control char
+ maRuns.AddRun( i+1, nCharPos1, bRTL );
+ nCharPos1 = i;
+ }
+ }
+
+ // add remainder of run
+ maRuns.AddRun( nCharPos0, nCharPos1, bRTL );
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplLayoutArgs::PrepareFallback()
+{
+ // short circuit if no fallback is needed
+ if( maReruns.IsEmpty() )
+ {
+ maRuns.Clear();
+ return false;
+ }
+
+ // convert the fallback requests to layout requests
+ bool bRTL;
+ int nMin, nEnd;
+
+ // get the individual fallback requests
+ typedef std::vector<int> IntVector;
+ IntVector aPosVector;
+ aPosVector.reserve( mnLength );
+ maReruns.ResetPos();
+ for(; maReruns.GetRun( &nMin, &nEnd, &bRTL ); maReruns.NextRun() )
+ for( int i = nMin; i < nEnd; ++i )
+ aPosVector.push_back( i );
+ maReruns.Clear();
+
+ // sort the individual fallback requests
+ std::sort( aPosVector.begin(), aPosVector.end() );
+
+ // adjust fallback runs to have the same order and limits of the original runs
+ ImplLayoutRuns aNewRuns;
+ maRuns.ResetPos();
+ for(; maRuns.GetRun( &nMin, &nEnd, &bRTL ); maRuns.NextRun() )
+ {
+ if( !bRTL) {
+ IntVector::const_iterator it = std::lower_bound( aPosVector.begin(), aPosVector.end(), nMin );
+ for(; (it != aPosVector.end()) && (*it < nEnd); ++it )
+ aNewRuns.AddPos( *it, bRTL );
+ } else {
+ IntVector::const_iterator it = std::upper_bound( aPosVector.begin(), aPosVector.end(), nEnd );
+ while( (it != aPosVector.begin()) && (*--it >= nMin) )
+ aNewRuns.AddPos( *it, bRTL );
+ }
+ }
+
+ maRuns = aNewRuns; // TODO: use vector<>::swap()
+ maRuns.ResetPos();
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplLayoutArgs::GetNextRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL )
+{
+ bool bValid = maRuns.GetRun( nMinRunPos, nEndRunPos, bRTL );
+ maRuns.NextRun();
+ return bValid;
+}
+
+// =======================================================================
+
+SalLayout::SalLayout()
+: mnMinCharPos( -1 ),
+ mnEndCharPos( -1 ),
+ mnLayoutFlags( 0 ),
+ mnUnitsPerPixel( 1 ),
+ mnOrientation( 0 ),
+ mnRefCount( 1 ),
+ maDrawOffset( 0, 0 )
+{}
+
+// -----------------------------------------------------------------------
+
+SalLayout::~SalLayout()
+{}
+
+// -----------------------------------------------------------------------
+
+void SalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ mnMinCharPos = rArgs.mnMinCharPos;
+ mnEndCharPos = rArgs.mnEndCharPos;
+ mnLayoutFlags = rArgs.mnFlags;
+ mnOrientation = rArgs.mnOrientation;
+}
+
+// -----------------------------------------------------------------------
+
+void SalLayout::Reference() const
+{
+ // TODO: protect when multiple threads can access this
+ ++mnRefCount;
+}
+
+// -----------------------------------------------------------------------
+
+void SalLayout::Release() const
+{
+ // TODO: protect when multiple threads can access this
+ if( --mnRefCount > 0 )
+ return;
+ // const_cast because some compilers violate ANSI C++ spec
+ delete const_cast<SalLayout*>(this);
+}
+
+// -----------------------------------------------------------------------
+
+Point SalLayout::GetDrawPosition( const Point& rRelative ) const
+{
+ Point aPos = maDrawBase;
+ Point aOfs = rRelative + maDrawOffset;
+
+ if( mnOrientation == 0 )
+ aPos += aOfs;
+ else
+ {
+ // cache trigonometric results
+ static int nOldOrientation = 0;
+ static double fCos = 1.0, fSin = 0.0;
+ if( nOldOrientation != mnOrientation )
+ {
+ nOldOrientation = mnOrientation;
+ double fRad = mnOrientation * (M_PI / 1800.0);
+ fCos = cos( fRad );
+ fSin = sin( fRad );
+ }
+
+ double fX = aOfs.X();
+ double fY = aOfs.Y();
+ long nX = static_cast<long>( +fCos * fX + fSin * fY );
+ long nY = static_cast<long>( +fCos * fY - fSin * fX );
+ aPos += Point( nX, nY );
+ }
+
+ return aPos;
+}
+
+// -----------------------------------------------------------------------
+
+// returns asian kerning values in quarter of character width units
+// to enable automatic halfwidth substitution for fullwidth punctuation
+// return value is negative for l, positive for r, zero for neutral
+
+// If the range doesn't match in 0x3000 and 0x30FB, please change
+// also ImplCalcKerning.
+
+int SalLayout::CalcAsianKerning( sal_UCS4 c, bool bLeft, bool /*TODO:? bVertical*/ )
+{
+ // http://www.asahi-net.or.jp/~sd5a-ucd/freetexts/jis/x4051/1995/appendix.html
+ static signed char nTable[0x30] =
+ {
+ 0, -2, -2, 0, 0, 0, 0, 0, +2, -2, +2, -2, +2, -2, +2, -2,
+ +2, -2, 0, 0, +2, -2, +2, -2, 0, 0, 0, 0, 0, +2, -2, -2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, +2, +2, -2, -2
+ };
+
+ int nResult = 0;
+ if( (c >= 0x3000) && (c < 0x3030) )
+ nResult = nTable[ c - 0x3000 ];
+ else switch( c )
+ {
+#if 0 // TODO: enable it for real-fixed-width fonts?
+ case ':': case ';': case '!':
+ if( !bVertical )
+ nResult = bLeft ? -1 : +1; // 25% left and right
+ break;
+#endif
+ case 0x30FB:
+ nResult = bLeft ? -1 : +1; // 25% left/right/top/bottom
+ break;
+ case 0x2019: case 0x201D:
+ case 0xFF01: case 0xFF09: case 0xFF0C:
+ case 0xFF1A: case 0xFF1B:
+ nResult = -2;
+ break;
+ case 0x2018: case 0x201C:
+ case 0xFF08:
+ nResult = +2;
+ break;
+ default:
+ break;
+ }
+
+ return nResult;
+}
+
+// -----------------------------------------------------------------------
+
+bool SalLayout::GetOutline( SalGraphics& rSalGraphics,
+ ::basegfx::B2DPolyPolygonVector& rVector ) const
+{
+ bool bAllOk = true;
+ bool bOneOk = false;
+
+ Point aPos;
+ ::basegfx::B2DPolyPolygon aGlyphOutline;
+ for( int nStart = 0;;)
+ {
+ sal_GlyphId nLGlyph;
+ if( !GetNextGlyphs( 1, &nLGlyph, aPos, nStart ) )
+ break;
+
+ // get outline of individual glyph, ignoring "empty" glyphs
+ bool bSuccess = rSalGraphics.GetGlyphOutline( nLGlyph, aGlyphOutline );
+ bAllOk &= bSuccess;
+ bOneOk |= bSuccess;
+ // only add non-empty outlines
+ if( bSuccess && (aGlyphOutline.count() > 0) )
+ {
+ if( aPos.X() || aPos.Y() )
+ {
+ aGlyphOutline.transform(basegfx::tools::createTranslateB2DHomMatrix(aPos.X(), aPos.Y()));
+ }
+
+ // insert outline at correct position
+ rVector.push_back( aGlyphOutline );
+ }
+ }
+
+ return (bAllOk & bOneOk);
+}
+
+// -----------------------------------------------------------------------
+
+bool SalLayout::GetBoundRect( SalGraphics& rSalGraphics, Rectangle& rRect ) const
+{
+ bool bRet = false;
+ rRect.SetEmpty();
+
+ Point aPos;
+ Rectangle aRectangle;
+ for( int nStart = 0;;)
+ {
+ sal_GlyphId nLGlyph;
+ if( !GetNextGlyphs( 1, &nLGlyph, aPos, nStart ) )
+ break;
+
+ // get bounding rectangle of individual glyph
+ if( rSalGraphics.GetGlyphBoundRect( nLGlyph, aRectangle ) )
+ {
+ // merge rectangle
+ aRectangle += aPos;
+ rRect.Union( aRectangle );
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+bool SalLayout::IsSpacingGlyph( sal_GlyphId nGlyph ) const
+{
+ bool bRet = false;
+ if( nGlyph & GF_ISCHAR )
+ {
+ long nChar = nGlyph & GF_IDXMASK;
+ bRet = (nChar <= 0x0020) // blank
+ //|| (nChar == 0x00A0) // non breaking space
+ || (nChar >= 0x2000 && nChar <= 0x200F) // whitespace
+ || (nChar == 0x3000); // ideographic space
+ }
+ else
+ bRet = ((nGlyph & GF_IDXMASK) == 3);
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontData* SalLayout::GetFallbackFontData( sal_GlyphId /*nGlyphId*/ ) const
+{
+#if 0
+ int nFallbackLevel = (nGlyphId & GF_FONTMASK) >> GF_FONTSHIFT
+ assert( nFallbackLevel == 0 );
+#endif
+ return NULL;
+}
+
+// =======================================================================
+
+GenericSalLayout::GenericSalLayout()
+: mpGlyphItems(0),
+ mnGlyphCount(0),
+ mnGlyphCapacity(0)
+{}
+
+// -----------------------------------------------------------------------
+
+GenericSalLayout::~GenericSalLayout()
+{
+ delete[] mpGlyphItems;
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::AppendGlyph( const GlyphItem& rGlyphItem )
+{
+ // TODO: use std::list<GlyphItem>
+ if( mnGlyphCount >= mnGlyphCapacity )
+ {
+ mnGlyphCapacity += 16 + 3 * mnGlyphCount;
+ GlyphItem* pNewGI = new GlyphItem[ mnGlyphCapacity ];
+ if( mpGlyphItems )
+ {
+ for( int i = 0; i < mnGlyphCount; ++i )
+ pNewGI[ i ] = mpGlyphItems[ i ];
+ delete[] mpGlyphItems;
+ }
+ mpGlyphItems = pNewGI;
+ }
+
+ mpGlyphItems[ mnGlyphCount++ ] = rGlyphItem;
+}
+
+// -----------------------------------------------------------------------
+
+bool GenericSalLayout::GetCharWidths( sal_Int32* pCharWidths ) const
+{
+ // initialize character extents buffer
+ int nCharCount = mnEndCharPos - mnMinCharPos;
+ for( int n = 0; n < nCharCount; ++n )
+ pCharWidths[n] = 0;
+
+ // determine cluster extents
+ const GlyphItem* const pEnd = mpGlyphItems + mnGlyphCount;
+ for( const GlyphItem* pG = mpGlyphItems; pG < pEnd; ++pG )
+ {
+ // use cluster start to get char index
+ if( !pG->IsClusterStart() )
+ continue;
+
+ int n = pG->mnCharPos;
+ if( n >= mnEndCharPos )
+ continue;
+ n -= mnMinCharPos;
+ if( n < 0 )
+ continue;
+
+ // left glyph in cluster defines default extent
+ long nXPosMin = pG->maLinearPos.X();
+ long nXPosMax = nXPosMin + pG->mnNewWidth;
+
+ // calculate right x-position for this glyph cluster
+ // break if no more glyphs in layout
+ // break at next glyph cluster start
+ while( (pG+1 < pEnd) && !pG[1].IsClusterStart() )
+ {
+ // advance to next glyph in cluster
+ ++pG;
+
+ if( pG->IsDiacritic() )
+ continue; // ignore diacritics
+ // get leftmost x-extent of this glyph
+ long nXPos = pG->maLinearPos.X();
+ if( nXPosMin > nXPos )
+ nXPosMin = nXPos;
+
+ // get rightmost x-extent of this glyph
+ nXPos += pG->mnNewWidth;
+ if( nXPosMax < nXPos )
+ nXPosMax = nXPos;
+ }
+
+ // when the current cluster overlaps with the next one assume
+ // rightmost cluster edge is the leftmost edge of next cluster
+ // for clusters that do not have x-sorted glyphs
+ // TODO: avoid recalculation of left bound in next cluster iteration
+ for( const GlyphItem* pN = pG; ++pN < pEnd; )
+ {
+ if( pN->IsClusterStart() )
+ break;
+ if( pN->IsDiacritic() )
+ continue; // ignore diacritics
+ if( nXPosMax > pN->maLinearPos.X() )
+ nXPosMax = pN->maLinearPos.X();
+ }
+ if( nXPosMax < nXPosMin )
+ nXPosMin = nXPosMax = 0;
+
+ // character width is sum of glyph cluster widths
+ pCharWidths[n] += nXPosMax - nXPosMin;
+ }
+
+ // TODO: distribute the cluster width proportionally to the characters
+ // clusters (e.g. ligatures) correspond to more than one char index,
+ // so some character widths are still uninitialized. This is solved
+ // by setting the first charwidth of the cluster to the cluster width
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+long GenericSalLayout::FillDXArray( sal_Int32* pCharWidths ) const
+{
+ if( pCharWidths )
+ if( !GetCharWidths( pCharWidths ) )
+ return 0;
+
+ long nWidth = GetTextWidth();
+ return nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+// the text width is the maximum logical extent of all glyphs
+long GenericSalLayout::GetTextWidth() const
+{
+ if( mnGlyphCount <= 0 )
+ return 0;
+
+ // initialize the extent
+ long nMinPos = 0;
+ long nMaxPos = 0;
+
+ const GlyphItem* pG = mpGlyphItems;
+ for( int i = mnGlyphCount; --i >= 0; ++pG )
+ {
+ // update the text extent with the glyph extent
+ long nXPos = pG->maLinearPos.X();
+ if( nMinPos > nXPos )
+ nMinPos = nXPos;
+ nXPos += pG->mnNewWidth;
+ if( nMaxPos < nXPos )
+ nMaxPos = nXPos;
+ }
+
+ long nWidth = nMaxPos - nMinPos;
+ return nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ SalLayout::AdjustLayout( rArgs );
+
+ if( rArgs.mpDXArray )
+ ApplyDXArray( rArgs );
+ else if( rArgs.mnLayoutWidth )
+ Justify( rArgs.mnLayoutWidth );
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs )
+{
+ if( mnGlyphCount <= 0 )
+ return;
+
+ // determine cluster boundaries and x base offset
+ const int nCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
+ int* pLogCluster = (int*)alloca( nCharCount * sizeof(int) );
+ int i, n;
+ long nBasePointX = -1;
+ if( mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK )
+ nBasePointX = 0;
+ for( i = 0; i < nCharCount; ++i )
+ pLogCluster[ i ] = -1;
+ GlyphItem* pG = mpGlyphItems;
+ for( i = 0; i < mnGlyphCount; ++i, ++pG )
+ {
+ n = pG->mnCharPos - rArgs.mnMinCharPos;
+ if( (n < 0) || (nCharCount <= n) )
+ continue;
+ if( pLogCluster[ n ] < 0 )
+ pLogCluster[ n ] = i;
+ if( nBasePointX < 0 )
+ nBasePointX = pG->maLinearPos.X();
+ }
+ // retarget unresolved pLogCluster[n] to a glyph inside the cluster
+ // TODO: better do it while the deleted-glyph markers are still there
+ for( n = 0; n < nCharCount; ++n )
+ if( (i = pLogCluster[0]) >= 0 )
+ break;
+ if( n >= nCharCount )
+ return;
+ for( n = 0; n < nCharCount; ++n )
+ {
+ if( pLogCluster[ n ] < 0 )
+ pLogCluster[ n ] = i;
+ else
+ i = pLogCluster[ n ];
+ }
+
+ // calculate adjusted cluster widths
+ sal_Int32* pNewGlyphWidths = (sal_Int32*)alloca( mnGlyphCount * sizeof(long) );
+ for( i = 0; i < mnGlyphCount; ++i )
+ pNewGlyphWidths[ i ] = 0;
+
+ bool bRTL;
+ for( int nCharPos = i = -1; rArgs.GetNextPos( &nCharPos, &bRTL ); )
+ {
+ n = nCharPos - rArgs.mnMinCharPos;
+ if( (n < 0) || (nCharCount <= n) ) continue;
+
+ if( pLogCluster[ n ] >= 0 )
+ i = pLogCluster[ n ];
+ if( i >= 0 )
+ {
+ long nDelta = rArgs.mpDXArray[ n ] ;
+ if( n > 0 )
+ nDelta -= rArgs.mpDXArray[ n-1 ];
+ pNewGlyphWidths[ i ] += nDelta * mnUnitsPerPixel;
+ }
+ }
+
+ // move cluster positions using the adjusted widths
+ long nDelta = 0;
+ long nNewPos = 0;
+ pG = mpGlyphItems;
+ for( i = 0; i < mnGlyphCount; ++i, ++pG )
+ {
+ if( pG->IsClusterStart() )
+ {
+ // calculate original and adjusted cluster width
+ int nOldClusterWidth = pG->mnNewWidth;
+ int nNewClusterWidth = pNewGlyphWidths[i];
+ GlyphItem* pClusterG = pG + 1;
+ for( int j = i; ++j < mnGlyphCount; ++pClusterG )
+ {
+ if( pClusterG->IsClusterStart() )
+ break;
+ if( !pClusterG->IsDiacritic() ) // #i99367# ignore diacritics
+ nOldClusterWidth += pClusterG->mnNewWidth;
+ nNewClusterWidth += pNewGlyphWidths[j];
+ }
+ const int nDiff = nNewClusterWidth - nOldClusterWidth;
+
+ // adjust cluster glyph widths and positions
+ nDelta = nBasePointX + (nNewPos - pG->maLinearPos.X());
+ if( !pG->IsRTLGlyph() )
+ {
+ // for LTR case extend rightmost glyph in cluster
+ pClusterG[-1].mnNewWidth += nDiff;
+ }
+ else
+ {
+ // right align cluster in new space for RTL case
+ pG->mnNewWidth += nDiff;
+ nDelta += nDiff;
+ }
+
+ nNewPos += nNewClusterWidth;
+ }
+
+ pG->maLinearPos.X() += nDelta;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::Justify( long nNewWidth )
+{
+ nNewWidth *= mnUnitsPerPixel;
+ int nOldWidth = GetTextWidth();
+ if( !nOldWidth || nNewWidth==nOldWidth )
+ return;
+
+ // find rightmost glyph, it won't get stretched
+ GlyphItem* pGRight = mpGlyphItems + mnGlyphCount - 1;
+
+ // count stretchable glyphs
+ GlyphItem* pG;
+ int nStretchable = 0;
+ int nMaxGlyphWidth = 0;
+ for( pG = mpGlyphItems; pG < pGRight; ++pG )
+ {
+ if( !pG->IsDiacritic() )
+ ++nStretchable;
+ if( nMaxGlyphWidth < pG->mnOrigWidth )
+ nMaxGlyphWidth = pG->mnOrigWidth;
+ }
+
+ // move rightmost glyph to requested position
+ nOldWidth -= pGRight->mnOrigWidth;
+ if( nOldWidth <= 0 )
+ return;
+ if( nNewWidth < nMaxGlyphWidth)
+ nNewWidth = nMaxGlyphWidth;
+ nNewWidth -= pGRight->mnOrigWidth;
+ pGRight->maLinearPos.X() = maBasePoint.X() + nNewWidth;
+
+ // justify glyph widths and positions
+ int nDiffWidth = nNewWidth - nOldWidth;
+ if( nDiffWidth >= 0) // expanded case
+ {
+ // expand width by distributing space between glyphs evenly
+ int nDeltaSum = 0;
+ for( pG = mpGlyphItems; pG < pGRight; ++pG )
+ {
+ // move glyph to justified position
+ pG->maLinearPos.X() += nDeltaSum;
+
+ // do not stretch non-stretchable glyphs
+ if( pG->IsDiacritic() || (nStretchable <= 0) )
+ continue;
+
+ // distribute extra space equally to stretchable glyphs
+ int nDeltaWidth = nDiffWidth / nStretchable--;
+ nDiffWidth -= nDeltaWidth;
+ pG->mnNewWidth += nDeltaWidth;
+ nDeltaSum += nDeltaWidth;
+ }
+ }
+ else // condensed case
+ {
+ // squeeze width by moving glyphs proportionally
+ double fSqueeze = (double)nNewWidth / nOldWidth;
+ for( pG = mpGlyphItems; ++pG < pGRight;)
+ {
+ int nX = pG->maLinearPos.X() - maBasePoint.X();
+ nX = (int)(nX * fSqueeze);
+ pG->maLinearPos.X() = nX + maBasePoint.X();
+ }
+ // adjust glyph widths to new positions
+ for( pG = mpGlyphItems; pG < pGRight; ++pG )
+ pG->mnNewWidth = pG[1].maLinearPos.X() - pG[0].maLinearPos.X();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::ApplyAsianKerning( const sal_Unicode* pStr, int nLength )
+{
+ long nOffset = 0;
+
+ GlyphItem* pGEnd = mpGlyphItems + mnGlyphCount;
+ for( GlyphItem* pG = mpGlyphItems; pG < pGEnd; ++pG )
+ {
+ const int n = pG->mnCharPos;
+ if( n < nLength - 1)
+ {
+ // ignore code ranges that are not affected by asian punctuation compression
+ const sal_Unicode cHere = pStr[n];
+ if( ((0x3000 != (cHere & 0xFF00)) && (0x2010 != (cHere & 0xFFF0))) || (0xFF00 != (cHere & 0xFF00)) )
+ continue;
+ const sal_Unicode cNext = pStr[n+1];
+ if( ((0x3000 != (cNext & 0xFF00)) && (0x2010 != (cNext & 0xFFF0))) || (0xFF00 != (cNext & 0xFF00)) )
+ continue;
+
+ // calculate compression values
+ const bool bVertical = false;
+ long nKernFirst = +CalcAsianKerning( cHere, true, bVertical );
+ long nKernNext = -CalcAsianKerning( cNext, false, bVertical );
+
+ // apply punctuation compression to logical glyph widths
+ long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
+ if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
+ {
+ int nGlyphWidth = pG->mnOrigWidth;
+ nDelta = (nDelta * nGlyphWidth + 2) / 4;
+ if( pG+1 == pGEnd )
+ pG->mnNewWidth += nDelta;
+ nOffset += nDelta;
+ }
+ }
+
+ // adjust the glyph positions to the new glyph widths
+ if( pG+1 != pGEnd )
+ pG->maLinearPos.X() += nOffset;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::KashidaJustify( long nKashidaIndex, int nKashidaWidth )
+{
+ // TODO: reimplement method when container type for GlyphItems changes
+
+ // skip if the kashida glyph in the font looks suspicious
+ if( nKashidaWidth <= 0 )
+ return;
+
+ // calculate max number of needed kashidas
+ const GlyphItem* pG1 = mpGlyphItems;
+ int nKashidaCount = 0, i;
+ for( i = 0; i < mnGlyphCount; ++i, ++pG1 )
+ {
+ // only inject kashidas in RTL contexts
+ if( !pG1->IsRTLGlyph() )
+ continue;
+ // no kashida-injection for blank justified expansion either
+ if( IsSpacingGlyph( pG1->mnGlyphIndex ) )
+ continue;
+
+ // calculate gap, ignore if too small
+ const int nGapWidth = pG1->mnNewWidth - pG1->mnOrigWidth;
+ // worst case is one kashida even for mini-gaps
+ if( 3 * nGapWidth >= nKashidaWidth )
+ nKashidaCount += 1 + (nGapWidth / nKashidaWidth);
+ }
+
+ if( !nKashidaCount )
+ return;
+
+ // reallocate glyph array for additional kashidas
+ // TODO: reuse array if additional glyphs would fit
+ mnGlyphCapacity = mnGlyphCount + nKashidaCount;
+ GlyphItem* pNewGlyphItems = new GlyphItem[ mnGlyphCapacity ];
+ GlyphItem* pG2 = pNewGlyphItems;
+ pG1 = mpGlyphItems;
+ for( i = mnGlyphCount; --i >= 0; ++pG1, ++pG2 )
+ {
+ // default action is to copy array element
+ *pG2 = *pG1;
+
+ // only inject kashida in RTL contexts
+ if( !pG1->IsRTLGlyph() )
+ continue;
+ // no kashida-injection for blank justified expansion either
+ if( IsSpacingGlyph( pG1->mnGlyphIndex ) )
+ continue;
+
+ // calculate gap, skip if too small
+ int nGapWidth = pG1->mnNewWidth - pG1->mnOrigWidth;
+ if( 3*nGapWidth < nKashidaWidth )
+ continue;
+
+ // fill gap with kashidas
+ nKashidaCount = 0;
+ Point aPos = pG1->maLinearPos;
+ aPos.X() -= nGapWidth; // cluster is already right aligned
+ for(; nGapWidth > 0; nGapWidth -= nKashidaWidth, ++nKashidaCount )
+ {
+ *(pG2++) = GlyphItem( pG1->mnCharPos, nKashidaIndex, aPos,
+ GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaWidth );
+ aPos.X() += nKashidaWidth;
+ }
+
+ // fixup rightmost kashida for gap remainder
+ if( nGapWidth < 0 )
+ {
+ aPos.X() += nGapWidth;
+ if( nKashidaCount <= 1 )
+ nGapWidth /= 2; // for small gap move kashida to middle
+ pG2[-1].mnNewWidth += nGapWidth; // adjust kashida width to gap width
+ pG2[-1].maLinearPos.X() += nGapWidth;
+ }
+
+ // when kashidas were inserted move the original cluster
+ // to the right and shrink it to it's original width
+ *pG2 = *pG1;
+ pG2->maLinearPos.X() = aPos.X();
+ pG2->mnNewWidth = pG2->mnOrigWidth;
+ }
+
+ // use the new glyph array
+ DBG_ASSERT( mnGlyphCapacity >= pG2-pNewGlyphItems, "KashidaJustify overflow" );
+ delete[] mpGlyphItems;
+ mpGlyphItems = pNewGlyphItems;
+ mnGlyphCount = pG2 - pNewGlyphItems;
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const
+{
+ // initialize result array
+ long nXPos = -1;
+ int i;
+ for( i = 0; i < nMaxIndex; ++i )
+ pCaretXArray[ i ] = nXPos;
+
+ // calculate caret positions using glyph array
+ const GlyphItem* pG = mpGlyphItems;
+ for( i = mnGlyphCount; --i >= 0; ++pG )
+ {
+ nXPos = pG->maLinearPos.X();
+ long nXRight = nXPos + pG->mnOrigWidth;
+ int n = pG->mnCharPos;
+ int nCurrIdx = 2 * (n - mnMinCharPos);
+ if( !pG->IsRTLGlyph() )
+ {
+ // normal positions for LTR case
+ pCaretXArray[ nCurrIdx ] = nXPos;
+ pCaretXArray[ nCurrIdx+1 ] = nXRight;
+ }
+ else
+ {
+ // reverse positions for RTL case
+ pCaretXArray[ nCurrIdx ] = nXRight;
+ pCaretXArray[ nCurrIdx+1 ] = nXPos;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int GenericSalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ int nCharCapacity = mnEndCharPos - mnMinCharPos;
+ sal_Int32* pCharWidths = (sal_Int32*)alloca( nCharCapacity * sizeof(sal_Int32) );
+ if( !GetCharWidths( pCharWidths ) )
+ return STRING_LEN;
+
+ long nWidth = 0;
+ for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
+ {
+ nWidth += pCharWidths[ i - mnMinCharPos ] * nFactor;
+ if( nWidth >= nMaxWidth )
+ return i;
+ nWidth += nCharExtra;
+ }
+
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
+
+int GenericSalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
+ int& nStart, sal_Int32* pGlyphAdvAry, int* pCharPosAry ) const
+{
+ const GlyphItem* pG = mpGlyphItems + nStart;
+
+ // find next glyph in substring
+ for(; nStart < mnGlyphCount; ++nStart, ++pG )
+ {
+ int n = pG->mnCharPos;
+ if( (mnMinCharPos <= n) && (n < mnEndCharPos) )
+ break;
+ }
+
+ // return zero if no more glyph found
+ if( nStart >= mnGlyphCount )
+ return 0;
+
+ // calculate absolute position in pixel units
+ Point aRelativePos = pG->maLinearPos - maBasePoint;
+
+ // find more glyphs which can be merged into one drawing instruction
+ int nCount = 0;
+ long nYPos = pG->maLinearPos.Y();
+ long nOldFlags = pG->mnGlyphIndex;
+ for(;;)
+ {
+ // update return data with glyph info
+ ++nCount;
+ *(pGlyphs++) = pG->mnGlyphIndex;
+ if( pCharPosAry )
+ *(pCharPosAry++) = pG->mnCharPos;
+ if( pGlyphAdvAry )
+ *pGlyphAdvAry = pG->mnNewWidth;
+
+ // break at end of glyph list
+ if( ++nStart >= mnGlyphCount )
+ break;
+ // break when enough glyphs
+ if( nCount >= nLen )
+ break;
+
+ long nGlyphAdvance = pG[1].maLinearPos.X() - pG->maLinearPos.X();
+ if( pGlyphAdvAry )
+ {
+ // override default advance width with correct value
+ *(pGlyphAdvAry++) = nGlyphAdvance;
+ }
+ else
+ {
+ // stop when next x-position is unexpected
+ if( pG->mnOrigWidth != nGlyphAdvance )
+ break;
+ }
+
+ // advance to next glyph
+ ++pG;
+
+ // stop when next y-position is unexpected
+ if( nYPos != pG->maLinearPos.Y() )
+ break;
+
+ // stop when no longer in string
+ int n = pG->mnCharPos;
+ if( (n < mnMinCharPos) || (mnEndCharPos <= n) )
+ break;
+
+ // stop when glyph flags change
+ if( (nOldFlags ^ pG->mnGlyphIndex) & GF_FLAGMASK )
+ break;
+
+ nOldFlags = pG->mnGlyphIndex; // &GF_FLAGMASK not needed for test above
+ }
+
+ aRelativePos.X() /= mnUnitsPerPixel;
+ aRelativePos.Y() /= mnUnitsPerPixel;
+ rPos = GetDrawPosition( aRelativePos );
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::MoveGlyph( int nStart, long nNewXPos )
+{
+ if( nStart >= mnGlyphCount )
+ return;
+
+ GlyphItem* pG = mpGlyphItems + nStart;
+ // the nNewXPos argument determines the new cell position
+ // as RTL-glyphs are right justified in their cell
+ // the cell position needs to be adjusted to the glyph position
+ if( pG->IsRTLGlyph() )
+ nNewXPos += pG->mnNewWidth - pG->mnOrigWidth;
+ // calculate the x-offset to the old position
+ long nXDelta = nNewXPos - pG->maLinearPos.X();
+ // adjust all following glyph positions if needed
+ if( nXDelta != 0 )
+ {
+ GlyphItem* const pGEnd = mpGlyphItems + mnGlyphCount;
+ for(; pG < pGEnd; ++pG )
+ pG->maLinearPos.X() += nXDelta;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::DropGlyph( int nStart )
+{
+ if( nStart >= mnGlyphCount )
+ return;
+ GlyphItem* pG = mpGlyphItems + nStart;
+ pG->mnGlyphIndex = GF_DROPPED;
+ pG->mnCharPos = -1;
+}
+
+// -----------------------------------------------------------------------
+
+void GenericSalLayout::Simplify( bool bIsBase )
+{
+ const sal_GlyphId nDropMarker = bIsBase ? GF_DROPPED : 0;
+
+ // remove dropped glyphs inplace
+ GlyphItem* pGDst = mpGlyphItems;
+ const GlyphItem* pGSrc = mpGlyphItems;
+ const GlyphItem* pGEnd = mpGlyphItems + mnGlyphCount;
+ for(; pGSrc < pGEnd; ++pGSrc )
+ {
+ if( pGSrc->mnGlyphIndex == nDropMarker )
+ continue;
+ if( pGDst != pGSrc )
+ *pGDst = *pGSrc;
+ ++pGDst;
+ }
+ mnGlyphCount = pGDst - mpGlyphItems;
+}
+
+// -----------------------------------------------------------------------
+
+// make sure GlyphItems are sorted left to right
+void GenericSalLayout::SortGlyphItems()
+{
+ // move cluster components behind their cluster start (especially for RTL)
+ // using insertion sort because the glyph items are "almost sorted"
+ const GlyphItem* const pGEnd = mpGlyphItems + mnGlyphCount;
+ for( GlyphItem* pG = mpGlyphItems; pG < pGEnd; ++pG )
+ {
+ // find a cluster starting with a diacritic
+ if( !pG->IsDiacritic() )
+ continue;
+ if( !pG->IsClusterStart() )
+ continue;
+ for( GlyphItem* pBaseGlyph = pG; ++pBaseGlyph < pGEnd; )
+ {
+ // find the base glyph matching to the misplaced diacritic
+ if( pBaseGlyph->IsClusterStart() )
+ break;
+ if( pBaseGlyph->IsDiacritic() )
+ continue;
+
+ // found the matching base glyph
+ // => this base glyph becomes the new cluster start
+ const GlyphItem aDiacritic = *pG;
+ *pG = *pBaseGlyph;
+ *pBaseGlyph = aDiacritic;
+
+ // update glyph flags of swapped glyphitems
+ pG->mnFlags &= ~GlyphItem::IS_IN_CLUSTER;
+ pBaseGlyph->mnFlags |= GlyphItem::IS_IN_CLUSTER;
+ // prepare for checking next cluster
+ pG = pBaseGlyph;
+ break;
+ }
+ }
+}
+
+// =======================================================================
+
+MultiSalLayout::MultiSalLayout( SalLayout& rBaseLayout, const ImplFontData* pBaseFont )
+: SalLayout()
+, mnLevel( 1 )
+, mbInComplete( false )
+{
+ //maFallbackRuns[0].Clear();
+ mpFallbackFonts[ 0 ] = pBaseFont;
+ mpLayouts[ 0 ] = &rBaseLayout;
+ mnUnitsPerPixel = rBaseLayout.GetUnitsPerPixel();
+}
+
+void MultiSalLayout::SetInComplete(bool bInComplete)
+{
+ mbInComplete = bInComplete;
+ maFallbackRuns[mnLevel-1] = ImplLayoutRuns();
+}
+
+// -----------------------------------------------------------------------
+
+MultiSalLayout::~MultiSalLayout()
+{
+ for( int i = 0; i < mnLevel; ++i )
+ mpLayouts[ i ]->Release();
+}
+
+// -----------------------------------------------------------------------
+
+bool MultiSalLayout::AddFallback( SalLayout& rFallback,
+ ImplLayoutRuns& rFallbackRuns, const ImplFontData* pFallbackFont )
+{
+ if( mnLevel >= MAX_FALLBACK )
+ return false;
+
+ mpFallbackFonts[ mnLevel ] = pFallbackFont;
+ mpLayouts[ mnLevel ] = &rFallback;
+ maFallbackRuns[ mnLevel-1 ] = rFallbackRuns;
+ ++mnLevel;
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool MultiSalLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ if( mnLevel <= 1 )
+ return false;
+ if (!mbInComplete)
+ maFallbackRuns[ mnLevel-1 ] = rArgs.maRuns;
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ SalLayout::AdjustLayout( rArgs );
+ ImplLayoutArgs aMultiArgs = rArgs;
+
+ if( !rArgs.mpDXArray && rArgs.mnLayoutWidth )
+ {
+ // for stretched text in a MultiSalLayout the target width needs to be
+ // distributed by individually adjusting its virtual character widths
+ long nTargetWidth = aMultiArgs.mnLayoutWidth;
+ nTargetWidth *= mnUnitsPerPixel; // convert target width to base font units
+ aMultiArgs.mnLayoutWidth = 0;
+
+ // we need to get the original unmodified layouts ready
+ for( int n = 0; n < mnLevel; ++n )
+ mpLayouts[n]->SalLayout::AdjustLayout( aMultiArgs );
+ // then we can measure the unmodified metrics
+ int nCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
+ sal_Int32* pJustificationArray = (sal_Int32*)alloca( nCharCount * sizeof(sal_Int32) );
+ FillDXArray( pJustificationArray );
+ // #i17359# multilayout is not simplified yet, so calculating the
+ // unjustified width needs handholding; also count the number of
+ // stretchable virtual char widths
+ long nOrigWidth = 0;
+ int nStretchable = 0;
+ for( int i = 0; i < nCharCount; ++i )
+ {
+ // convert array from widths to sum of widths
+ nOrigWidth += pJustificationArray[i];
+ if( pJustificationArray[i] > 0 )
+ ++nStretchable;
+ }
+
+ // now we are able to distribute the extra width over the virtual char widths
+ if( nOrigWidth && (nTargetWidth != nOrigWidth) )
+ {
+ int nDiffWidth = nTargetWidth - nOrigWidth;
+ int nWidthSum = 0;
+ for( int i = 0; i < nCharCount; ++i )
+ {
+ int nJustWidth = pJustificationArray[i];
+ if( (nJustWidth > 0) && (nStretchable > 0) )
+ {
+ int nDeltaWidth = nDiffWidth / nStretchable;
+ nJustWidth += nDeltaWidth;
+ nDiffWidth -= nDeltaWidth;
+ --nStretchable;
+ }
+ nWidthSum += nJustWidth;
+ pJustificationArray[i] = nWidthSum;
+ }
+ if( nWidthSum != nTargetWidth )
+ pJustificationArray[ nCharCount-1 ] = nTargetWidth;
+
+ // the justification array is still in base level units
+ // => convert it to pixel units
+ if( mnUnitsPerPixel > 1 )
+ {
+ for( int i = 0; i < nCharCount; ++i )
+ {
+ sal_Int32 nVal = pJustificationArray[ i ];
+ nVal += (mnUnitsPerPixel + 1) / 2;
+ pJustificationArray[ i ] = nVal / mnUnitsPerPixel;
+ }
+ }
+
+ // change the mpDXArray temporarilly (just for the justification)
+ aMultiArgs.mpDXArray = pJustificationArray;
+ }
+ }
+
+ // Compute rtl flags, since in some scripts glyphs/char order can be
+ // reversed for a few character sequencies e.g. Myanmar
+ std::vector<bool> vRtl(rArgs.mnEndCharPos - rArgs.mnMinCharPos, false);
+ rArgs.ResetPos();
+ bool bRtl;
+ int nRunStart, nRunEnd;
+ while (rArgs.GetNextRun(&nRunStart, &nRunEnd, &bRtl))
+ {
+ if (bRtl) std::fill(vRtl.begin() + (nRunStart - rArgs.mnMinCharPos),
+ vRtl.begin() + (nRunEnd - rArgs.mnMinCharPos), true);
+ }
+ rArgs.ResetPos();
+
+ // prepare "merge sort"
+ int nStartOld[ MAX_FALLBACK ];
+ int nStartNew[ MAX_FALLBACK ];
+ int nCharPos[ MAX_FALLBACK ];
+ sal_Int32 nGlyphAdv[ MAX_FALLBACK ];
+ int nValid[ MAX_FALLBACK ] = {0};
+
+ sal_GlyphId nDummy;
+ Point aPos;
+ int nLevel = 0, n;
+ for( n = 0; n < mnLevel; ++n )
+ {
+ // now adjust the individual components
+ if( n > 0 )
+ {
+ aMultiArgs.maRuns = maFallbackRuns[ n-1 ];
+ aMultiArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
+ }
+ mpLayouts[n]->AdjustLayout( aMultiArgs );
+
+ // disable glyph-injection for glyph-fallback SalLayout iteration
+ mpLayouts[n]->DisableGlyphInjection( true );
+
+ // remove unused parts of component
+ if( n > 0 )
+ {
+ if (mbInComplete && (n == mnLevel-1))
+ mpLayouts[n]->Simplify( true );
+ else
+ mpLayouts[n]->Simplify( false );
+ }
+
+ // prepare merging components
+ nStartNew[ nLevel ] = nStartOld[ nLevel ] = 0;
+ nValid[ nLevel ] = mpLayouts[n]->GetNextGlyphs( 1, &nDummy, aPos,
+ nStartNew[ nLevel ], &nGlyphAdv[ nLevel ], &nCharPos[ nLevel ] );
+#ifdef MULTI_SL_DEBUG
+ if (nValid[nLevel]) fprintf(mslLog(), "layout[%d]->GetNextGlyphs %d,%d x%d a%d c%d %x\n", n, nStartOld[nLevel], nStartNew[nLevel], aPos.X(), nGlyphAdv[nLevel], nCharPos[nLevel],
+ rArgs.mpStr[nCharPos[nLevel]]);
+#endif
+ if( (n > 0) && !nValid[ nLevel ] )
+ {
+ // an empty fallback layout can be released
+ mpLayouts[n]->Release();
+ }
+ else
+ {
+ // reshuffle used fallbacks if needed
+ if( nLevel != n )
+ {
+ mpLayouts[ nLevel ] = mpLayouts[ n ];
+ mpFallbackFonts[ nLevel ] = mpFallbackFonts[ n ];
+ maFallbackRuns[ nLevel ] = maFallbackRuns[ n ];
+ }
+ ++nLevel;
+ }
+ }
+ mnLevel = nLevel;
+
+ // merge the fallback levels
+ long nXPos = 0;
+ double fUnitMul = 1.0;
+ for( n = 0; n < nLevel; ++n )
+ maFallbackRuns[n].ResetPos();
+ int nActiveCharPos = nCharPos[0];
+ int nLastRunEndChar = (vRtl[nActiveCharPos - mnMinCharPos])?
+ rArgs.mnEndCharPos : rArgs.mnMinCharPos - 1;
+ int nRunVisibleEndChar = nCharPos[0];
+ while( nValid[0] && (nLevel > 0))
+ {
+ // find best fallback level
+ for( n = 0; n < nLevel; ++n )
+ if( nValid[n] && !maFallbackRuns[n].PosIsInAnyRun( nActiveCharPos ) )
+ // fallback level n wins when it requested no further fallback
+ break;
+ int nFBLevel = n;
+
+ if( n < nLevel )
+ {
+ // use base(n==0) or fallback(n>=1) level
+ fUnitMul = mnUnitsPerPixel;
+ fUnitMul /= mpLayouts[n]->GetUnitsPerPixel();
+ long nNewPos = static_cast<long>(nXPos/fUnitMul + 0.5);
+ mpLayouts[n]->MoveGlyph( nStartOld[n], nNewPos );
+ }
+ else
+ {
+ n = 0; // keep NotDef in base level
+ fUnitMul = 1.0;
+ }
+
+ if( n > 0 )
+ {
+ // drop the NotDef glyphs in the base layout run if a fallback run exists
+ while (
+ (maFallbackRuns[ n-1 ].PosIsInRun( nCharPos[0] ) ) &&
+ (!maFallbackRuns[ n ].PosIsInAnyRun( nCharPos[0] ) )
+ )
+ {
+ mpLayouts[0]->DropGlyph( nStartOld[0] );
+ nStartOld[0] = nStartNew[0];
+ nValid[0] = mpLayouts[0]->GetNextGlyphs( 1, &nDummy, aPos,
+ nStartNew[0], &nGlyphAdv[0], &nCharPos[0] );
+#ifdef MULTI_SL_DEBUG
+ if (nValid[0]) fprintf(mslLog(), "layout[0]->GetNextGlyphs %d,%d x%d a%d c%d %x\n", nStartOld[0], nStartNew[0], aPos.X(), nGlyphAdv[0], nCharPos[0], rArgs.mpStr[nCharPos[0]]);
+#endif
+ if( !nValid[0] )
+ break;
+ }
+ }
+
+ // skip to end of layout run and calculate its advance width
+ int nRunAdvance = 0;
+ bool bKeepNotDef = (nFBLevel >= nLevel);
+ for(;;)
+ {
+ nRunAdvance += nGlyphAdv[n];
+
+ // proceed to next glyph
+ nStartOld[n] = nStartNew[n];
+ int nOrigCharPos = nCharPos[n];
+ nValid[n] = mpLayouts[n]->GetNextGlyphs( 1, &nDummy, aPos,
+ nStartNew[n], &nGlyphAdv[n], &nCharPos[n] );
+#ifdef MULTI_SL_DEBUG
+ if (nValid[n]) fprintf(mslLog(), "layout[%d]->GetNextGlyphs %d,%d a%d c%d %x\n", n, nStartOld[n], nStartNew[n], nGlyphAdv[n], nCharPos[n], rArgs.mpStr[nCharPos[n]]);
+#endif
+ // break after last glyph of active layout
+ if( !nValid[n] )
+ {
+ // performance optimization (when a fallback layout is no longer needed)
+ if( n >= nLevel-1 )
+ --nLevel;
+ break;
+ }
+
+ //If the next character is one which belongs to the next level, then we
+ //are finished here for now, and we'll pick up after the next level has
+ //been processed
+ if ((n+1 < nLevel) && (nCharPos[n] != nOrigCharPos))
+ {
+ if (nOrigCharPos < nCharPos[n])
+ {
+ if (nCharPos[n+1] > nOrigCharPos && (nCharPos[n+1] < nCharPos[n]))
+ break;
+ }
+ else if (nOrigCharPos > nCharPos[n])
+ {
+ if (nCharPos[n+1] > nCharPos[n] && (nCharPos[n+1] < nOrigCharPos))
+ break;
+ }
+ }
+
+ // break at end of layout run
+ if( n > 0 )
+ {
+ // skip until end of fallback run
+ if( !maFallbackRuns[n-1].PosIsInRun( nCharPos[n] ) )
+ break;
+ }
+ else
+ {
+ // break when a fallback is needed and available
+ bool bNeedFallback = maFallbackRuns[0].PosIsInRun( nCharPos[0] );
+ if( bNeedFallback )
+ if( !maFallbackRuns[ nLevel-1 ].PosIsInRun( nCharPos[0] ) )
+ break;
+ // break when change from resolved to unresolved base layout run
+ if( bKeepNotDef && !bNeedFallback )
+ { maFallbackRuns[0].NextRun(); break; }
+ bKeepNotDef = bNeedFallback;
+ }
+ // check for reordered glyphs
+ if (aMultiArgs.mpDXArray &&
+ nRunVisibleEndChar < mnEndCharPos &&
+ nRunVisibleEndChar >= mnMinCharPos &&
+ nCharPos[n] < mnEndCharPos &&
+ nCharPos[n] >= mnMinCharPos)
+ {
+ if (vRtl[nActiveCharPos - mnMinCharPos])
+ {
+ if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
+ >= aMultiArgs.mpDXArray[nCharPos[n] - mnMinCharPos])
+ {
+ nRunVisibleEndChar = nCharPos[n];
+ }
+ }
+ else if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
+ <= aMultiArgs.mpDXArray[nCharPos[n] - mnMinCharPos])
+ {
+ nRunVisibleEndChar = nCharPos[n];
+ }
+ }
+ }
+
+ // if a justification array is available
+ // => use it directly to calculate the corresponding run width
+ if( aMultiArgs.mpDXArray )
+ {
+ // the run advance is the width from the first char
+ // in the run to the first char in the next run
+ nRunAdvance = 0;
+#ifdef MULTI_SL_DEBUG
+ const bool bLTR = !(vRtl[nActiveCharPos - mnMinCharPos]);//(nActiveCharPos < nCharPos[0]);
+ int nOldRunAdv = 0;
+ int nDXIndex = nCharPos[0] - mnMinCharPos - bLTR;
+ if( nDXIndex >= 0 )
+ nOldRunAdv += aMultiArgs.mpDXArray[ nDXIndex ];
+ nDXIndex = nActiveCharPos - mnMinCharPos - bLTR;
+ if( nDXIndex >= 0 )
+ nOldRunAdv -= aMultiArgs.mpDXArray[ nDXIndex ];
+ if( !bLTR )
+ nOldRunAdv = -nOldRunAdv;
+#endif
+ if (vRtl[nActiveCharPos - mnMinCharPos])
+ {
+ if (nRunVisibleEndChar > mnMinCharPos && nRunVisibleEndChar <= mnEndCharPos)
+ nRunAdvance -= aMultiArgs.mpDXArray[nRunVisibleEndChar - 1 - mnMinCharPos];
+ if (nLastRunEndChar > mnMinCharPos && nLastRunEndChar <= mnEndCharPos)
+ nRunAdvance += aMultiArgs.mpDXArray[nLastRunEndChar - 1 - mnMinCharPos];
+#ifdef MULTI_SL_DEBUG
+ fprintf(mslLog(), "rtl visible %d-%d,%d-%d adv%d(%d)\n", nLastRunEndChar-1, nRunVisibleEndChar-1, nActiveCharPos - bLTR, nCharPos[0] - bLTR, nRunAdvance, nOldRunAdv);
+#endif
+ }
+ else
+ {
+ if (nRunVisibleEndChar >= mnMinCharPos)
+ nRunAdvance += aMultiArgs.mpDXArray[nRunVisibleEndChar - mnMinCharPos];
+ if (nLastRunEndChar >= mnMinCharPos)
+ nRunAdvance -= aMultiArgs.mpDXArray[nLastRunEndChar - mnMinCharPos];
+#ifdef MULTI_SL_DEBUG
+ fprintf(mslLog(), "visible %d-%d,%d-%d adv%d(%d)\n", nLastRunEndChar, nRunVisibleEndChar, nActiveCharPos - bLTR, nCharPos[0] - bLTR, nRunAdvance, nOldRunAdv);
+#endif
+ }
+ nLastRunEndChar = nRunVisibleEndChar;
+ nRunVisibleEndChar = nCharPos[0];
+ // the requested width is still in pixel units
+ // => convert it to base level font units
+ nRunAdvance *= mnUnitsPerPixel;
+ }
+ else
+ {
+ // the measured width is still in fallback font units
+ // => convert it to base level font units
+ if( n > 0 ) // optimization: because (fUnitMul==1.0) for (n==0)
+ nRunAdvance = static_cast<long>(nRunAdvance*fUnitMul + 0.5);
+ }
+
+ // calculate new x position (in base level units)
+ nXPos += nRunAdvance;
+
+ // prepare for next fallback run
+ nActiveCharPos = nCharPos[0];
+ // it essential that the runs don't get ahead of themselves and in the
+ // if( bKeepNotDef && !bNeedFallback ) statement above, the next run may
+ // have already been reached on the base level
+ for( int i = nFBLevel; --i >= 0;)
+ {
+ if (maFallbackRuns[i].GetRun(&nRunStart, &nRunEnd, &bRtl))
+ {
+ if (bRtl)
+ {
+ if (nRunStart > nActiveCharPos)
+ maFallbackRuns[i].NextRun();
+ }
+ else
+ {
+ if (nRunEnd <= nActiveCharPos)
+ maFallbackRuns[i].NextRun();
+ }
+ }
+ }
+// if( !maFallbackRuns[i].PosIsInRun( nActiveCharPos ) )
+// maFallbackRuns[i].NextRun();
+ }
+
+ mpLayouts[0]->Simplify( true );
+
+ // reenable glyph-injection
+ for( n = 0; n < mnLevel; ++n )
+ mpLayouts[n]->DisableGlyphInjection( false );
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSalLayout::InitFont() const
+{
+ if( mnLevel > 0 )
+ mpLayouts[0]->InitFont();
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontData* MultiSalLayout::GetFallbackFontData( sal_GlyphId nGlyphId ) const
+{
+ int nFallbackLevel = (nGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
+ return mpFallbackFonts[ nFallbackLevel ];
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSalLayout::DrawText( SalGraphics& rGraphics ) const
+{
+ for( int i = mnLevel; --i >= 0; )
+ {
+ SalLayout& rLayout = *mpLayouts[ i ];
+ rLayout.DrawBase() += maDrawBase;
+ rLayout.DrawOffset() += maDrawOffset;
+ rLayout.InitFont();
+ rLayout.DrawText( rGraphics );
+ rLayout.DrawOffset() -= maDrawOffset;
+ rLayout.DrawBase() -= maDrawBase;
+ }
+ // NOTE: now the baselevel font is active again
+}
+
+ // -----------------------------------------------------------------------
+
+int MultiSalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ if( mnLevel <= 0 )
+ return STRING_LEN;
+ if( mnLevel == 1 )
+ return mpLayouts[0]->GetTextBreak( nMaxWidth, nCharExtra, nFactor );
+
+ int nCharCount = mnEndCharPos - mnMinCharPos;
+ sal_Int32* pCharWidths = (sal_Int32*)alloca( 2*nCharCount * sizeof(sal_Int32) );
+ mpLayouts[0]->FillDXArray( pCharWidths );
+
+ for( int n = 1; n < mnLevel; ++n )
+ {
+ SalLayout& rLayout = *mpLayouts[ n ];
+ rLayout.FillDXArray( pCharWidths + nCharCount );
+ double fUnitMul = mnUnitsPerPixel;
+ fUnitMul /= rLayout.GetUnitsPerPixel();
+ for( int i = 0; i < nCharCount; ++i )
+ {
+ long w = pCharWidths[ i + nCharCount ];
+ w = static_cast<long>(w*fUnitMul + 0.5);
+ pCharWidths[ i ] += w;
+ }
+ }
+
+ long nWidth = 0;
+ for( int i = 0; i < nCharCount; ++i )
+ {
+ nWidth += pCharWidths[ i ] * nFactor;
+ if( nWidth > nMaxWidth )
+ return (i + mnMinCharPos);
+ nWidth += nCharExtra;
+ }
+
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
+
+long MultiSalLayout::FillDXArray( sal_Int32* pCharWidths ) const
+{
+ long nMaxWidth = 0;
+
+ // prepare merging of fallback levels
+ sal_Int32* pTempWidths = NULL;
+ const int nCharCount = mnEndCharPos - mnMinCharPos;
+ if( pCharWidths )
+ {
+ for( int i = 0; i < nCharCount; ++i )
+ pCharWidths[i] = 0;
+ pTempWidths = (sal_Int32*)alloca( nCharCount * sizeof(sal_Int32) );
+ }
+
+ for( int n = mnLevel; --n >= 0; )
+ {
+ // query every fallback level
+ long nTextWidth = mpLayouts[n]->FillDXArray( pTempWidths );
+ if( !nTextWidth )
+ continue;
+ // merge results from current level
+ double fUnitMul = mnUnitsPerPixel;
+ fUnitMul /= mpLayouts[n]->GetUnitsPerPixel();
+ nTextWidth = static_cast<long>(nTextWidth * fUnitMul + 0.5);
+ if( nMaxWidth < nTextWidth )
+ nMaxWidth = nTextWidth;
+ if( !pCharWidths )
+ continue;
+ // calculate virtual char widths using most probable fallback layout
+ for( int i = 0; i < nCharCount; ++i )
+ {
+ // #i17359# restriction:
+ // one char cannot be resolved from different fallbacks
+ if( pCharWidths[i] != 0 )
+ continue;
+ long nCharWidth = pTempWidths[i];
+ if( !nCharWidth )
+ continue;
+ nCharWidth = static_cast<long>(nCharWidth * fUnitMul + 0.5);
+ pCharWidths[i] = nCharWidth;
+ }
+ }
+
+ return nMaxWidth;
+}
+
+// -----------------------------------------------------------------------
+
+void MultiSalLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const
+{
+ SalLayout& rLayout = *mpLayouts[ 0 ];
+ rLayout.GetCaretPositions( nMaxIndex, pCaretXArray );
+
+ if( mnLevel > 1 )
+ {
+ sal_Int32* pTempPos = (sal_Int32*)alloca( nMaxIndex * sizeof(sal_Int32) );
+ for( int n = 1; n < mnLevel; ++n )
+ {
+ mpLayouts[ n ]->GetCaretPositions( nMaxIndex, pTempPos );
+ double fUnitMul = mnUnitsPerPixel;
+ fUnitMul /= mpLayouts[n]->GetUnitsPerPixel();
+ for( int i = 0; i < nMaxIndex; ++i )
+ if( pTempPos[i] >= 0 )
+ {
+ long w = pTempPos[i];
+ w = static_cast<long>(w*fUnitMul + 0.5);
+ pCaretXArray[i] = w;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int MultiSalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIdxAry, Point& rPos,
+ int& nStart, sal_Int32* pGlyphAdvAry, int* pCharPosAry ) const
+{
+ // for multi-level fallback only single glyphs should be used
+ if( mnLevel > 1 && nLen > 1 )
+ nLen = 1;
+
+ // NOTE: nStart is tagged with current font index
+ int nLevel = static_cast<unsigned>(nStart) >> GF_FONTSHIFT;
+ nStart &= ~GF_FONTMASK;
+ for(; nLevel < mnLevel; ++nLevel, nStart=0 )
+ {
+ SalLayout& rLayout = *mpLayouts[ nLevel ];
+ rLayout.InitFont();
+ int nRetVal = rLayout.GetNextGlyphs( nLen, pGlyphIdxAry, rPos,
+ nStart, pGlyphAdvAry, pCharPosAry );
+ if( nRetVal )
+ {
+ int nFontTag = nLevel << GF_FONTSHIFT;
+ nStart |= nFontTag;
+ double fUnitMul = mnUnitsPerPixel;
+ fUnitMul /= mpLayouts[nLevel]->GetUnitsPerPixel();
+ for( int i = 0; i < nRetVal; ++i )
+ {
+ if( pGlyphAdvAry )
+ {
+ long w = pGlyphAdvAry[i];
+ w = static_cast<long>(w * fUnitMul + 0.5);
+ pGlyphAdvAry[i] = w;
+ }
+ pGlyphIdxAry[ i ] |= nFontTag;
+ }
+ rPos += maDrawBase;
+ rPos += maDrawOffset;
+ return nRetVal;
+ }
+ }
+
+ // #111016# reset to base level font when done
+ mpLayouts[0]->InitFont();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+bool MultiSalLayout::GetOutline( SalGraphics& rGraphics,
+ ::basegfx::B2DPolyPolygonVector& rPPV ) const
+{
+ bool bRet = false;
+
+ for( int i = mnLevel; --i >= 0; )
+ {
+ SalLayout& rLayout = *mpLayouts[ i ];
+ rLayout.DrawBase() = maDrawBase;
+ rLayout.DrawOffset() += maDrawOffset;
+ rLayout.InitFont();
+ bRet |= rLayout.GetOutline( rGraphics, rPPV );
+ rLayout.DrawOffset() -= maDrawOffset;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+bool MultiSalLayout::GetBoundRect( SalGraphics& rGraphics, Rectangle& rRect ) const
+{
+ bool bRet = false;
+
+ Rectangle aRectangle;
+ for( int i = mnLevel; --i >= 0; )
+ {
+ SalLayout& rLayout = *mpLayouts[ i ];
+ rLayout.DrawBase() = maDrawBase;
+ rLayout.DrawOffset() += maDrawOffset;
+ rLayout.InitFont();
+ if( rLayout.GetBoundRect( rGraphics, aRectangle ) )
+ {
+ rRect.Union( aRectangle );
+ bRet = true;
+ }
+ rLayout.DrawOffset() -= maDrawOffset;
+ }
+
+ return bRet;
+}
+
+// =======================================================================
diff --git a/vcl/source/gdi/salmisc.cxx b/vcl/source/gdi/salmisc.cxx
new file mode 100644
index 000000000000..31df581f50a2
--- /dev/null
+++ b/vcl/source/gdi/salmisc.cxx
@@ -0,0 +1,516 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <rtl/memory.h>
+#include <vcl/bmpacc.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/bmpfast.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define IMPL_CASE_GET_FORMAT( Format ) \
+case( BMP_FORMAT##Format ): \
+ pFncGetPixel = BitmapReadAccess::GetPixelFor##Format; \
+break
+
+// -----------------------------------------------------------------------------
+
+#define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
+case( BMP_FORMAT##Format ): \
+{ \
+ pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
+ pDstBuffer->mnBitCount = BitCount; \
+} \
+break
+
+// -----------------------------------------------------------------------------
+
+#define DOUBLE_SCANLINES() \
+while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
+{ \
+ memcpy( pDstScanMap[ nActY + 1L ], pDstScan, rDstBuffer.mnScanlineSize ); \
+ nActY++; \
+}
+
+// -----------
+// - Inlines -
+// -----------
+
+#define TC_TO_PAL_COLORS 4096
+
+static long ImplIndexFromColor( const BitmapColor& rCol )
+{
+#if TC_TO_PAL_COLORS == 4096
+
+ return( ( ( (long) rCol.GetBlue() >> 4L) << 8L ) |
+ ( ( (long) rCol.GetGreen() >> 4L ) << 4L ) |
+ ( (long) rCol.GetRed() >> 4L ) );
+
+#elif TC_TO_PAL_COLORS == 32768
+
+ return( ( ( (long) rCol.GetBlue() >> 3L) << 10L ) |
+ ( ( (long) rCol.GetGreen() >> 3L ) << 5L ) |
+ ( (long) rCol.GetRed() >> 3L ) );
+
+#endif
+}
+
+
+#define COLOR_TO_INDEX( _def_rCol )
+
+// ------------------------
+// - conversion functions -
+// ------------------------
+
+static void ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
+ FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
+ Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
+{
+ const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
+ const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
+ const ColorMask& rDstMask = rDstBuffer.maColorMask;
+ BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
+ BitmapColor* pColMapBuf = aColMap.ImplGetColorBuffer();
+ BitmapColor aIndex( 0 );
+
+ for( USHORT i = 0, nSrcCount = aColMap.GetEntryCount(), nDstCount = rDstBuffer.maPalette.GetEntryCount(); i < nSrcCount; i++ )
+ {
+ if( ( i < nDstCount ) && ( rSrcBuffer.maPalette[ i ] == rDstBuffer.maPalette[ i ] ) )
+ aIndex.SetIndex( sal::static_int_cast<BYTE>(i) );
+ else
+ aIndex.SetIndex( sal::static_int_cast<BYTE>(rDstBuffer.maPalette.GetBestIndex( rSrcBuffer.maPalette[ i ] )) );
+
+ pColMapBuf[ i ] = aIndex;
+ }
+
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pFncSetPixel( pDstScan, nX, pColMapBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
+
+ DOUBLE_SCANLINES();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+static void ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
+ FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
+ Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
+{
+ const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
+ const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
+ const ColorMask& rDstMask = rDstBuffer.maColorMask;
+ const BitmapColor* pColBuf = rSrcBuffer.maPalette.ImplGetColorBuffer();
+
+ if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_1BIT_MSB_PAL )
+ {
+ const BitmapColor aCol0( pColBuf[ 0 ] );
+ const BitmapColor aCol1( pColBuf[ 1 ] );
+ long nMapX;
+
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; )
+ {
+ nMapX = pMapX[ nX ];
+ pFncSetPixel( pDstScan, nX++,
+ pSrcScan[ nMapX >> 3 ] & ( 1 << ( 7 - ( nMapX & 7 ) ) ) ? aCol1 : aCol0,
+ rDstMask );
+ }
+
+ DOUBLE_SCANLINES();
+ }
+ }
+ else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_4BIT_MSN_PAL )
+ {
+ long nMapX;
+
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; )
+ {
+ nMapX = pMapX[ nX ];
+ pFncSetPixel( pDstScan, nX++,
+ pColBuf[ ( pSrcScan[ nMapX >> 1 ] >> ( nMapX & 1 ? 0 : 4 ) ) & 0x0f ],
+ rDstMask );
+ }
+
+ DOUBLE_SCANLINES();
+ }
+ }
+ else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_8BIT_PAL )
+ {
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pFncSetPixel( pDstScan, nX, pColBuf[ pSrcScan[ pMapX[ nX ] ] ], rDstMask );
+
+ DOUBLE_SCANLINES();
+ }
+ }
+ else
+ {
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pFncSetPixel( pDstScan, nX, pColBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
+
+ DOUBLE_SCANLINES();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+static void ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
+ FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
+ Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
+{
+ const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
+ const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
+ const ColorMask& rDstMask = rDstBuffer.maColorMask;
+
+ if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_24BIT_TC_BGR )
+ {
+ BitmapColor aCol;
+ BYTE* pPixel;
+
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aCol.SetBlue( *( pPixel = ( pSrcScan + pMapX[ nX ] * 3 ) )++ );
+ aCol.SetGreen( *pPixel++ );
+ aCol.SetRed( *pPixel );
+ pFncSetPixel( pDstScan, nX, aCol, rDstMask );
+ }
+
+ DOUBLE_SCANLINES()
+ }
+ }
+ else
+ {
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ pFncSetPixel( pDstScan, nX, pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ), rDstMask );
+
+ DOUBLE_SCANLINES();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+static void ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
+ FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
+ Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
+{
+ const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
+ const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
+ const ColorMask& rDstMask = rDstBuffer.maColorMask;
+ BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
+ BYTE* pColToPalMap = new BYTE[ TC_TO_PAL_COLORS ];
+ BitmapColor aIndex( 0 );
+
+ for( long nR = 0; nR < 16; nR++ )
+ {
+ for( long nG = 0; nG < 16; nG++ )
+ {
+ for( long nB = 0; nB < 16; nB++ )
+ {
+ BitmapColor aCol( sal::static_int_cast<BYTE>(nR << 4),
+ sal::static_int_cast<BYTE>(nG << 4),
+ sal::static_int_cast<BYTE>(nB << 4) );
+ pColToPalMap[ ImplIndexFromColor( aCol ) ] = (BYTE) rDstBuffer.maPalette.GetBestIndex( aCol );
+ }
+ }
+ }
+
+ for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
+ {
+ Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
+
+ for( long nX = 0L; nX < nWidth; nX++ )
+ {
+ aIndex.SetIndex( pColToPalMap[ ImplIndexFromColor( pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ) ) ] );
+ pFncSetPixel( pDstScan, nX, aIndex, rDstMask );
+ }
+
+ DOUBLE_SCANLINES();
+ }
+
+ delete[] pColToPalMap;
+}
+
+// -----------------------------------------------------------------------------
+
+// ---------------------
+// - StretchAndConvert -
+// ---------------------
+
+BitmapBuffer* StretchAndConvert( const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect,
+ ULONG nDstBitmapFormat, BitmapPalette* pDstPal, ColorMask* pDstMask )
+{
+ FncGetPixel pFncGetPixel;
+ FncSetPixel pFncSetPixel;
+ BitmapBuffer* pDstBuffer = new BitmapBuffer;
+ long i;
+
+ // set function for getting pixels
+ switch( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) )
+ {
+ IMPL_CASE_GET_FORMAT( _1BIT_MSB_PAL );
+ IMPL_CASE_GET_FORMAT( _1BIT_LSB_PAL );
+ IMPL_CASE_GET_FORMAT( _4BIT_MSN_PAL );
+ IMPL_CASE_GET_FORMAT( _4BIT_LSN_PAL );
+ IMPL_CASE_GET_FORMAT( _8BIT_PAL );
+ IMPL_CASE_GET_FORMAT( _8BIT_TC_MASK );
+ IMPL_CASE_GET_FORMAT( _16BIT_TC_MSB_MASK );
+ IMPL_CASE_GET_FORMAT( _16BIT_TC_LSB_MASK );
+ IMPL_CASE_GET_FORMAT( _24BIT_TC_BGR );
+ IMPL_CASE_GET_FORMAT( _24BIT_TC_RGB );
+ IMPL_CASE_GET_FORMAT( _24BIT_TC_MASK );
+ IMPL_CASE_GET_FORMAT( _32BIT_TC_ABGR );
+ IMPL_CASE_GET_FORMAT( _32BIT_TC_ARGB );
+ IMPL_CASE_GET_FORMAT( _32BIT_TC_BGRA );
+ IMPL_CASE_GET_FORMAT( _32BIT_TC_RGBA );
+ IMPL_CASE_GET_FORMAT( _32BIT_TC_MASK );
+
+ default:
+ // should never come here
+ // initialize pFncGetPixel to something valid that is
+ // least likely to crash
+ pFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_MSB_PAL;
+ DBG_ERROR( "unknown read format" );
+ break;
+ }
+
+ // set function for setting pixels
+ const ULONG nDstScanlineFormat = BMP_SCANLINE_FORMAT( nDstBitmapFormat );
+ switch( nDstScanlineFormat )
+ {
+ IMPL_CASE_SET_FORMAT( _1BIT_MSB_PAL, 1 );
+ IMPL_CASE_SET_FORMAT( _1BIT_LSB_PAL, 1 );
+ IMPL_CASE_SET_FORMAT( _4BIT_MSN_PAL, 1 );
+ IMPL_CASE_SET_FORMAT( _4BIT_LSN_PAL, 4 );
+ IMPL_CASE_SET_FORMAT( _8BIT_PAL, 8 );
+ IMPL_CASE_SET_FORMAT( _8BIT_TC_MASK, 8 );
+ IMPL_CASE_SET_FORMAT( _16BIT_TC_MSB_MASK, 16 );
+ IMPL_CASE_SET_FORMAT( _16BIT_TC_LSB_MASK, 16 );
+ IMPL_CASE_SET_FORMAT( _24BIT_TC_BGR, 24 );
+ IMPL_CASE_SET_FORMAT( _24BIT_TC_RGB, 24 );
+ IMPL_CASE_SET_FORMAT( _24BIT_TC_MASK, 24 );
+ IMPL_CASE_SET_FORMAT( _32BIT_TC_ABGR, 32 );
+ IMPL_CASE_SET_FORMAT( _32BIT_TC_ARGB, 32 );
+ IMPL_CASE_SET_FORMAT( _32BIT_TC_BGRA, 32 );
+ IMPL_CASE_SET_FORMAT( _32BIT_TC_RGBA, 32 );
+ IMPL_CASE_SET_FORMAT( _32BIT_TC_MASK, 32 );
+
+ default:
+ // should never come here
+ // initialize pFncSetPixel to something valid that is
+ // least likely to crash
+ pFncSetPixel = BitmapReadAccess::SetPixelFor_1BIT_MSB_PAL;
+ pDstBuffer->mnBitCount = 1;
+ DBG_ERROR( "unknown write format" );
+ break;
+ }
+
+ // fill destination buffer
+ pDstBuffer->mnFormat = nDstBitmapFormat;
+ pDstBuffer->mnWidth = rTwoRect.mnDestWidth;
+ pDstBuffer->mnHeight = rTwoRect.mnDestHeight;
+ pDstBuffer->mnScanlineSize = AlignedWidth4Bytes( pDstBuffer->mnBitCount * pDstBuffer->mnWidth );
+ try
+ {
+ pDstBuffer->mpBits = new BYTE[ pDstBuffer->mnScanlineSize * pDstBuffer->mnHeight ];
+ }
+ catch( const std::bad_alloc& )
+ {
+ // memory exception, clean up
+ pDstBuffer->mpBits = NULL;
+ delete pDstBuffer;
+ return NULL;
+ }
+
+ // do we need a destination palette or color mask?
+ if( ( nDstScanlineFormat == BMP_FORMAT_1BIT_MSB_PAL ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_1BIT_LSB_PAL ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_4BIT_MSN_PAL ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_4BIT_LSN_PAL ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_8BIT_PAL ) )
+ {
+ DBG_ASSERT( pDstPal, "destination buffer requires palette" );
+ pDstBuffer->maPalette = *pDstPal;
+ }
+ else if( ( nDstScanlineFormat == BMP_FORMAT_8BIT_TC_MASK ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_16BIT_TC_MSB_MASK ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_16BIT_TC_LSB_MASK ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_24BIT_TC_MASK ) ||
+ ( nDstScanlineFormat == BMP_FORMAT_32BIT_TC_MASK ) )
+ {
+ DBG_ASSERT( pDstMask, "destination buffer requires color mask" );
+ pDstBuffer->maColorMask = *pDstMask;
+ }
+
+ // short circuit the most important conversions
+ bool bFastConvert = ImplFastBitmapConversion( *pDstBuffer, rSrcBuffer, rTwoRect );
+ if( bFastConvert )
+ return pDstBuffer;
+
+ const long nSrcX = rTwoRect.mnSrcX, nSrcY = rTwoRect.mnSrcY;
+ const long nSrcDX = rTwoRect.mnSrcWidth, nSrcDY = rTwoRect.mnSrcHeight;
+ const long nDstDX = rTwoRect.mnDestWidth, nDstDY = rTwoRect.mnDestHeight;
+ Scanline* pSrcScan = NULL;
+ Scanline* pDstScan = NULL;
+ long* pMapX = NULL;
+ long* pMapY = NULL;
+ long nTmp, nOffset;
+
+ try
+ {
+ pSrcScan = new Scanline[ rSrcBuffer.mnHeight ];
+ pDstScan = new Scanline[ nDstDY ];
+ pMapX = new long[ nDstDX ];
+ pMapY = new long[ nDstDY ];
+ }
+ catch( const std::bad_alloc& )
+ {
+ // memory exception, clean up
+ // remark: the buffer ptr causing the exception
+ // is still NULL here
+ delete[] pSrcScan;
+ delete[] pDstScan;
+ delete[] pMapX;
+ delete[] pMapY;
+ delete pDstBuffer;
+ return NULL;
+ }
+
+ // horizontal mapping table
+ if( nDstDX != nSrcDX )
+ {
+ const double fFactorX = ( nDstDX > 1 ) ? (double) ( nSrcDX - 1 ) / ( nDstDX - 1 ) : 0.0;
+
+ for( i = 0L; i < nDstDX; i++ )
+ pMapX[ i ] = nSrcX + FRound( i * fFactorX );
+ }
+ else
+ {
+ for( i = 0L, nTmp = nSrcX; i < nDstDX; i++ )
+ pMapX[ i ] = nTmp++;
+ }
+
+ // vertical mapping table
+ if( nDstDY != nSrcDY )
+ {
+ const double fFactorY = ( nDstDY > 1 ) ? (double) ( nSrcDY - 1 ) / ( nDstDY - 1 ) : 0.0;
+
+ for( i = 0L; i < nDstDY; i++ )
+ pMapY[ i ] = nSrcY + FRound( i * fFactorY );
+ }
+ else
+ {
+ for( i = 0L, nTmp = nSrcY; i < nDstDY; i++ )
+ pMapY[ i ] = nTmp++;
+ }
+
+ // source scanline buffer
+ Scanline pTmpScan;
+ if( BMP_SCANLINE_ADJUSTMENT( rSrcBuffer.mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ pTmpScan = rSrcBuffer.mpBits, nOffset = rSrcBuffer.mnScanlineSize;
+ else
+ {
+ pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
+ nOffset = -rSrcBuffer.mnScanlineSize;
+ }
+
+ for( i = 0L; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset )
+ pSrcScan[ i ] = pTmpScan;
+
+ // destination scanline buffer
+ if( BMP_SCANLINE_ADJUSTMENT( pDstBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ pTmpScan = pDstBuffer->mpBits, nOffset = pDstBuffer->mnScanlineSize;
+ else
+ {
+ pTmpScan = pDstBuffer->mpBits + ( nDstDY - 1 ) * pDstBuffer->mnScanlineSize;
+ nOffset = -pDstBuffer->mnScanlineSize;
+ }
+
+ for( i = 0L; i < nDstDY; i++, pTmpScan += nOffset )
+ pDstScan[ i ] = pTmpScan;
+
+ // do buffer scaling and conversion
+ if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 )
+ {
+ ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
+ pSrcScan, pDstScan, pMapX, pMapY );
+ }
+ else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 )
+ {
+ ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
+ pSrcScan, pDstScan, pMapX, pMapY );
+ }
+ else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 )
+ {
+ ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
+ pSrcScan, pDstScan, pMapX, pMapY );
+ }
+ else
+ {
+ ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
+ pSrcScan, pDstScan, pMapX, pMapY );
+ }
+
+ // cleanup
+ delete[] pSrcScan;
+ delete[] pDstScan;
+ delete[] pMapX;
+ delete[] pMapY;
+
+ return pDstBuffer;
+}
diff --git a/vcl/source/gdi/salnativewidgets-none.cxx b/vcl/source/gdi/salnativewidgets-none.cxx
new file mode 100644
index 000000000000..8aa0e47f1a35
--- /dev/null
+++ b/vcl/source/gdi/salnativewidgets-none.cxx
@@ -0,0 +1,134 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/salgdi.hxx>
+
+using namespace rtl;
+
+/****************************************************************
+ * Placeholder for no native widgets
+ ***************************************************************/
+
+
+/*
+ * IsNativeControlSupported()
+ *
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart
+ */
+BOOL SalGraphics::IsNativeControlSupported( ControlType, ControlPart )
+{
+ return( FALSE );
+}
+
+
+/*
+ * HitTestNativeControl()
+ *
+ * If the return value is TRUE, bIsInside contains information whether
+ * aPos was or was not inside the native widget specified by the
+ * nType/nPart combination.
+ */
+BOOL SalGraphics::hitTestNativeControl( ControlType,
+ ControlPart,
+ const Rectangle&,
+ const Point&,
+ BOOL& )
+{
+ return( FALSE );
+}
+
+
+/*
+ * DrawNativeControl()
+ *
+ * Draws the requested control described by nPart/nState.
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL SalGraphics::drawNativeControl( ControlType,
+ ControlPart,
+ const Rectangle&,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ return( FALSE );
+}
+
+
+/*
+ * DrawNativeControlText()
+ *
+ * OPTIONAL. Draws the requested text for the control described by nPart/nState.
+ * Used if text not drawn by DrawNativeControl().
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL SalGraphics::drawNativeControlText( ControlType,
+ ControlPart,
+ const Rectangle&,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ return( FALSE );
+}
+
+
+/*
+ * GetNativeControlRegion()
+ *
+ * If the return value is TRUE, rNativeBoundingRegion
+ * contains the TRUE bounding region covered by the control
+ * including any adornment, while rNativeContentRegion contains the area
+ * within the control that can be safely drawn into without drawing over
+ * the borders of the control.
+ *
+ * rControlRegion: The bounding region of the control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL SalGraphics::getNativeControlRegion( ControlType,
+ ControlPart,
+ const Rectangle&,
+ ControlState,
+ const ImplControlValue&,
+ const OUString&,
+ Rectangle &,
+ Rectangle & )
+{
+ return( FALSE );
+}
+
diff --git a/vcl/source/gdi/svcompat.cxx b/vcl/source/gdi/svcompat.cxx
new file mode 100644
index 000000000000..415cad128a49
--- /dev/null
+++ b/vcl/source/gdi/svcompat.cxx
@@ -0,0 +1,78 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/stream.hxx>
+#include <svcompat.hxx>
+
+// --------------
+// - ImplCompat -
+// --------------
+
+ImplCompat::ImplCompat( SvStream& rStm, USHORT nStreamMode, USHORT nVersion ) :
+ mpRWStm ( &rStm ),
+ mnStmMode ( nStreamMode ),
+ mnVersion ( nVersion )
+{
+ if( !mpRWStm->GetError() )
+ {
+ if( STREAM_WRITE == mnStmMode )
+ {
+ *mpRWStm << mnVersion;
+ mnTotalSize = ( mnCompatPos = mpRWStm->Tell() ) + 4UL;
+ mpRWStm->SeekRel( 4L );
+ }
+ else
+ {
+ *mpRWStm >> mnVersion;
+ *mpRWStm >> mnTotalSize;
+ mnCompatPos = mpRWStm->Tell();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+ImplCompat::~ImplCompat()
+{
+ if( STREAM_WRITE == mnStmMode )
+ {
+ const UINT32 nEndPos = mpRWStm->Tell();
+
+ mpRWStm->Seek( mnCompatPos );
+ *mpRWStm << ( nEndPos - mnTotalSize );
+ mpRWStm->Seek( nEndPos );
+ }
+ else
+ {
+ const UINT32 nReadSize = mpRWStm->Tell() - mnCompatPos;
+
+ if( mnTotalSize > nReadSize )
+ mpRWStm->SeekRel( mnTotalSize - nReadSize );
+ }
+}
diff --git a/vcl/source/gdi/textlayout.cxx b/vcl/source/gdi/textlayout.cxx
new file mode 100644
index 000000000000..78ce197525ec
--- /dev/null
+++ b/vcl/source/gdi/textlayout.cxx
@@ -0,0 +1,386 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ***********************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/ctrl.hxx"
+#include "vcl/outdev.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/textlayout.hxx"
+
+#include <com/sun/star/i18n/ScriptDirection.hpp>
+
+#include <tools/diagnose_ex.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <rtl/strbuf.hxx>
+#endif
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Exception;
+ namespace ScriptDirection = ::com::sun::star::i18n::ScriptDirection;
+
+ //====================================================================
+ //= DefaultTextLayout
+ //====================================================================
+ //--------------------------------------------------------------------
+ DefaultTextLayout::~DefaultTextLayout()
+ {
+ }
+
+ //--------------------------------------------------------------------
+ long DefaultTextLayout::GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return m_rTargetDevice.GetTextWidth( _rText, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ void DefaultTextLayout::DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex,
+ xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText )
+ {
+ m_rTargetDevice.DrawText( _rStartPoint, _rText, _nStartIndex, _nLength, _pVector, _pDisplayText );
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultTextLayout::GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray,
+ xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return m_rTargetDevice.GetCaretPositions( _rText, _pCaretXArray, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ xub_StrLen DefaultTextLayout::GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return m_rTargetDevice.GetTextBreak( _rText, _nMaxTextWidth, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultTextLayout::DecomposeTextRectAction() const
+ {
+ return false;
+ }
+
+ //====================================================================
+ //= ReferenceDeviceTextLayout
+ //====================================================================
+ class ReferenceDeviceTextLayout : public ITextLayout
+ {
+ public:
+ ReferenceDeviceTextLayout( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice );
+ virtual ~ReferenceDeviceTextLayout();
+
+ // ITextLayout
+ virtual long GetTextWidth( const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const;
+ virtual void DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText );
+ virtual bool GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
+ virtual xub_StrLen GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
+ virtual bool DecomposeTextRectAction() const;
+
+ public:
+ // equivalents to the respective OutputDevice methods, which take the reference device into account
+ long GetTextArray( const XubString& _rText, sal_Int32* _pDXAry, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
+ Rectangle DrawText( const Rectangle& _rRect, const XubString& _rText, USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText );
+
+ protected:
+ void onBeginDrawText()
+ {
+ m_aCompleteTextRect.SetEmpty();
+ }
+ Rectangle onEndDrawText()
+ {
+ return m_aCompleteTextRect;
+ }
+
+ private:
+ OutputDevice& m_rTargetDevice;
+ OutputDevice& m_rReferenceDevice;
+ Font m_aUnzoomedPointFont;
+ const Fraction m_aZoom;
+ const bool m_bRTLEnabled;
+
+ Rectangle m_aCompleteTextRect;
+ };
+
+ //====================================================================
+ //= ControlTextRenderer
+ //====================================================================
+ ReferenceDeviceTextLayout::ReferenceDeviceTextLayout( const Control& _rControl, OutputDevice& _rTargetDevice,
+ OutputDevice& _rReferenceDevice )
+ :m_rTargetDevice( _rTargetDevice )
+ ,m_rReferenceDevice( _rReferenceDevice )
+ ,m_aUnzoomedPointFont( _rControl.GetUnzoomedControlPointFont() )
+ ,m_aZoom( _rControl.GetZoom() )
+ ,m_bRTLEnabled( _rControl.IsRTLEnabled() )
+ {
+ m_rTargetDevice.Push( PUSH_MAPMODE | PUSH_FONT | PUSH_TEXTLAYOUTMODE );
+
+ MapMode aTargetMapMode( m_rTargetDevice.GetMapMode() );
+ OSL_ENSURE( aTargetMapMode.GetOrigin() == Point(), "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: uhm, the code below won't work here ..." );
+
+ // normally, controls simulate "zoom" by "zooming" the font. This is responsible for (part of) the discrepancies
+ // between text in Writer and text in controls in Writer, though both have the same font.
+ // So, if we have a zoom set at the control, then we do not scale the font, but instead modify the map mode
+ // to accomodate for the zoom.
+ aTargetMapMode.SetScaleX( m_aZoom ); // TODO: shouldn't this be "current_scale * zoom"?
+ aTargetMapMode.SetScaleY( m_aZoom );
+
+ // also, use a higher-resolution map unit than "pixels", which should save us some rounding errors when
+ // translating coordinates between the reference device and the target device.
+ OSL_ENSURE( aTargetMapMode.GetMapUnit() == MAP_PIXEL,
+ "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: this class is not expected to work with such target devices!" );
+ // we *could* adjust all the code in this class to handle this case, but at the moment, it's not necessary
+ const MapUnit eTargetMapUnit = m_rReferenceDevice.GetMapMode().GetMapUnit();
+ aTargetMapMode.SetMapUnit( eTargetMapUnit );
+ OSL_ENSURE( aTargetMapMode.GetMapUnit() != MAP_PIXEL,
+ "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: a reference device which has map mode PIXEL?!" );
+
+ m_rTargetDevice.SetMapMode( aTargetMapMode );
+
+ // now that the Zoom is part of the map mode, reset the target device's font to the "unzoomed" version
+ Font aDrawFont( m_aUnzoomedPointFont );
+ aDrawFont.SetSize( m_rTargetDevice.LogicToLogic( aDrawFont.GetSize(), MAP_POINT, eTargetMapUnit ) );
+ _rTargetDevice.SetFont( aDrawFont );
+
+ // transfer font to the reference device
+ m_rReferenceDevice.Push( PUSH_FONT | PUSH_TEXTLAYOUTMODE );
+ Font aRefFont( m_aUnzoomedPointFont );
+ aRefFont.SetSize( OutputDevice::LogicToLogic(
+ aRefFont.GetSize(), MAP_POINT, m_rReferenceDevice.GetMapMode().GetMapUnit() ) );
+ m_rReferenceDevice.SetFont( aRefFont );
+ }
+
+ //--------------------------------------------------------------------
+ ReferenceDeviceTextLayout::~ReferenceDeviceTextLayout()
+ {
+ m_rReferenceDevice.Pop();
+ m_rTargetDevice.Pop();
+ }
+
+ //--------------------------------------------------------------------
+ namespace
+ {
+ //................................................................
+ bool lcl_normalizeLength( const XubString& _rText, const xub_StrLen _nStartIndex, xub_StrLen& _io_nLength )
+ {
+ xub_StrLen nTextLength = _rText.Len();
+ if ( _nStartIndex > nTextLength )
+ return false;
+ if ( _nStartIndex + _io_nLength > nTextLength )
+ _io_nLength = nTextLength - _nStartIndex;
+ return true;
+ }
+ }
+
+ //--------------------------------------------------------------------
+ long ReferenceDeviceTextLayout::GetTextArray( const XubString& _rText, sal_Int32* _pDXAry, xub_StrLen _nStartIndex,
+ xub_StrLen _nLength ) const
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return 0;
+
+ // retrieve the character widths from the reference device
+ long nTextWidth = m_rReferenceDevice.GetTextArray( _rText, _pDXAry, _nStartIndex, _nLength );
+#if OSL_DEBUG_LEVEL > 1
+ if ( _pDXAry )
+ {
+ ::rtl::OStringBuffer aTrace;
+ aTrace.append( "ReferenceDeviceTextLayout::GetTextArray( " );
+ aTrace.append( ::rtl::OUStringToOString( _rText, RTL_TEXTENCODING_UTF8 ) );
+ aTrace.append( " ): " );
+ aTrace.append( nTextWidth );
+ aTrace.append( " = ( " );
+ for ( size_t i=0; i<_nLength; )
+ {
+ aTrace.append( _pDXAry[i] );
+ if ( ++i < _nLength )
+ aTrace.append( ", " );
+ }
+ aTrace.append( ")" );
+ OSL_TRACE( aTrace.makeStringAndClear().getStr() );
+ }
+#endif
+ return nTextWidth;
+ }
+
+ //--------------------------------------------------------------------
+ long ReferenceDeviceTextLayout::GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return GetTextArray( _rText, NULL, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ void ReferenceDeviceTextLayout::DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText )
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return;
+
+ if ( _pVector && _pDisplayText )
+ {
+ MetricVector aGlyphBounds;
+ m_rReferenceDevice.GetGlyphBoundRects( _rStartPoint, _rText, _nStartIndex, _nLength, _nStartIndex, aGlyphBounds );
+ ::std::copy(
+ aGlyphBounds.begin(), aGlyphBounds.end(),
+ ::std::insert_iterator< MetricVector > ( *_pVector, _pVector->end() ) );
+ _pDisplayText->Append( _rText.Copy( _nStartIndex, _nLength ) );
+ return;
+ }
+
+ sal_Int32* pCharWidths = new sal_Int32[ _nLength ];
+ long nTextWidth = GetTextArray( _rText, pCharWidths, _nStartIndex, _nLength );
+ m_rTargetDevice.DrawTextArray( _rStartPoint, _rText, pCharWidths, _nStartIndex, _nLength );
+ delete[] pCharWidths;
+
+ m_aCompleteTextRect.Union( Rectangle( _rStartPoint, Size( nTextWidth, m_rTargetDevice.GetTextHeight() ) ) );
+ }
+
+ //--------------------------------------------------------------------
+ bool ReferenceDeviceTextLayout::GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray,
+ xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return false;
+
+ // retrieve the caret positions from the reference device
+ if ( !m_rReferenceDevice.GetCaretPositions( _rText, _pCaretXArray, _nStartIndex, _nLength ) )
+ return false;
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ xub_StrLen ReferenceDeviceTextLayout::GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return 0;
+
+ return m_rReferenceDevice.GetTextBreak( _rText, _nMaxTextWidth, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ bool ReferenceDeviceTextLayout::DecomposeTextRectAction() const
+ {
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ namespace
+ {
+ long zoomBy( long _value, const Fraction& _zoom )
+ {
+ double n = (double)_value;
+ n *= (double)_zoom.GetNumerator();
+ n /= (double)_zoom.GetDenominator();
+ return (long)::rtl::math::round( n );
+ }
+ long unzoomBy( long _value, const Fraction& _zoom )
+ {
+ return zoomBy( _value, Fraction( _zoom.GetDenominator(), _zoom.GetNumerator() ) );
+ }
+ }
+
+ //--------------------------------------------------------------------
+ Rectangle ReferenceDeviceTextLayout::DrawText( const Rectangle& _rRect, const XubString& _rText, USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText )
+ {
+ if ( !_rText.Len() )
+ return Rectangle();
+
+ // determine text layout mode from the RTL-ness of the control whose text we render
+ ULONG nTextLayoutMode = m_bRTLEnabled ? TEXT_LAYOUT_BIDI_RTL : TEXT_LAYOUT_BIDI_LTR;
+ m_rReferenceDevice.SetLayoutMode( nTextLayoutMode );
+ m_rTargetDevice.SetLayoutMode( nTextLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
+ // TEXT_LAYOUT_TEXTORIGIN_LEFT is because when we do actually draw the text (in DrawText( Point, ... )), then
+ // our caller gives us the left border of the draw position, regardless of script type, text layout,
+ // and the like
+
+ // in our ctor, we set the map mode of the target device from pixel to twip, but our caller doesn't know this,
+ // but passed pixel coordinates. So, adjust the rect.
+ Rectangle aRect( m_rTargetDevice.PixelToLogic( _rRect ) );
+
+ onBeginDrawText();
+ m_rTargetDevice.DrawText( aRect, _rText, _nStyle, _pVector, _pDisplayText, this );
+ Rectangle aTextRect = onEndDrawText();
+
+ if ( aTextRect.IsEmpty() && !aRect.IsEmpty() )
+ {
+ // this happens for instance if we're in a PaintToDevice call, where only a MetaFile is recorded,
+ // but no actual painting happens, so our "DrawText( Point, ... )" is never called
+ // In this case, calculate the rect from what OutputDevice::GetTextRect would give us. This has
+ // the disadvantage of less accuracy, compared with the approach to calculate the rect from the
+ // single "DrawText( Point, ... )" calls, since more intermediate arithmetics will translate
+ // from ref- to target-units.
+ aTextRect = m_rTargetDevice.GetTextRect( aRect, _rText, _nStyle, NULL, this );
+ }
+
+ // similar to above, the text rect now contains TWIPs (or whatever unit the ref device has), but the caller
+ // expects pixel coordinates
+ aTextRect = m_rTargetDevice.LogicToPixel( aTextRect );
+
+ // convert the metric vector
+ if ( _pVector )
+ {
+ for ( MetricVector::iterator charRect = _pVector->begin();
+ charRect != _pVector->end();
+ ++charRect
+ )
+ {
+ *charRect = m_rTargetDevice.LogicToPixel( *charRect );
+ }
+ }
+
+ return aTextRect;
+ }
+
+ //====================================================================
+ //= ControlTextRenderer
+ //====================================================================
+ //--------------------------------------------------------------------
+ ControlTextRenderer::ControlTextRenderer( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice )
+ :m_pImpl( new ReferenceDeviceTextLayout( _rControl, _rTargetDevice, _rReferenceDevice ) )
+ {
+ }
+
+ //--------------------------------------------------------------------
+ ControlTextRenderer::~ControlTextRenderer()
+ {
+ }
+
+ //--------------------------------------------------------------------
+ Rectangle ControlTextRenderer::DrawText( const Rectangle& _rRect, const XubString& _rText, USHORT _nStyle,
+ MetricVector* _pVector, String* _pDisplayText )
+ {
+ return m_pImpl->DrawText( _rRect, _rText, _nStyle, _pVector, _pDisplayText );
+ }
+
+//........................................................................
+} // namespace vcl
+//........................................................................
diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx
new file mode 100644
index 000000000000..4c1439ffe6f4
--- /dev/null
+++ b/vcl/source/gdi/virdev.cxx
@@ -0,0 +1,449 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salinst.hxx>
+#include <vcl/salgdi.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/salvd.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/outdev.h>
+#include <vcl/virdev.hxx>
+
+using namespace ::com::sun::star::uno;
+
+// =======================================================================
+
+void VirtualDevice::ImplInitVirDev( const OutputDevice* pOutDev,
+ long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData )
+{
+ DBG_ASSERT( nBitCount <= 1,
+ "VirtualDevice::VirtualDevice(): Only 0 or 1 is for BitCount allowed" );
+
+ if ( nDX < 1 )
+ nDX = 1;
+
+ if ( nDY < 1 )
+ nDY = 1;
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( !pOutDev )
+ pOutDev = ImplGetDefaultWindow();
+ if( !pOutDev )
+ return;
+
+ SalGraphics* pGraphics;
+ if ( !pOutDev->mpGraphics )
+ ((OutputDevice*)pOutDev)->ImplGetGraphics();
+ pGraphics = pOutDev->mpGraphics;
+ if ( pGraphics )
+ mpVirDev = pSVData->mpDefInst->CreateVirtualDevice( pGraphics, nDX, nDY, nBitCount, pData );
+ else
+ mpVirDev = NULL;
+ if ( !mpVirDev )
+ {
+ // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario)
+ throw ::com::sun::star::uno::RuntimeException(
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Could not create system bitmap!" ) ),
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+ //GetpApp()->Exception( EXC_SYSOBJNOTCREATED );
+ }
+
+ mnBitCount = ( nBitCount ? nBitCount : pOutDev->GetBitCount() );
+ mnOutWidth = nDX;
+ mnOutHeight = nDY;
+ mbScreenComp = TRUE;
+ mnAlphaDepth = -1;
+
+ // #i59315# init vdev size from system object, when passed a
+ // SystemGraphicsData. Otherwise, output size will always
+ // incorrectly stay at (1,1)
+ if( pData && mpVirDev )
+ mpVirDev->GetSize(mnOutWidth,mnOutHeight);
+
+ if( mnBitCount < 8 )
+ SetAntialiasing( ANTIALIASING_DISABLE_TEXT );
+
+ if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER )
+ mbScreenComp = FALSE;
+ else if ( pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
+ mbScreenComp = ((VirtualDevice*)pOutDev)->mbScreenComp;
+
+ meOutDevType = OUTDEV_VIRDEV;
+ mbDevOutput = TRUE;
+ mpFontList = pSVData->maGDIData.mpScreenFontList;
+ mpFontCache = pSVData->maGDIData.mpScreenFontCache;
+ mnDPIX = pOutDev->mnDPIX;
+ mnDPIY = pOutDev->mnDPIY;
+ maFont = pOutDev->maFont;
+
+ if( maTextColor != pOutDev->maTextColor )
+ {
+ maTextColor = pOutDev->maTextColor;
+ mbInitTextColor = true;
+ }
+
+ // Virtuelle Devices haben defaultmaessig einen weissen Hintergrund
+ SetBackground( Wallpaper( Color( COL_WHITE ) ) );
+
+ // #i59283# don't erase user-provided surface
+ if( !pData )
+ Erase();
+
+ // VirDev in Liste eintragen
+ mpNext = pSVData->maGDIData.mpFirstVirDev;
+ mpPrev = NULL;
+ if ( mpNext )
+ mpNext->mpPrev = this;
+ else
+ pSVData->maGDIData.mpLastVirDev = this;
+ pSVData->maGDIData.mpFirstVirDev = this;
+}
+
+// -----------------------------------------------------------------------
+
+VirtualDevice::VirtualDevice( USHORT nBitCount )
+: mpVirDev( NULL ),
+ meRefDevMode( REFDEV_NONE )
+{
+ DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
+
+ ImplInitVirDev( Application::GetDefaultDevice(), 1, 1, nBitCount );
+}
+
+// -----------------------------------------------------------------------
+
+VirtualDevice::VirtualDevice( const OutputDevice& rCompDev, USHORT nBitCount )
+ : mpVirDev( NULL ),
+ meRefDevMode( REFDEV_NONE )
+{
+ DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
+
+ ImplInitVirDev( &rCompDev, 1, 1, nBitCount );
+}
+
+// -----------------------------------------------------------------------
+
+VirtualDevice::VirtualDevice( const OutputDevice& rCompDev, USHORT nBitCount, USHORT nAlphaBitCount )
+ : mpVirDev( NULL ),
+ meRefDevMode( REFDEV_NONE )
+{
+ DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
+
+ ImplInitVirDev( &rCompDev, 1, 1, nBitCount );
+
+ // #110958# Enable alpha channel
+ mnAlphaDepth = sal::static_int_cast<sal_Int8>(nAlphaBitCount);
+}
+
+// -----------------------------------------------------------------------
+
+VirtualDevice::VirtualDevice( const SystemGraphicsData *pData, USHORT nBitCount )
+: mpVirDev( NULL ),
+ meRefDevMode( REFDEV_NONE )
+{
+ DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
+
+ ImplInitVirDev( Application::GetDefaultDevice(), 1, 1, nBitCount, pData );
+}
+
+// -----------------------------------------------------------------------
+
+VirtualDevice::~VirtualDevice()
+{
+ DBG_TRACE( "VirtualDevice::~VirtualDevice()" );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ ImplReleaseGraphics();
+
+ if ( mpVirDev )
+ pSVData->mpDefInst->DestroyVirtualDevice( mpVirDev );
+
+ // remove this VirtualDevice from the double-linked global list
+ if( mpPrev )
+ mpPrev->mpNext = mpNext;
+ else
+ pSVData->maGDIData.mpFirstVirDev = mpNext;
+
+ if( mpNext )
+ mpNext->mpPrev = mpPrev;
+ else
+ pSVData->maGDIData.mpLastVirDev = mpPrev;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL VirtualDevice::ImplSetOutputSizePixel( const Size& rNewSize, BOOL bErase )
+{
+ DBG_TRACE3( "VirtualDevice::ImplSetOutputSizePixel( %ld, %ld, %d )", rNewSize.Width(), rNewSize.Height(), (int)bErase );
+
+ if ( !mpVirDev )
+ return FALSE;
+ else if ( rNewSize == GetOutputSizePixel() )
+ {
+ if ( bErase )
+ Erase();
+ return TRUE;
+ }
+
+ BOOL bRet;
+ long nNewWidth = rNewSize.Width(), nNewHeight = rNewSize.Height();
+
+ if ( nNewWidth < 1 )
+ nNewWidth = 1;
+
+ if ( nNewHeight < 1 )
+ nNewHeight = 1;
+
+ if ( bErase )
+ {
+ bRet = mpVirDev->SetSize( nNewWidth, nNewHeight );
+
+ if ( bRet )
+ {
+ mnOutWidth = rNewSize.Width();
+ mnOutHeight = rNewSize.Height();
+ Erase();
+ }
+ }
+ else
+ {
+ SalVirtualDevice* pNewVirDev;
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return FALSE;
+ }
+
+ pNewVirDev = pSVData->mpDefInst->CreateVirtualDevice( mpGraphics, nNewWidth, nNewHeight, mnBitCount );
+ if ( pNewVirDev )
+ {
+ SalGraphics* pGraphics = pNewVirDev->GetGraphics();
+ if ( pGraphics )
+ {
+ SalTwoRect aPosAry;
+ long nWidth;
+ long nHeight;
+ if ( mnOutWidth < nNewWidth )
+ nWidth = mnOutWidth;
+ else
+ nWidth = nNewWidth;
+ if ( mnOutHeight < nNewHeight )
+ nHeight = mnOutHeight;
+ else
+ nHeight = nNewHeight;
+ aPosAry.mnSrcX = 0;
+ aPosAry.mnSrcY = 0;
+ aPosAry.mnSrcWidth = nWidth;
+ aPosAry.mnSrcHeight = nHeight;
+ aPosAry.mnDestX = 0;
+ aPosAry.mnDestY = 0;
+ aPosAry.mnDestWidth = nWidth;
+ aPosAry.mnDestHeight = nHeight;
+
+ pGraphics->CopyBits( &aPosAry, mpGraphics, this, this );
+ pNewVirDev->ReleaseGraphics( pGraphics );
+ ImplReleaseGraphics();
+ pSVData->mpDefInst->DestroyVirtualDevice( mpVirDev );
+ mpVirDev = pNewVirDev;
+ mnOutWidth = rNewSize.Width();
+ mnOutHeight = rNewSize.Height();
+ bRet = TRUE;
+ }
+ else
+ {
+ bRet = FALSE;
+ pSVData->mpDefInst->DestroyVirtualDevice( pNewVirDev );
+ }
+ }
+ else
+ bRet = FALSE;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+// #i32109#: Fill opaque areas correctly (without relying on
+// fill/linecolor state)
+void VirtualDevice::ImplFillOpaqueRectangle( const Rectangle& rRect )
+{
+ // Set line and fill color to black (->opaque),
+ // fill rect with that (linecolor, too, because of
+ // those pesky missing pixel problems)
+ Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ SetLineColor( COL_BLACK );
+ SetFillColor( COL_BLACK );
+ DrawRect( rRect );
+ Pop();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL VirtualDevice::SetOutputSizePixel( const Size& rNewSize, BOOL bErase )
+{
+ if( ImplSetOutputSizePixel(rNewSize, bErase) )
+ {
+ if( mnAlphaDepth != -1 )
+ {
+ // #110958# Setup alpha bitmap
+ if(mpAlphaVDev && mpAlphaVDev->GetOutputSizePixel() != rNewSize)
+ {
+ delete mpAlphaVDev;
+ mpAlphaVDev = 0L;
+ }
+
+ if( !mpAlphaVDev )
+ {
+ mpAlphaVDev = new VirtualDevice( *this, mnAlphaDepth );
+ mpAlphaVDev->ImplSetOutputSizePixel(rNewSize, bErase);
+ }
+
+ // TODO: copy full outdev state to new one, here. Also needed in outdev2.cxx:DrawOutDev
+ if( GetLineColor() != Color( COL_TRANSPARENT ) )
+ mpAlphaVDev->SetLineColor( COL_BLACK );
+
+ if( GetFillColor() != Color( COL_TRANSPARENT ) )
+ mpAlphaVDev->SetFillColor( COL_BLACK );
+
+ mpAlphaVDev->SetMapMode( GetMapMode() );
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void VirtualDevice::SetReferenceDevice( RefDevMode i_eRefDevMode )
+{
+ sal_Int32 nDPIX = 600, nDPIY = 600;
+ switch( i_eRefDevMode )
+ {
+ case REFDEV_NONE:
+ default:
+ DBG_ASSERT( FALSE, "VDev::SetRefDev illegal argument!" );
+ break;
+ case REFDEV_MODE06:
+ nDPIX = nDPIY = 600;
+ break;
+ case REFDEV_MODE48:
+ nDPIX = nDPIY = 4800;
+ break;
+ case REFDEV_MODE_MSO1:
+ nDPIX = nDPIY = 6*1440;
+ break;
+ case REFDEV_MODE_PDF1:
+ nDPIX = nDPIY = 720;
+ break;
+ }
+ ImplSetReferenceDevice( i_eRefDevMode, nDPIX, nDPIY );
+}
+
+void VirtualDevice::SetReferenceDevice( sal_Int32 i_nDPIX, sal_Int32 i_nDPIY )
+{
+ ImplSetReferenceDevice( REFDEV_CUSTOM, i_nDPIX, i_nDPIY );
+}
+
+void VirtualDevice::ImplSetReferenceDevice( RefDevMode i_eRefDevMode, sal_Int32 i_nDPIX, sal_Int32 i_nDPIY )
+{
+ mnDPIX = i_nDPIX;
+ mnDPIY = i_nDPIY;
+
+ EnableOutput( FALSE ); // prevent output on reference device
+ mbScreenComp = FALSE;
+
+ // invalidate currently selected fonts
+ mbInitFont = TRUE;
+ mbNewFont = TRUE;
+
+ // avoid adjusting font lists when already in refdev mode
+ BYTE nOldRefDevMode = meRefDevMode;
+ BYTE nOldCompatFlag = (BYTE)meRefDevMode & REFDEV_FORCE_ZERO_EXTLEAD;
+ meRefDevMode = (BYTE)(i_eRefDevMode | nOldCompatFlag);
+ if( (nOldRefDevMode ^ nOldCompatFlag) != REFDEV_NONE )
+ return;
+
+ // the reference device should have only scalable fonts
+ // => clean up the original font lists before getting new ones
+ if ( mpFontEntry )
+ {
+ mpFontCache->Release( mpFontEntry );
+ mpFontEntry = NULL;
+ }
+ if ( mpGetDevFontList )
+ {
+ delete mpGetDevFontList;
+ mpGetDevFontList = NULL;
+ }
+ if ( mpGetDevSizeList )
+ {
+ delete mpGetDevSizeList;
+ mpGetDevSizeList = NULL;
+ }
+
+ // preserve global font lists
+ ImplSVData* pSVData = ImplGetSVData();
+ if( mpFontList && (mpFontList != pSVData->maGDIData.mpScreenFontList) )
+ delete mpFontList;
+ if( mpFontCache && (mpFontCache != pSVData->maGDIData.mpScreenFontCache) )
+ delete mpFontCache;
+
+ // get font list with scalable fonts only
+ ImplGetGraphics();
+ mpFontList = pSVData->maGDIData.mpScreenFontList->Clone( true, false );
+
+ // prepare to use new font lists
+ mpFontCache = new ImplFontCache( false );
+}
+
+// -----------------------------------------------------------------------
+
+void VirtualDevice::Compat_ZeroExtleadBug()
+{
+ meRefDevMode = (BYTE)meRefDevMode | REFDEV_FORCE_ZERO_EXTLEAD;
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/source/gdi/wall.cxx b/vcl/source/gdi/wall.cxx
new file mode 100644
index 000000000000..10aa4431f69d
--- /dev/null
+++ b/vcl/source/gdi/wall.cxx
@@ -0,0 +1,639 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/debug.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/wall.hxx>
+#include <vcl/wall2.hxx>
+#include <vcl/svapp.hxx>
+
+
+DBG_NAME( Wallpaper );
+
+// -----------------------------------------------------------------------
+
+ImplWallpaper::ImplWallpaper() :
+ maColor( COL_TRANSPARENT )
+{
+ mnRefCount = 1;
+ mpBitmap = NULL;
+ mpCache = NULL;
+ mpGradient = NULL;
+ mpRect = NULL;
+ meStyle = WALLPAPER_NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplWallpaper::ImplWallpaper( const ImplWallpaper& rImplWallpaper ) :
+ maColor( rImplWallpaper.maColor )
+{
+ mnRefCount = 1;
+ meStyle = rImplWallpaper.meStyle;
+
+ if ( rImplWallpaper.mpBitmap )
+ mpBitmap = new BitmapEx( *rImplWallpaper.mpBitmap );
+ else
+ mpBitmap = NULL;
+ if( rImplWallpaper.mpCache )
+ mpCache = new BitmapEx( *rImplWallpaper.mpCache );
+ else
+ mpCache = NULL;
+ if ( rImplWallpaper.mpGradient )
+ mpGradient = new Gradient( *rImplWallpaper.mpGradient );
+ else
+ mpGradient = NULL;
+ if ( rImplWallpaper.mpRect )
+ mpRect = new Rectangle( *rImplWallpaper.mpRect );
+ else
+ mpRect = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplWallpaper::~ImplWallpaper()
+{
+ delete mpBitmap;
+ delete mpCache;
+ delete mpGradient;
+ delete mpRect;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWallpaper::ImplSetCachedBitmap( BitmapEx& rBmp )
+{
+ if( !mpCache )
+ mpCache = new BitmapEx( rBmp );
+ else
+ *mpCache = rBmp;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWallpaper::ImplReleaseCachedBitmap()
+{
+ delete mpCache;
+ mpCache = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, ImplWallpaper& rImplWallpaper )
+{
+ VersionCompat aCompat( rIStm, STREAM_READ );
+ UINT16 nTmp16;
+
+ delete rImplWallpaper.mpRect;
+ rImplWallpaper.mpRect = NULL;
+
+ delete rImplWallpaper.mpGradient;
+ rImplWallpaper.mpGradient = NULL;
+
+ delete rImplWallpaper.mpBitmap;
+ rImplWallpaper.mpBitmap = NULL;
+
+ // version 1
+ rIStm >> rImplWallpaper.maColor;
+ rIStm >> nTmp16; rImplWallpaper.meStyle = (WallpaperStyle) nTmp16;
+
+ // version 2
+ if( aCompat.GetVersion() >= 2 )
+ {
+ BOOL bRect, bGrad, bBmp, bDummy;
+
+ rIStm >> bRect >> bGrad >> bBmp >> bDummy >> bDummy >> bDummy;
+
+ if( bRect )
+ {
+ rImplWallpaper.mpRect = new Rectangle;
+ rIStm >> *rImplWallpaper.mpRect;
+ }
+
+ if( bGrad )
+ {
+ rImplWallpaper.mpGradient = new Gradient;
+ rIStm >> *rImplWallpaper.mpGradient;
+ }
+
+ if( bBmp )
+ {
+ rImplWallpaper.mpBitmap = new BitmapEx;
+ rIStm >> *rImplWallpaper.mpBitmap;
+ }
+
+ // version 3 (new color format)
+ if( aCompat.GetVersion() >= 3 )
+ {
+ rImplWallpaper.maColor.Read( rIStm, TRUE );
+ }
+ }
+
+ return rIStm;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const ImplWallpaper& rImplWallpaper )
+{
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 3 );
+ BOOL bRect = ( rImplWallpaper.mpRect != NULL );
+ BOOL bGrad = ( rImplWallpaper.mpGradient != NULL );
+ BOOL bBmp = ( rImplWallpaper.mpBitmap != NULL );
+ BOOL bDummy = FALSE;
+
+ // version 1
+ rOStm << rImplWallpaper.maColor << (UINT16) rImplWallpaper.meStyle;
+
+ // version 2
+ rOStm << bRect << bGrad << bBmp << bDummy << bDummy << bDummy;
+
+ if( bRect )
+ rOStm << *rImplWallpaper.mpRect;
+
+ if( bGrad )
+ rOStm << *rImplWallpaper.mpGradient;
+
+ if( bBmp )
+ rOStm << *rImplWallpaper.mpBitmap;
+
+ // version 3 (new color format)
+ ( (Color&) rImplWallpaper.maColor ).Write( rOStm, TRUE );
+
+ return rOStm;
+}
+
+// -----------------------------------------------------------------------
+
+inline void Wallpaper::ImplMakeUnique( BOOL bReleaseCache )
+{
+ // Falls noch andere Referenzen bestehen, dann kopieren
+ if ( mpImplWallpaper->mnRefCount != 1 )
+ {
+ if ( mpImplWallpaper->mnRefCount )
+ mpImplWallpaper->mnRefCount--;
+ mpImplWallpaper = new ImplWallpaper( *(mpImplWallpaper) );
+ }
+
+ if( bReleaseCache )
+ mpImplWallpaper->ImplReleaseCachedBitmap();
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper::Wallpaper()
+{
+ DBG_CTOR( Wallpaper, NULL );
+
+ static ImplWallpaper aStaticImplWallpaper;
+
+ aStaticImplWallpaper.mnRefCount = 0;
+ mpImplWallpaper = &aStaticImplWallpaper;
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper::Wallpaper( const Wallpaper& rWallpaper )
+{
+ DBG_CTOR( Wallpaper, NULL );
+ DBG_CHKOBJ( &rWallpaper, Wallpaper, NULL );
+ DBG_ASSERT( rWallpaper.mpImplWallpaper->mnRefCount < 0xFFFFFFFE, "Wallpaper: RefCount overflow" );
+
+ // Instance Daten uebernehmen und Referenzcounter erhoehen
+ mpImplWallpaper = rWallpaper.mpImplWallpaper;
+ // RefCount == 0 fuer statische Objekte
+ if ( mpImplWallpaper->mnRefCount )
+ mpImplWallpaper->mnRefCount++;
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper::Wallpaper( const Color& rColor )
+{
+ DBG_CTOR( Wallpaper, NULL );
+
+ mpImplWallpaper = new ImplWallpaper;
+ mpImplWallpaper->maColor = rColor;
+ mpImplWallpaper->meStyle = WALLPAPER_TILE;
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper::Wallpaper( const BitmapEx& rBmpEx )
+{
+ DBG_CTOR( Wallpaper, NULL );
+
+ mpImplWallpaper = new ImplWallpaper;
+ mpImplWallpaper->mpBitmap = new BitmapEx( rBmpEx );
+ mpImplWallpaper->meStyle = WALLPAPER_TILE;
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper::Wallpaper( const Gradient& rGradient )
+{
+ DBG_CTOR( Wallpaper, NULL );
+
+ mpImplWallpaper = new ImplWallpaper;
+ mpImplWallpaper->mpGradient = new Gradient( rGradient );
+ mpImplWallpaper->meStyle = WALLPAPER_TILE;
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper::~Wallpaper()
+{
+ DBG_DTOR( Wallpaper, NULL );
+
+ // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpImplWallpaper->mnRefCount )
+ {
+ if ( mpImplWallpaper->mnRefCount == 1 )
+ delete mpImplWallpaper;
+ else
+ mpImplWallpaper->mnRefCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetColor( const Color& rColor )
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ ImplMakeUnique();
+ mpImplWallpaper->maColor = rColor;
+
+ if( WALLPAPER_NULL == mpImplWallpaper->meStyle || WALLPAPER_APPLICATIONGRADIENT == mpImplWallpaper->meStyle )
+ mpImplWallpaper->meStyle = WALLPAPER_TILE;
+}
+
+// -----------------------------------------------------------------------
+
+const Color& Wallpaper::GetColor() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ return mpImplWallpaper->maColor;
+}
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetStyle( WallpaperStyle eStyle )
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ ImplMakeUnique( FALSE );
+
+ if( eStyle == WALLPAPER_APPLICATIONGRADIENT )
+ // set a dummy gradient, the correct gradient
+ // will be created dynamically in GetGradient()
+ SetGradient( ImplGetApplicationGradient() );
+
+ mpImplWallpaper->meStyle = eStyle;
+}
+
+// -----------------------------------------------------------------------
+
+WallpaperStyle Wallpaper::GetStyle() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ return mpImplWallpaper->meStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetBitmap( const BitmapEx& rBitmap )
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ if ( !rBitmap )
+ {
+ if ( mpImplWallpaper->mpBitmap )
+ {
+ ImplMakeUnique();
+ delete mpImplWallpaper->mpBitmap;
+ mpImplWallpaper->mpBitmap = NULL;
+ }
+ }
+ else
+ {
+ ImplMakeUnique();
+ if ( mpImplWallpaper->mpBitmap )
+ *(mpImplWallpaper->mpBitmap) = rBitmap;
+ else
+ mpImplWallpaper->mpBitmap = new BitmapEx( rBitmap );
+ }
+
+ if( WALLPAPER_NULL == mpImplWallpaper->meStyle || WALLPAPER_APPLICATIONGRADIENT == mpImplWallpaper->meStyle)
+ mpImplWallpaper->meStyle = WALLPAPER_TILE;
+}
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetBitmap()
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ if ( mpImplWallpaper->mpBitmap )
+ {
+ ImplMakeUnique();
+ delete mpImplWallpaper->mpBitmap;
+ mpImplWallpaper->mpBitmap = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BitmapEx Wallpaper::GetBitmap() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ if ( mpImplWallpaper->mpBitmap )
+ return *(mpImplWallpaper->mpBitmap);
+ else
+ {
+ BitmapEx aBmp;
+ return aBmp;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Wallpaper::IsBitmap() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ return (mpImplWallpaper->mpBitmap != 0);
+}
+
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetGradient( const Gradient& rGradient )
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ ImplMakeUnique();
+
+ if ( mpImplWallpaper->mpGradient )
+ *(mpImplWallpaper->mpGradient) = rGradient;
+ else
+ mpImplWallpaper->mpGradient = new Gradient( rGradient );
+
+ if( WALLPAPER_NULL == mpImplWallpaper->meStyle || WALLPAPER_APPLICATIONGRADIENT == mpImplWallpaper->meStyle )
+ mpImplWallpaper->meStyle = WALLPAPER_TILE;
+}
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetGradient()
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ if ( mpImplWallpaper->mpGradient )
+ {
+ ImplMakeUnique();
+ delete mpImplWallpaper->mpGradient;
+ mpImplWallpaper->mpGradient = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Gradient Wallpaper::GetGradient() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ if( WALLPAPER_APPLICATIONGRADIENT == mpImplWallpaper->meStyle )
+ return ImplGetApplicationGradient();
+ else if ( mpImplWallpaper->mpGradient )
+ return *(mpImplWallpaper->mpGradient);
+ else
+ {
+ Gradient aGradient;
+ return aGradient;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Wallpaper::IsGradient() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ return (mpImplWallpaper->mpGradient != 0);
+}
+
+
+// -----------------------------------------------------------------------
+
+Gradient Wallpaper::ImplGetApplicationGradient() const
+{
+ Gradient g;
+ g.SetAngle( 900 );
+ g.SetStyle( GRADIENT_LINEAR );
+ g.SetStartColor( Application::GetSettings().GetStyleSettings().GetFaceColor() );
+ // no 'extreme' gradient when high contrast
+ if( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ g.SetEndColor( Application::GetSettings().GetStyleSettings().GetFaceColor() );
+ else
+ g.SetEndColor( Application::GetSettings().GetStyleSettings().GetFaceGradientColor() );
+ return g;
+}
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetRect( const Rectangle& rRect )
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ ImplMakeUnique( FALSE );
+
+ if ( rRect.IsEmpty() )
+ {
+ if ( mpImplWallpaper->mpRect )
+ {
+ delete mpImplWallpaper->mpRect;
+ mpImplWallpaper->mpRect = NULL;
+ }
+ }
+ else
+ {
+ if ( mpImplWallpaper->mpRect )
+ *(mpImplWallpaper->mpRect) = rRect;
+ else
+ mpImplWallpaper->mpRect = new Rectangle( rRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Wallpaper::SetRect()
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ if ( mpImplWallpaper->mpRect )
+ {
+ ImplMakeUnique( FALSE );
+ delete mpImplWallpaper->mpRect;
+ mpImplWallpaper->mpRect = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle Wallpaper::GetRect() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ if ( mpImplWallpaper->mpRect )
+ return *(mpImplWallpaper->mpRect);
+ else
+ {
+ Rectangle aRect;
+ return aRect;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Wallpaper::IsRect() const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+
+ return (mpImplWallpaper->mpRect != 0);
+}
+
+
+// -----------------------------------------------------------------------
+
+BOOL Wallpaper::IsFixed() const
+{
+ if ( mpImplWallpaper->meStyle == WALLPAPER_NULL )
+ return FALSE;
+ else
+ return (!mpImplWallpaper->mpBitmap && !mpImplWallpaper->mpGradient);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Wallpaper::IsScrollable() const
+{
+ if ( mpImplWallpaper->meStyle == WALLPAPER_NULL )
+ return FALSE;
+ else if ( !mpImplWallpaper->mpBitmap && !mpImplWallpaper->mpGradient )
+ return TRUE;
+ else if ( mpImplWallpaper->mpBitmap )
+ return (mpImplWallpaper->meStyle == WALLPAPER_TILE);
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper& Wallpaper::operator=( const Wallpaper& rWallpaper )
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+ DBG_CHKOBJ( &rWallpaper, Wallpaper, NULL );
+ DBG_ASSERT( rWallpaper.mpImplWallpaper->mnRefCount < 0xFFFFFFFE, "Wallpaper: RefCount overflow" );
+
+ // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
+ if ( rWallpaper.mpImplWallpaper->mnRefCount )
+ rWallpaper.mpImplWallpaper->mnRefCount++;
+
+ // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
+ // die letzte Referenz ist, sonst Referenzcounter decrementieren
+ if ( mpImplWallpaper->mnRefCount )
+ {
+ if ( mpImplWallpaper->mnRefCount == 1 )
+ delete mpImplWallpaper;
+ else
+ mpImplWallpaper->mnRefCount--;
+ }
+
+ mpImplWallpaper = rWallpaper.mpImplWallpaper;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Wallpaper::operator==( const Wallpaper& rWallpaper ) const
+{
+ DBG_CHKTHIS( Wallpaper, NULL );
+ DBG_CHKOBJ( &rWallpaper, Wallpaper, NULL );
+
+ if ( mpImplWallpaper == rWallpaper.mpImplWallpaper )
+ return TRUE;
+
+ if ( ( mpImplWallpaper->meStyle != rWallpaper.mpImplWallpaper->meStyle ) ||
+ ( mpImplWallpaper->maColor != rWallpaper.mpImplWallpaper->maColor ) )
+ return FALSE;
+
+ if ( mpImplWallpaper->mpRect != rWallpaper.mpImplWallpaper->mpRect
+ && ( !mpImplWallpaper->mpRect
+ || !rWallpaper.mpImplWallpaper->mpRect
+ || *(mpImplWallpaper->mpRect) != *(rWallpaper.mpImplWallpaper->mpRect) ) )
+ return FALSE;
+
+ if ( mpImplWallpaper->mpBitmap != rWallpaper.mpImplWallpaper->mpBitmap
+ && ( !mpImplWallpaper->mpBitmap
+ || !rWallpaper.mpImplWallpaper->mpBitmap
+ || *(mpImplWallpaper->mpBitmap) != *(rWallpaper.mpImplWallpaper->mpBitmap) ) )
+ return FALSE;
+
+ if ( mpImplWallpaper->mpGradient != rWallpaper.mpImplWallpaper->mpGradient
+ && ( !mpImplWallpaper->mpGradient
+ || !rWallpaper.mpImplWallpaper->mpGradient
+ || *(mpImplWallpaper->mpGradient) != *(rWallpaper.mpImplWallpaper->mpGradient) ) )
+ return FALSE;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator>>( SvStream& rIStm, Wallpaper& rWallpaper )
+{
+ rWallpaper.ImplMakeUnique();
+ return( rIStm >> *rWallpaper.mpImplWallpaper );
+}
+
+// -----------------------------------------------------------------------
+
+SvStream& operator<<( SvStream& rOStm, const Wallpaper& rWallpaper )
+{
+ return( rOStm << *rWallpaper.mpImplWallpaper );
+}
diff --git a/vcl/source/glyphs/gcach_ftyp.cxx b/vcl/source/glyphs/gcach_ftyp.cxx
new file mode 100644
index 000000000000..ebdd59f517af
--- /dev/null
+++ b/vcl/source/glyphs/gcach_ftyp.cxx
@@ -0,0 +1,2557 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifdef WNT
+#include <svsys.h>
+#undef CreateFont
+#endif
+
+#include "gcach_ftyp.hxx"
+
+#include "vcl/svapp.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/impfont.hxx"
+
+#include "tools/poly.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+
+#include "osl/file.hxx"
+#include "osl/thread.hxx"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_TRUETYPE_IDS_H
+
+#ifndef FT_RENDER_MODE_MONO // happens in the MACOSX build
+ #define FT_RENDER_MODE_MONO ft_render_mode_mono
+#endif
+#include "rtl/instance.hxx"
+
+#ifndef FREETYPE_PATCH
+ // VERSION_MINOR in freetype.h is too coarse
+ // if patch-level is not available we need to fine-tune the version ourselves
+ #define FTVERSION 2005
+#else
+ #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH)
+#endif
+#if FTVERSION >= 2200
+typedef const FT_Vector* FT_Vector_CPtr;
+#else // FTVERSION < 2200
+typedef FT_Vector* FT_Vector_CPtr;
+#endif
+
+#include <vector>
+
+// TODO: move file mapping stuff to OSL
+#if defined(UNX)
+ #if !defined(HPUX)
+ // PORTERS: dlfcn is used for getting symbols from FT versions newer than baseline
+ #include <dlfcn.h>
+ #endif
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <sys/mman.h>
+ #include "vcl/fontmanager.hxx"
+#elif defined(WNT)
+ #include <io.h>
+ #define strncasecmp strnicmp
+#endif
+
+typedef const unsigned char* CPU8;
+inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; }
+inline sal_Int16 NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(p); }
+inline sal_uInt32 NEXT_U32( CPU8& p ) { p+=4; return (p[-4]<<24)|(p[-3]<<16)|(p[-2]<<8)|p[-1]; }
+//inline sal_Int32 NEXT_S32( U8*& p ) { return (sal_Int32)NEXT_U32(p); }
+
+// -----------------------------------------------------------------------
+
+// the gamma table makes artificial bold look better for CJK glyphs
+static unsigned char aGammaTable[257];
+
+static void InitGammaTable()
+{
+ static const int M_MAX = 255;
+ static const int M_X = 128;
+ static const int M_Y = 208;
+
+ int x, a;
+ for( x = 0; x < 256; x++)
+ {
+ if ( x <= M_X )
+ a = ( x * M_Y + M_X / 2) / M_X;
+ else
+ a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
+ ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
+
+ aGammaTable[x] = (unsigned char)a;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static FT_Library aLibFT = 0;
+
+// #110607# enable linking with old FT versions
+static int nFTVERSION = 0;
+static FT_Error (*pFTNewSize)(FT_Face,FT_Size*);
+static FT_Error (*pFTActivateSize)(FT_Size);
+static FT_Error (*pFTDoneSize)(FT_Size);
+FT_Error (*pFTEmbolden)(FT_GlyphSlot);
+FT_Error (*pFTOblique)(FT_GlyphSlot);
+static bool bEnableSizeFT = false;
+
+struct EqStr{ bool operator()(const char* a, const char* b) const { return !strcmp(a,b); } };
+typedef ::std::hash_map<const char*,FtFontFile*,::std::hash<const char*>, EqStr> FontFileList;
+namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; }
+
+// -----------------------------------------------------------------------
+
+// TODO: remove when the priorities are selected by UI
+// if (AH==0) => disable autohinting
+// if (AA==0) => disable antialiasing
+// if (EB==0) => disable embedded bitmaps
+// if (AA prio <= AH prio) => antialias + autohint
+// if (AH<AA) => do not autohint when antialiasing
+// if (EB<AH) => do not autohint for monochrome
+static int nDefaultPrioEmbedded = 2;
+static int nDefaultPrioAutoHint = 1;
+static int nDefaultPrioAntiAlias = 1;
+
+// =======================================================================
+// FreetypeManager
+// =======================================================================
+
+FtFontFile::FtFontFile( const ::rtl::OString& rNativeFileName )
+: maNativeFileName( rNativeFileName ),
+ mpFileMap( NULL ),
+ mnFileSize( 0 ),
+ mnRefCount( 0 ),
+ mnLangBoost( 0 )
+{
+ // boost font preference if UI language is mentioned in filename
+ int nPos = maNativeFileName.lastIndexOf( '_' );
+ if( nPos == -1 || maNativeFileName[nPos+1] == '.' )
+ mnLangBoost += 0x1000; // no langinfo => good
+ else
+ {
+ static const char* pLangBoost = NULL;
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ LanguageType aLang = Application::GetSettings().GetUILanguage();
+ switch( aLang )
+ {
+ case LANGUAGE_JAPANESE:
+ pLangBoost = "jan";
+ break;
+ case LANGUAGE_CHINESE:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ pLangBoost = "zhs";
+ break;
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_MACAU:
+ pLangBoost = "zht";
+ break;
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ pLangBoost = "kor";
+ break;
+ }
+ }
+
+ if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) )
+ mnLangBoost += 0x2000; // matching langinfo => better
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FtFontFile* FtFontFile::FindFontFile( const ::rtl::OString& rNativeFileName )
+{
+ // font file already known? (e.g. for ttc, synthetic, aliased fonts)
+ const char* pFileName = rNativeFileName.getStr();
+ FontFileList &rFontFileList = vclFontFileList::get();
+ FontFileList::const_iterator it = rFontFileList.find( pFileName );
+ if( it != rFontFileList.end() )
+ return (*it).second;
+
+ // no => create new one
+ FtFontFile* pFontFile = new FtFontFile( rNativeFileName );
+ pFileName = pFontFile->maNativeFileName.getStr();
+ rFontFileList[ pFileName ] = pFontFile;
+ return pFontFile;
+}
+
+// -----------------------------------------------------------------------
+
+bool FtFontFile::Map()
+{
+ if( mnRefCount++ <= 0 )
+ {
+ const char* pFileName = maNativeFileName.getStr();
+#if defined(UNX)
+ int nFile = open( pFileName, O_RDONLY );
+ if( nFile < 0 )
+ return false;
+
+ struct stat aStat;
+ fstat( nFile, &aStat );
+ mnFileSize = aStat.st_size;
+ mpFileMap = (const unsigned char*)
+ mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 );
+ if( mpFileMap == MAP_FAILED )
+ mpFileMap = NULL;
+ close( nFile );
+#elif defined(WNT)
+ void* pFileDesc = ::CreateFile( pFileName, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
+ if( pFileDesc == INVALID_HANDLE_VALUE)
+ return false;
+
+ mnFileSize = ::GetFileSize( pFileDesc, NULL );
+ HANDLE aHandle = ::CreateFileMapping( pFileDesc, NULL, PAGE_READONLY, 0, mnFileSize, "TTF" );
+ mpFileMap = (const unsigned char*)::MapViewOfFile( aHandle, FILE_MAP_READ, 0, 0, mnFileSize );
+ ::CloseHandle( pFileDesc );
+#else
+ FILE* pFile = fopen( pFileName, "rb" );
+ if( !pFile )
+ return false;
+
+ struct stat aStat;
+ stat( pFileName, &aStat );
+ mnFileSize = aStat.st_size;
+ mpFileMap = new unsigned char[ mnFileSize ];
+ if( mnFileSize != fread( mpFileMap, 1, mnFileSize, pFile ) )
+ {
+ delete[] mpFileMap;
+ mpFileMap = NULL;
+ }
+ fclose( pFile );
+#endif
+ }
+
+ return (mpFileMap != NULL);
+}
+
+// -----------------------------------------------------------------------
+
+void FtFontFile::Unmap()
+{
+ if( (--mnRefCount > 0) || (mpFileMap == NULL) )
+ return;
+
+#if defined(UNX)
+ munmap( (char*)mpFileMap, mnFileSize );
+#elif defined(WNT)
+ UnmapViewOfFile( (LPCVOID)mpFileMap );
+#else
+ delete[] mpFileMap;
+#endif
+
+ mpFileMap = NULL;
+}
+
+// =======================================================================
+
+FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes,
+ const ::rtl::OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic,
+ const ExtraKernInfo* pExtraKernInfo )
+:
+ maFaceFT( NULL ),
+ mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ),
+ mnFaceNum( nFaceNum ),
+ mnRefCount( 0 ),
+ mnSynthetic( nSynthetic ),
+ mnFontId( nFontId ),
+ maDevFontAttributes( rDevFontAttributes ),
+ mpChar2Glyph( NULL ),
+ mpGlyph2Char( NULL ),
+ mpExtraKernInfo( pExtraKernInfo )
+{
+ // prefer font with low ID
+ maDevFontAttributes.mnQuality += 10000 - nFontId;
+ // prefer font with matching file names
+ maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost();
+ // prefer font with more external info
+ if( pExtraKernInfo )
+ maDevFontAttributes.mnQuality += 100;
+}
+
+// -----------------------------------------------------------------------
+
+FtFontInfo::~FtFontInfo()
+{
+ delete mpExtraKernInfo;
+ delete mpChar2Glyph;
+ delete mpGlyph2Char;
+}
+
+void FtFontInfo::InitHashes() const
+{
+ // TODO: avoid pointers when empty stl::hash_* objects become cheap
+ mpChar2Glyph = new Int2IntMap();
+ mpGlyph2Char = new Int2IntMap();
+}
+
+// -----------------------------------------------------------------------
+
+FT_FaceRec_* FtFontInfo::GetFaceFT()
+{
+ // get faceFT once/multiple depending on availability of SizeFT APIs
+ if( (mnRefCount++ <= 0) || !bEnableSizeFT )
+ {
+ if( !mpFontFile->Map() )
+ return NULL;
+ FT_Error rc = FT_New_Memory_Face( aLibFT,
+ (FT_Byte*)mpFontFile->GetBuffer(),
+ mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT );
+ if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) )
+ maFaceFT = NULL;
+ }
+
+ return maFaceFT;
+}
+
+// -----------------------------------------------------------------------
+
+void FtFontInfo::ReleaseFaceFT( FT_FaceRec_* pFaceFT )
+{
+ // release last/each depending on SizeFT availability
+ if( (--mnRefCount <= 0) || !bEnableSizeFT )
+ {
+ FT_Done_Face( pFaceFT );
+ maFaceFT = NULL;
+ mpFontFile->Unmap();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool FtFontInfo::HasExtraKerning() const
+{
+ if( !mpExtraKernInfo )
+ return false;
+ // TODO: how to enable the line below without getting #i29881# back?
+ // on the other hand being to optimistic doesn't cause problems
+ // return mpExtraKernInfo->HasKernPairs();
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const
+{
+ if( !mpExtraKernInfo )
+ return 0;
+ return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs );
+}
+
+// -----------------------------------------------------------------------
+
+int FtFontInfo::GetExtraGlyphKernValue( int nLeftGlyph, int nRightGlyph ) const
+{
+ if( !mpExtraKernInfo )
+ return 0;
+ if( !mpGlyph2Char )
+ return 0;
+ sal_Unicode cLeftChar = (*mpGlyph2Char)[ nLeftGlyph ];
+ sal_Unicode cRightChar = (*mpGlyph2Char)[ nRightGlyph ];
+ return mpExtraKernInfo->GetUnscaledKernValue( cLeftChar, cRightChar );
+}
+
+// -----------------------------------------------------------------------
+
+static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
+static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
+//static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
+
+// -----------------------------------------------------------------------
+
+const unsigned char* FtFontInfo::GetTable( const char* pTag, ULONG* pLength ) const
+{
+ const unsigned char* pBuffer = mpFontFile->GetBuffer();
+ int nFileSize = mpFontFile->GetFileSize();
+ if( !pBuffer || nFileSize<1024 )
+ return NULL;
+
+ // we currently only handle TTF and TTC headers
+ unsigned nFormat = GetUInt( pBuffer );
+ const unsigned char* p = pBuffer + 12;
+ if( nFormat == 0x74746366 ) // TTC_MAGIC
+ p += GetUInt( p + 4 * mnFaceNum );
+ else if( (nFormat!=0x00010000) && (nFormat!=0x74727565) ) // TTF_MAGIC and Apple TTF Magic
+ return NULL;
+
+ // walk table directory until match
+ int nTables = GetUShort( p - 8 );
+ if( nTables >= 64 ) // something fishy?
+ return NULL;
+ for( int i = 0; i < nTables; ++i, p+=16 )
+ {
+ if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] )
+ {
+ ULONG nLength = GetUInt( p + 12 );
+ if( pLength != NULL )
+ *pLength = nLength;
+ const unsigned char* pTable = pBuffer + GetUInt( p + 8 );
+ if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) )
+ return pTable;
+ }
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList )
+{
+ ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
+ pFontList->Add( pFD );
+}
+
+// =======================================================================
+
+FreetypeManager::FreetypeManager()
+: mnMaxFontId( 0 ), mnNextFontId( 0x1000 )
+{
+ /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT );
+
+#ifdef RTLD_DEFAULT // true if a good dlfcn.h header was included
+ // Get version of freetype library to enable workarounds.
+ // Freetype <= 2.0.9 does not have FT_Library_Version().
+ // Using dl_sym() instead of osl_getSymbol() because latter
+ // isn't designed to work with oslModule=NULL
+ void (*pFTLibraryVersion)(FT_Library library,
+ FT_Int *amajor, FT_Int *aminor, FT_Int *apatch);
+ pFTLibraryVersion = (void (*)(FT_Library library,
+ FT_Int *amajor, FT_Int *aminor, FT_Int *apatch))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Library_Version" );
+
+ pFTNewSize = (FT_Error(*)(FT_Face,FT_Size*))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_New_Size" );
+ pFTActivateSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Activate_Size" );
+ pFTDoneSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Done_Size" );
+ pFTEmbolden = (FT_Error(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Embolden" );
+ pFTOblique = (FT_Error(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Oblique" );
+
+ bEnableSizeFT = (pFTNewSize!=NULL) && (pFTActivateSize!=NULL) && (pFTDoneSize!=NULL);
+
+ FT_Int nMajor = 0, nMinor = 0, nPatch = 0;
+ if( pFTLibraryVersion )
+ pFTLibraryVersion( aLibFT, &nMajor, &nMinor, &nPatch );
+ nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch;
+
+ // disable embedded bitmaps for Freetype-2.1.3 unless explicitly
+ // requested by env var below because it crashes StarOffice on RH9
+ // reason: double free in freetype's embedded bitmap handling
+ if( nFTVERSION == 2103 )
+ nDefaultPrioEmbedded = 0;
+ // disable artificial emboldening with the Freetype API for older versions
+ if( nFTVERSION < 2110 )
+ pFTEmbolden = NULL;
+
+#else // RTLD_DEFAULT
+ // assume systems where dlsym is not possible use supplied library
+ nFTVERSION = FTVERSION;
+#endif
+
+ // TODO: remove when the priorities are selected by UI
+ char* pEnv;
+ pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
+ if( pEnv )
+ nDefaultPrioEmbedded = pEnv[0] - '0';
+ pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
+ if( pEnv )
+ nDefaultPrioAntiAlias = pEnv[0] - '0';
+ pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" );
+ if( pEnv )
+ nDefaultPrioAutoHint = pEnv[0] - '0';
+
+ InitGammaTable();
+}
+
+// -----------------------------------------------------------------------
+
+void* FreetypeServerFont::GetFtFace() const
+{
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ return maFaceFT;
+}
+
+// -----------------------------------------------------------------------
+
+FreetypeManager::~FreetypeManager()
+{
+// This crashes on Solaris 10
+// TODO: check which versions have this problem
+//
+// FT_Error rcFT = FT_Done_FreeType( aLibFT );
+}
+
+// -----------------------------------------------------------------------
+
+void FreetypeManager::AddFontFile( const rtl::OString& rNormalizedName,
+ int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr,
+ const ExtraKernInfo* pExtraKernInfo )
+{
+ if( !rNormalizedName.getLength() )
+ return;
+
+ if( maFontList.find( nFontId ) != maFontList.end() )
+ return;
+
+ FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr,
+ rNormalizedName, nFaceNum, nFontId, 0, pExtraKernInfo );
+ maFontList[ nFontId ] = pFontInfo;
+ if( mnMaxFontId < nFontId )
+ mnMaxFontId = nFontId;
+}
+
+// -----------------------------------------------------------------------
+
+long FreetypeManager::AddFontDir( const String& rUrlName )
+{
+ osl::Directory aDir( rUrlName );
+ osl::FileBase::RC rcOSL = aDir.open();
+ if( rcOSL != osl::FileBase::E_None )
+ return 0;
+
+ long nCount = 0;
+
+ osl::DirectoryItem aDirItem;
+ rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
+ while( (rcOSL = aDir.getNextItem( aDirItem, 20 )) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aFileStatus( FileStatusMask_FileURL );
+ rcOSL = aDirItem.getFileStatus( aFileStatus );
+
+ ::rtl::OUString aUSytemPath;
+ OSL_VERIFY( osl::FileBase::E_None
+ == osl::FileBase::getSystemPathFromFileURL( aFileStatus.getFileURL(), aUSytemPath ));
+ ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
+ const char* pszFontFileName = aCFileName.getStr();
+
+ FT_FaceRec_* aFaceFT = NULL;
+ for( int nFaceNum = 0, nMaxFaces = 1; nFaceNum < nMaxFaces; ++nFaceNum )
+ {
+ FT_Error rcFT = FT_New_Face( aLibFT, pszFontFileName, nFaceNum, &aFaceFT );
+ if( (rcFT != FT_Err_Ok) || (aFaceFT == NULL) )
+ break;
+
+ if( !FT_IS_SCALABLE( aFaceFT ) ) // ignore non-scalabale fonts
+ continue;
+
+ nMaxFaces = aFaceFT->num_faces;
+
+ ImplDevFontAttributes aDFA;
+
+ // TODO: prefer unicode names if available
+ // TODO: prefer locale specific names if available?
+ if ( aFaceFT->family_name )
+ aDFA.maName = String::CreateFromAscii( aFaceFT->family_name );
+
+ if ( aFaceFT->style_name )
+ aDFA.maStyleName = String::CreateFromAscii( aFaceFT->style_name );
+
+ aDFA.mbSymbolFlag = false;
+ for( int i = aFaceFT->num_charmaps; --i >= 0; )
+ {
+ const FT_CharMap aCM = aFaceFT->charmaps[i];
+#if (FTVERSION < 2000)
+ if( aCM->encoding == FT_ENCODING_NONE )
+#else
+ if( (aCM->platform_id == TT_PLATFORM_MICROSOFT)
+ && (aCM->encoding_id == TT_MS_ID_SYMBOL_CS) )
+#endif
+ aDFA.mbSymbolFlag = true;
+ }
+
+ // TODO: extract better font characterization data from font
+ aDFA.meFamily = FAMILY_DONTKNOW;
+ aDFA.mePitch = FT_IS_FIXED_WIDTH( aFaceFT ) ? PITCH_FIXED : PITCH_VARIABLE;
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = FT_STYLE_FLAG_BOLD & aFaceFT->style_flags ? WEIGHT_BOLD : WEIGHT_NORMAL;
+ aDFA.meItalic = FT_STYLE_FLAG_ITALIC & aFaceFT->style_flags ? ITALIC_NORMAL : ITALIC_NONE;
+
+ aDFA.mnQuality = 0;
+ aDFA.mbOrientation= true;
+ aDFA.mbDevice = true;
+ aDFA.mbSubsettable= false;
+ aDFA.mbEmbeddable = false;
+
+ FT_Done_Face( aFaceFT );
+ AddFontFile( aCFileName, nFaceNum, ++mnNextFontId, aDFA, NULL );
+ ++nCount;
+ }
+ }
+
+ aDir.close();
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void FreetypeManager::AnnounceFonts( ImplDevFontList* pToAdd ) const
+{
+ for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
+ {
+ FtFontInfo* pFtFontInfo = it->second;
+ pFtFontInfo->AnnounceFont( pToAdd );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FreetypeManager::ClearFontList( )
+{
+ for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
+ {
+ FtFontInfo* pFtFontInfo = it->second;
+ delete pFtFontInfo;
+ }
+ maFontList.clear();
+}
+
+// -----------------------------------------------------------------------
+
+FreetypeServerFont* FreetypeManager::CreateFont( const ImplFontSelectData& rFSD )
+{
+ FtFontInfo* pFontInfo = NULL;
+
+ // find a FontInfo matching to the font id
+ sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData );
+ FontList::iterator it = maFontList.find( nFontId );
+ if( it != maFontList.end() )
+ pFontInfo = it->second;
+
+ if( !pFontInfo )
+ return NULL;
+
+ FreetypeServerFont* pNew = new FreetypeServerFont( rFSD, pFontInfo );
+
+ return pNew;
+}
+
+// =======================================================================
+
+ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA )
+: ImplFontData( rDFA, IFTSFONT_MAGIC ),
+ mpFtFontInfo( pFI )
+{
+ mbDevice = false;
+ mbOrientation = true;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplFTSFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
+ return pEntry;
+}
+
+// =======================================================================
+// FreetypeServerFont
+// =======================================================================
+
+FreetypeServerFont::FreetypeServerFont( const ImplFontSelectData& rFSD, FtFontInfo* pFI )
+: ServerFont( rFSD ),
+ mnPrioEmbedded(nDefaultPrioEmbedded),
+ mnPrioAntiAlias(nDefaultPrioAntiAlias),
+ mnPrioAutoHint(nDefaultPrioAutoHint),
+ mpFontInfo( pFI ),
+ maFaceFT( NULL ),
+ maSizeFT( NULL ),
+ mbFaceOk( false ),
+ maRecodeConverter( NULL ),
+ mpLayoutEngine( NULL )
+{
+ maFaceFT = pFI->GetFaceFT();
+
+#ifdef HDU_DEBUG
+ fprintf( stderr, "FTSF::FTSF(\"%s\", h=%d, w=%d, sy=%d) => %d\n",
+ pFI->GetFontFileName()->getStr(), rFSD.mnHeight, rFSD.mnWidth, pFI->IsSymbolFont(), maFaceFT!=0 );
+#endif
+
+ if( !maFaceFT )
+ return;
+
+ // set the pixel size of the font instance
+ mnWidth = rFSD.mnWidth;
+ if( !mnWidth )
+ mnWidth = rFSD.mnHeight;
+ mfStretch = (double)mnWidth / rFSD.mnHeight;
+ // sanity check (e.g. #i66394#, #i66244#, #66537#)
+ if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) )
+ return;
+
+ // perf: use maSizeFT if available
+ if( bEnableSizeFT )
+ {
+ pFTNewSize( maFaceFT, &maSizeFT );
+ pFTActivateSize( maSizeFT );
+ }
+ FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
+ if( rc != FT_Err_Ok )
+ return;
+
+ // prepare for font encodings other than unicode or symbol
+ FT_Encoding eEncoding = FT_ENCODING_UNICODE;
+ if( mpFontInfo->IsSymbolFont() )
+ {
+#if (FTVERSION < 2000)
+ eEncoding = FT_ENCODING_NONE;
+#else
+ if( FT_IS_SFNT( maFaceFT ) )
+ eEncoding = ft_encoding_symbol;
+ else
+ eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts
+#endif
+ }
+ rc = FT_Select_Charmap( maFaceFT, eEncoding );
+ // no standard encoding applies => we need an encoding converter
+ if( rc != FT_Err_Ok )
+ {
+ rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
+ for( int i = maFaceFT->num_charmaps; --i >= 0; )
+ {
+ const FT_CharMap aCM = maFaceFT->charmaps[i];
+ if( aCM->platform_id == TT_PLATFORM_MICROSOFT )
+ {
+ switch( aCM->encoding_id )
+ {
+ case TT_MS_ID_SJIS:
+ eEncoding = FT_ENCODING_SJIS;
+ eRecodeFrom = RTL_TEXTENCODING_SHIFT_JIS;
+ break;
+ case TT_MS_ID_GB2312:
+ eEncoding = FT_ENCODING_GB2312;
+ eRecodeFrom = RTL_TEXTENCODING_GB_2312;
+ break;
+ case TT_MS_ID_BIG_5:
+ eEncoding = FT_ENCODING_BIG5;
+ eRecodeFrom = RTL_TEXTENCODING_BIG5;
+ break;
+ case TT_MS_ID_WANSUNG:
+ eEncoding = FT_ENCODING_WANSUNG;
+ eRecodeFrom = RTL_TEXTENCODING_MS_949;
+ break;
+ case TT_MS_ID_JOHAB:
+ eEncoding = FT_ENCODING_JOHAB;
+ eRecodeFrom = RTL_TEXTENCODING_MS_1361;
+ break;
+ }
+ }
+ else if( aCM->platform_id == TT_PLATFORM_MACINTOSH )
+ {
+ switch( aCM->encoding_id )
+ {
+ case TT_MAC_ID_ROMAN:
+ eEncoding = FT_ENCODING_APPLE_ROMAN;
+ eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
+ break;
+ // TODO: add other encodings when Mac-only
+ // non-unicode fonts show up
+ }
+ }
+ else if( aCM->platform_id == TT_PLATFORM_ADOBE )
+ {
+ switch( aCM->encoding_id )
+ {
+#ifdef TT_ADOBE_ID_LATIN1
+ case TT_ADOBE_ID_LATIN1: // better unicode than nothing
+ eEncoding = FT_ENCODING_ADOBE_LATIN_1;
+ eRecodeFrom = RTL_TEXTENCODING_ISO_8859_1;
+ break;
+#endif // TT_ADOBE_ID_LATIN1
+ case TT_ADOBE_ID_STANDARD: // better unicode than nothing
+ eEncoding = FT_ENCODING_ADOBE_STANDARD;
+ eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
+ break;
+ }
+ }
+ }
+
+ if( FT_Err_Ok != FT_Select_Charmap( maFaceFT, eEncoding ) )
+ return;
+
+ if( eRecodeFrom != RTL_TEXTENCODING_UNICODE )
+ maRecodeConverter = rtl_createUnicodeToTextConverter( eRecodeFrom );
+ }
+
+ mbFaceOk = true;
+
+ ApplyGSUB( rFSD );
+
+ // TODO: query GASP table for load flags
+ mnLoadFlags = FT_LOAD_DEFAULT;
+#if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
+ // we are not using FT_Set_Transform() yet, so just ignore it for now
+ mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM;
+#endif
+
+ mbArtItalic = (rFSD.meItalic != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE);
+ mbArtBold = (rFSD.meWeight > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
+ mbUseGamma = false;
+ if( mbArtBold )
+ {
+ //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai
+ //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan
+ //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified
+ //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung
+ //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional
+ //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
+ static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above
+ const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
+ if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT )
+ && rFSD.mnHeight < 20)
+ mbUseGamma = true;
+ }
+
+ if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) )
+ mnLoadFlags |= FT_LOAD_NO_BITMAP;
+}
+
+void FreetypeServerFont::SetFontOptions( const ImplFontOptions& rFontOptions)
+{
+ FontAutoHint eHint = rFontOptions.GetUseAutoHint();
+ if( eHint == AUTOHINT_DONTKNOW )
+ eHint = mbUseGamma ? AUTOHINT_TRUE : AUTOHINT_FALSE;
+
+ if( eHint == AUTOHINT_TRUE )
+ mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
+
+ if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only
+ mnLoadFlags |= FT_LOAD_NO_HINTING;
+ mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334#
+
+ if( rFontOptions.DontUseAntiAlias() )
+ mnPrioAntiAlias = 0;
+ if( rFontOptions.DontUseEmbeddedBitmaps() )
+ mnPrioEmbedded = 0;
+ if( rFontOptions.DontUseHinting() )
+ mnPrioAutoHint = 0;
+
+#if (FTVERSION >= 2005) || defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
+ if( mnPrioAutoHint <= 0 )
+#endif
+ mnLoadFlags |= FT_LOAD_NO_HINTING;
+
+#if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
+ if( !(mnLoadFlags & FT_LOAD_NO_HINTING) && (nFTVERSION >= 2103))
+ {
+ mnLoadFlags |= FT_LOAD_TARGET_NORMAL;
+ switch( rFontOptions.GetHintStyle() )
+ {
+ case HINT_NONE:
+ mnLoadFlags |= FT_LOAD_NO_HINTING;
+ break;
+ case HINT_SLIGHT:
+ mnLoadFlags |= FT_LOAD_TARGET_LIGHT;
+ break;
+ case HINT_MEDIUM:
+ break;
+ case HINT_FULL:
+ default:
+ break;
+ }
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+bool FreetypeServerFont::TestFont() const
+{
+ return mbFaceOk;
+}
+
+// -----------------------------------------------------------------------
+
+FreetypeServerFont::~FreetypeServerFont()
+{
+ if( mpLayoutEngine )
+ delete mpLayoutEngine;
+
+ if( maRecodeConverter )
+ rtl_destroyUnicodeToTextConverter( maRecodeConverter );
+
+ if( maSizeFT )
+ pFTDoneSize( maSizeFT );
+
+ mpFontInfo->ReleaseFaceFT( maFaceFT );
+}
+
+ // -----------------------------------------------------------------------
+
+int FreetypeServerFont::GetEmUnits() const
+{
+ return maFaceFT->units_per_EM;
+}
+
+// -----------------------------------------------------------------------
+
+void FreetypeServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
+{
+ static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes();
+
+ rTo.mbScalableFont = true;
+ rTo.mbDevice = true;
+ rTo.mbKernableFont = (FT_HAS_KERNING( maFaceFT ) != 0) || mpFontInfo->HasExtraKerning();
+ rTo.mnOrientation = GetFontSelData().mnOrientation;
+
+ //Always consider [star]symbol as symbol fonts
+ if (
+ (rTo.GetFamilyName().EqualsAscii("OpenSymbol")) ||
+ (rTo.GetFamilyName().EqualsAscii("StarSymbol"))
+ )
+ {
+ rTo.mbSymbolFlag = true;
+ }
+
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ rFactor = 0x100;
+
+ rTo.mnWidth = mnWidth;
+
+ const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
+ rTo.mnAscent = (+rMetrics.ascender + 32) >> 6;
+#if (FTVERSION < 2000)
+ rTo.mnDescent = (+rMetrics.descender + 32) >> 6;
+#else
+ rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
+#endif
+ rTo.mnIntLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
+ rTo.mnSlant = 0;
+
+ const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
+ const TT_HoriHeader* pHHEA = (const TT_HoriHeader*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_hhea );
+ if( pOS2 && (pOS2->version != 0xFFFF) )
+ {
+ // map the panose info from the OS2 table to their VCL counterparts
+ switch( pOS2->panose[0] )
+ {
+ case 1: rTo.meFamily = FAMILY_ROMAN; break;
+ case 2: rTo.meFamily = FAMILY_SWISS; break;
+ case 3: rTo.meFamily = FAMILY_MODERN; break;
+ case 4: rTo.meFamily = FAMILY_SCRIPT; break;
+ case 5: rTo.meFamily = FAMILY_DECORATIVE; break;
+ // TODO: is it reasonable to override the attribute with DONTKNOW?
+ case 0: // fall through
+ default: rTo.meFamilyType = FAMILY_DONTKNOW; break;
+ }
+
+ switch( pOS2->panose[3] )
+ {
+ case 2: // fall through
+ case 3: // fall through
+ case 4: // fall through
+ case 5: // fall through
+ case 6: // fall through
+ case 7: // fall through
+ case 8: rTo.mePitch = PITCH_VARIABLE; break;
+ case 9: rTo.mePitch = PITCH_FIXED; break;
+ // TODO: is it reasonable to override the attribute with DONTKNOW?
+ case 0: // fall through
+ case 1: // fall through
+ default: rTo.mePitch = PITCH_DONTKNOW; break;
+ }
+
+ // #108862# sanity check, some fonts treat descent as signed !!!
+ int nDescent = pOS2->usWinDescent;
+ if( nDescent > 5*maFaceFT->units_per_EM )
+ nDescent = (short)pOS2->usWinDescent; // interpret it as signed!
+
+ const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM;
+ if( pOS2->usWinAscent || pOS2->usWinDescent ) // #i30551#
+ {
+ rTo.mnAscent = (long)( +pOS2->usWinAscent * fScale + 0.5 );
+ rTo.mnDescent = (long)( +nDescent * fScale + 0.5 );
+ rTo.mnIntLeading = (long)( (+pOS2->usWinAscent + pOS2->usWinDescent - maFaceFT->units_per_EM) * fScale + 0.5 );
+ }
+ rTo.mnExtLeading = 0;
+ if( (pHHEA != NULL) && (pOS2->usWinAscent || pOS2->usWinDescent) )
+ {
+ int nExtLeading = pHHEA->Line_Gap;
+ nExtLeading -= (pOS2->usWinAscent + pOS2->usWinDescent);
+ nExtLeading += (pHHEA->Ascender - pHHEA->Descender);
+ if( nExtLeading > 0 )
+ rTo.mnExtLeading = (long)(nExtLeading * fScale + 0.5);
+ }
+
+ // Check for CJK capabilities of the current font
+ // #107888# workaround for Asian...
+ // TODO: remove when ExtLeading fully implemented
+ BOOL bCJKCapable = ((pOS2->ulUnicodeRange2 & 0x2DF00000) != 0);
+
+ if ( bCJKCapable && (pOS2->usWinAscent || pOS2->usWinDescent) )
+ {
+ rTo.mnIntLeading += rTo.mnExtLeading;
+
+ // #109280# The line height for Asian fonts is too small.
+ // Therefore we add half of the external leading to the
+ // ascent, the other half is added to the descent.
+ const long nHalfTmpExtLeading = rTo.mnExtLeading / 2;
+ const long nOtherHalfTmpExtLeading = rTo.mnExtLeading -
+ nHalfTmpExtLeading;
+
+ // #110641# external leading for Asian fonts.
+ // The factor 0.3 has been verified during experiments.
+ const long nCJKExtLeading = (long)(0.30 * (rTo.mnAscent + rTo.mnDescent));
+
+ if ( nCJKExtLeading > rTo.mnExtLeading )
+ rTo.mnExtLeading = nCJKExtLeading - rTo.mnExtLeading;
+ else
+ rTo.mnExtLeading = 0;
+
+ rTo.mnAscent += nHalfTmpExtLeading;
+ rTo.mnDescent += nOtherHalfTmpExtLeading;
+ }
+ }
+
+ // initialize kashida width
+ // TODO: what if there are different versions of this glyph available
+ rTo.mnMinKashida = rTo.mnAscent / 4; // a reasonable default
+ const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 );
+ if( nKashidaGlyphId )
+ {
+ GlyphData aGlyphData;
+ InitGlyphData( nKashidaGlyphId, aGlyphData );
+ rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static inline void SplitGlyphFlags( const FreetypeServerFont& rFont, int& nGlyphIndex, int& nGlyphFlags )
+{
+ nGlyphFlags = nGlyphIndex & GF_FLAGMASK;
+ nGlyphIndex &= GF_IDXMASK;
+
+ if( nGlyphIndex & GF_ISCHAR )
+ nGlyphIndex = rFont.GetRawGlyphIndex( nGlyphIndex );
+}
+
+// -----------------------------------------------------------------------
+
+int FreetypeServerFont::ApplyGlyphTransform( int nGlyphFlags,
+ FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const
+{
+ int nAngle = GetFontSelData().mnOrientation;
+ // shortcut most common case
+ if( !nAngle && !nGlyphFlags )
+ return nAngle;
+
+ const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
+ FT_Vector aVector;
+ FT_Matrix aMatrix;
+
+ bool bStretched = false;
+
+ switch( nGlyphFlags & GF_ROTMASK )
+ {
+ default: // straight
+ aVector.x = 0;
+ aVector.y = 0;
+ aMatrix.xx = +mnCos;
+ aMatrix.yy = +mnCos;
+ aMatrix.xy = -mnSin;
+ aMatrix.yx = +mnSin;
+ break;
+ case GF_ROTL: // left
+ nAngle += 900;
+ bStretched = (mfStretch != 1.0);
+ aVector.x = (FT_Pos)(+rMetrics.descender * mfStretch);
+ aVector.y = -rMetrics.ascender;
+ aMatrix.xx = (FT_Pos)(-mnSin / mfStretch);
+ aMatrix.yy = (FT_Pos)(-mnSin * mfStretch);
+ aMatrix.xy = (FT_Pos)(-mnCos * mfStretch);
+ aMatrix.yx = (FT_Pos)(+mnCos / mfStretch);
+ break;
+ case GF_ROTR: // right
+ nAngle -= 900;
+ bStretched = (mfStretch != 1.0);
+ aVector.x = -maFaceFT->glyph->metrics.horiAdvance;
+ aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0);
+ aVector.y = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0);
+ aMatrix.xx = (FT_Pos)(+mnSin / mfStretch);
+ aMatrix.yy = (FT_Pos)(+mnSin * mfStretch);
+ aMatrix.xy = (FT_Pos)(+mnCos * mfStretch);
+ aMatrix.yx = (FT_Pos)(-mnCos / mfStretch);
+ break;
+ }
+
+ while( nAngle < 0 )
+ nAngle += 3600;
+
+ if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
+ {
+ FT_Glyph_Transform( pGlyphFT, NULL, &aVector );
+
+ // orthogonal transforms are better handled by bitmap operations
+ if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) )
+ {
+ // workaround for compatibility with older FT versions
+ if( nFTVERSION < 2102 )
+ {
+ FT_Fixed t = aMatrix.xy;
+ aMatrix.xy = aMatrix.yx;
+ aMatrix.yx = t;
+ }
+
+ // apply non-orthogonal or stretch transformations
+ FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
+ nAngle = 0;
+ }
+ }
+ else
+ {
+ // FT<=2005 ignores transforms for bitmaps, so do it manually
+ FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT);
+ pBmpGlyphFT->left += (aVector.x + 32) >> 6;
+ pBmpGlyphFT->top += (aVector.y + 32) >> 6;
+ }
+
+ return nAngle;
+}
+
+// -----------------------------------------------------------------------
+
+int FreetypeServerFont::GetRawGlyphIndex( sal_UCS4 aChar ) const
+{
+ if( mpFontInfo->IsSymbolFont() )
+ {
+ if( !FT_IS_SFNT( maFaceFT ) )
+ {
+ if( (aChar & 0xFF00) == 0xF000 )
+ aChar &= 0xFF; // PS font symbol mapping
+ else if( aChar > 0xFF )
+ return 0;
+ }
+ }
+
+ // if needed recode from unicode to font encoding
+ if( maRecodeConverter )
+ {
+ sal_Char aTempArray[8];
+ sal_Size nTempSize;
+ sal_uInt32 nCvtInfo;
+
+ // assume that modern UCS4 fonts have unicode CMAPs
+ // => no encoding remapping to unicode is needed
+ if( aChar > 0xFFFF )
+ return 0;
+
+ sal_Unicode aUCS2Char = static_cast<sal_Unicode>(aChar);
+ rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext( maRecodeConverter );
+ int nChars = rtl_convertUnicodeToText( maRecodeConverter, aContext,
+ &aUCS2Char, 1, aTempArray, sizeof(aTempArray),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK,
+ &nCvtInfo, &nTempSize );
+ rtl_destroyUnicodeToTextContext( maRecodeConverter, aContext );
+
+ aChar = 0;
+ for( int i = 0; i < nChars; ++i )
+ aChar = aChar*256 + (aTempArray[i] & 0xFF);
+ }
+
+ // cache glyph indexes in font info to share between different sizes
+ int nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar );
+ if( nGlyphIndex < 0 )
+ {
+ nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar );
+ if( !nGlyphIndex)
+ {
+ // check if symbol aliasing helps
+ if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() )
+ nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 );
+#if 0 // disabled for now because it introduced ae bad side-effect (#i88376#)
+ // Finally try the postscript name table
+ if (!nGlyphIndex)
+ nGlyphIndex = psp::PrintFontManager::get().FreeTypeCharIndex( maFaceFT, aChar );
+#endif
+ }
+ mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex );
+ }
+
+ return nGlyphIndex;
+}
+
+// -----------------------------------------------------------------------
+
+int FreetypeServerFont::FixupGlyphIndex( int nGlyphIndex, sal_UCS4 aChar ) const
+{
+ int nGlyphFlags = GF_NONE;
+
+ // do glyph substitution if necessary
+ // CJK vertical writing needs special treatment
+ if( GetFontSelData().mbVertical )
+ {
+ // TODO: rethink when GSUB is used for non-vertical case
+ GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( nGlyphIndex );
+ if( it == maGlyphSubstitution.end() )
+ {
+ int nTemp = GetVerticalChar( aChar );
+ if( nTemp ) // is substitution possible
+ nTemp = GetRawGlyphIndex( nTemp );
+ if( nTemp ) // substitute manually if sensible
+ nGlyphIndex = nTemp | (GF_GSUB | GF_ROTL);
+ else
+ nGlyphFlags |= GetVerticalFlags( aChar );
+ }
+ else
+ {
+ // for vertical GSUB also compensate for nOrientation=2700
+ nGlyphIndex = (*it).second;
+ nGlyphFlags |= GF_GSUB | GF_ROTL;
+ }
+ }
+
+#if 0
+ // #95556# autohinting not yet optimized for non-western glyph styles
+ if( !(mnLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_FORCE_AUTOHINT) )
+ && ( (aChar >= 0x0600 && aChar < 0x1E00) // south-east asian + arabic
+ ||(aChar >= 0x2900 && aChar < 0xD800) // CJKV
+ ||(aChar >= 0xF800) ) ) // presentation + symbols
+ {
+ nGlyphFlags |= GF_UNHINTED;
+ }
+#endif
+
+ if( nGlyphIndex != 0 )
+ nGlyphIndex |= nGlyphFlags;
+
+ return nGlyphIndex;
+}
+
+
+// -----------------------------------------------------------------------
+
+int FreetypeServerFont::GetGlyphIndex( sal_UCS4 aChar ) const
+{
+ int nGlyphIndex = GetRawGlyphIndex( aChar );
+ nGlyphIndex = FixupGlyphIndex( nGlyphIndex, aChar );
+ return nGlyphIndex;
+}
+
+// -----------------------------------------------------------------------
+
+static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags )
+{
+ int nCharWidth = pFaceFT->glyph->metrics.horiAdvance;
+
+ if( nGlyphFlags & GF_ROTMASK ) // for bVertical rotated glyphs
+ {
+ const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics;
+#if (FTVERSION < 2000)
+ nCharWidth = (int)((rMetrics.height - rMetrics.descender) * fStretch);
+#else
+ nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch);
+#endif
+ }
+
+ return (nCharWidth + 32) >> 6;
+}
+
+// -----------------------------------------------------------------------
+
+void FreetypeServerFont::InitGlyphData( int nGlyphIndex, GlyphData& rGD ) const
+{
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ int nGlyphFlags;
+ SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
+
+ int nLoadFlags = mnLoadFlags;
+
+// if( mbArtItalic )
+// nLoadFlags |= FT_LOAD_NO_BITMAP;
+
+ FT_Error rc = -1;
+#if (FTVERSION <= 2008)
+ // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
+ // => first we have to try without hinting
+ if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
+ {
+ rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
+ if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format!=FT_GLYPH_FORMAT_BITMAP) )
+ rc = -1; // mark as "loading embedded bitmap" was unsuccessful
+ nLoadFlags |= FT_LOAD_NO_BITMAP;
+ }
+
+ if( rc != FT_Err_Ok )
+#endif
+ rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
+
+ if( rc != FT_Err_Ok )
+ {
+ // we get here e.g. when a PS font lacks the default glyph
+ rGD.SetCharWidth( 0 );
+ rGD.SetDelta( 0, 0 );
+ rGD.SetOffset( 0, 0 );
+ rGD.SetSize( Size( 0, 0 ) );
+ return;
+ }
+
+ const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0);
+ if( mbArtBold && pFTEmbolden )
+ (*pFTEmbolden)( maFaceFT->glyph );
+
+ const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags );
+ rGD.SetCharWidth( nCharWidth );
+
+ FT_Glyph pGlyphFT;
+ rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
+
+ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
+ if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug
+ pGlyphFT->advance.y = 0;
+ rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
+
+ FT_BBox aBbox;
+ FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
+ if( aBbox.yMin > aBbox.yMax ) // circumvent freetype bug
+ {
+ int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
+ }
+
+ rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
+ rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
+
+ FT_Done_Glyph( pGlyphFT );
+}
+
+// -----------------------------------------------------------------------
+
+bool FreetypeServerFont::GetAntialiasAdvice( void ) const
+{
+ if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
+ return false;
+ bool bAdviseAA = true;
+ // TODO: also use GASP info
+ return bAdviseAA;
+}
+
+// -----------------------------------------------------------------------
+
+bool FreetypeServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& rRawBitmap ) const
+{
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ int nGlyphFlags;
+ SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
+
+ FT_Int nLoadFlags = mnLoadFlags;
+ // #i70930# force mono-hinting for monochrome text
+ if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse
+ {
+ nLoadFlags &= ~0xF0000;
+ nLoadFlags |= FT_LOAD_TARGET_MONO;
+ }
+
+ if( mbArtItalic )
+ nLoadFlags |= FT_LOAD_NO_BITMAP;
+
+#if (FTVERSION >= 2002)
+ // for 0/90/180/270 degree fonts enable hinting even if not advisable
+ // non-hinted and non-antialiased bitmaps just look too ugly
+ if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) )
+ nLoadFlags &= ~FT_LOAD_NO_HINTING;
+#endif
+
+ if( mnPrioEmbedded <= mnPrioAutoHint )
+ nLoadFlags |= FT_LOAD_NO_BITMAP;
+
+ FT_Error rc = -1;
+#if (FTVERSION <= 2008)
+ // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
+ // => first we have to try without hinting
+ if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
+ {
+ rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
+ if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) )
+ rc = -1; // mark as "loading embedded bitmap" was unsuccessful
+ nLoadFlags |= FT_LOAD_NO_BITMAP;
+ }
+
+ if( rc != FT_Err_Ok )
+#endif
+ rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
+ if( rc != FT_Err_Ok )
+ return false;
+
+ if( mbArtBold && pFTEmbolden )
+ (*pFTEmbolden)( maFaceFT->glyph );
+
+ FT_Glyph pGlyphFT;
+ rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
+ if( rc != FT_Err_Ok )
+ return false;
+
+ int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
+
+ if( mbArtItalic )
+ {
+ FT_Matrix aMatrix;
+ aMatrix.xx = aMatrix.yy = 0x10000L;
+ if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx
+ aMatrix.xy = 0x6000L, aMatrix.yx = 0;
+ else
+ aMatrix.yx = 0x6000L, aMatrix.xy = 0;
+ FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
+ }
+
+ // Check for zero area bounding boxes as this crashes some versions of FT.
+ // This also provides a handy short cut as much of the code following
+ // becomes an expensive nop when a glyph covers no pixels.
+ FT_BBox cbox;
+ FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
+
+ if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
+ {
+ nAngle = 0;
+ memset(&rRawBitmap, 0, sizeof rRawBitmap);
+ FT_Done_Glyph( pGlyphFT );
+ return true;
+ }
+
+ if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
+ {
+ if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
+ ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+ // #i15743# freetype API 2.1.3 changed the FT_RENDER_MODE_MONO constant
+ FT_Render_Mode nRenderMode = (FT_Render_Mode)((nFTVERSION<2103) ? 1 : FT_RENDER_MODE_MONO);
+
+ rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, TRUE );
+ if( rc != FT_Err_Ok )
+ {
+ FT_Done_Glyph( pGlyphFT );
+ return false;
+ }
+ }
+
+ const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
+ // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
+ rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
+ rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
+
+ const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
+ rRawBitmap.mnHeight = rBitmapFT.rows;
+ rRawBitmap.mnBitCount = 1;
+ if( mbArtBold && !pFTEmbolden )
+ {
+ rRawBitmap.mnWidth = rBitmapFT.width + 1;
+ int nLineBytes = (rRawBitmap.mnWidth + 7) >> 3;
+ rRawBitmap.mnScanlineSize = (nLineBytes > rBitmapFT.pitch) ? nLineBytes : rBitmapFT.pitch;
+ }
+ else
+ {
+ rRawBitmap.mnWidth = rBitmapFT.width;
+ rRawBitmap.mnScanlineSize = rBitmapFT.pitch;
+ }
+
+ const ULONG nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
+
+ if( rRawBitmap.mnAllocated < nNeededSize )
+ {
+ delete[] rRawBitmap.mpBits;
+ rRawBitmap.mnAllocated = 2*nNeededSize;
+ rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
+ }
+
+ if( !mbArtBold || pFTEmbolden )
+ {
+ memcpy( rRawBitmap.mpBits, rBitmapFT.buffer, nNeededSize );
+ }
+ else
+ {
+ memset( rRawBitmap.mpBits, 0, nNeededSize );
+ const unsigned char* pSrcLine = rBitmapFT.buffer;
+ unsigned char* pDstLine = rRawBitmap.mpBits;
+ for( int h = rRawBitmap.mnHeight; --h >= 0; )
+ {
+ memcpy( pDstLine, pSrcLine, rBitmapFT.pitch );
+ pDstLine += rRawBitmap.mnScanlineSize;
+ pSrcLine += rBitmapFT.pitch;
+ }
+
+ unsigned char* p = rRawBitmap.mpBits;
+ for( ULONG y=0; y < rRawBitmap.mnHeight; y++ )
+ {
+ unsigned char nLastByte = 0;
+ for( ULONG x=0; x < rRawBitmap.mnScanlineSize; x++ )
+ {
+ unsigned char nTmp = p[x] << 7;
+ p[x] |= (p[x] >> 1) | nLastByte;
+ nLastByte = nTmp;
+ }
+ p += rRawBitmap.mnScanlineSize;
+ }
+ }
+
+ FT_Done_Glyph( pGlyphFT );
+
+ // special case for 0/90/180/270 degree orientation
+ switch( nAngle )
+ {
+ case -900:
+ case +900:
+ case +1800:
+ case +2700:
+ rRawBitmap.Rotate( nAngle );
+ break;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool FreetypeServerFont::GetGlyphBitmap8( int nGlyphIndex, RawBitmap& rRawBitmap ) const
+{
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ int nGlyphFlags;
+ SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
+
+ FT_Int nLoadFlags = mnLoadFlags;
+
+ if( mbArtItalic )
+ nLoadFlags |= FT_LOAD_NO_BITMAP;
+
+#if (FTVERSION <= 2004) && !defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
+ // autohinting in FT<=2.0.4 makes antialiased glyphs look worse
+ nLoadFlags |= FT_LOAD_NO_HINTING;
+#else
+ if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) )
+ nLoadFlags |= FT_LOAD_NO_HINTING;
+#endif
+
+ if( mnPrioEmbedded <= mnPrioAntiAlias )
+ nLoadFlags |= FT_LOAD_NO_BITMAP;
+
+ FT_Error rc = -1;
+#if (FTVERSION <= 2008)
+ // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
+ // => first we have to try without hinting
+ if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
+ {
+ rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
+ if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) )
+ rc = -1; // mark as "loading embedded bitmap" was unsuccessful
+ nLoadFlags |= FT_LOAD_NO_BITMAP;
+ }
+
+ if( rc != FT_Err_Ok )
+#endif
+ rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
+
+ if( rc != FT_Err_Ok )
+ return false;
+
+ if( mbArtBold && pFTEmbolden )
+ (*pFTEmbolden)( maFaceFT->glyph );
+
+ FT_Glyph pGlyphFT;
+ rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
+ if( rc != FT_Err_Ok )
+ return false;
+
+ int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
+
+ if( mbArtItalic )
+ {
+ FT_Matrix aMatrix;
+ aMatrix.xx = aMatrix.yy = 0x10000L;
+ if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx
+ aMatrix.xy = 0x6000L, aMatrix.yx = 0;
+ else
+ aMatrix.yx = 0x6000L, aMatrix.xy = 0;
+ FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
+ }
+
+ if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
+ ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+ bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP);
+ if( !bEmbedded )
+ {
+ rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, TRUE );
+ if( rc != FT_Err_Ok )
+ {
+ FT_Done_Glyph( pGlyphFT );
+ return false;
+ }
+ }
+
+ const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
+ rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
+ rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
+
+ const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
+ rRawBitmap.mnHeight = rBitmapFT.rows;
+ rRawBitmap.mnWidth = rBitmapFT.width;
+ rRawBitmap.mnBitCount = 8;
+ rRawBitmap.mnScanlineSize = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch;
+ if( mbArtBold && !pFTEmbolden )
+ {
+ ++rRawBitmap.mnWidth;
+ ++rRawBitmap.mnScanlineSize;
+ }
+ rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4;
+
+ const ULONG nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
+ if( rRawBitmap.mnAllocated < nNeededSize )
+ {
+ delete[] rRawBitmap.mpBits;
+ rRawBitmap.mnAllocated = 2*nNeededSize;
+ rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
+ }
+
+ const unsigned char* pSrc = rBitmapFT.buffer;
+ unsigned char* pDest = rRawBitmap.mpBits;
+ if( !bEmbedded )
+ {
+ for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
+ {
+ for( x = 0; x < rBitmapFT.width; ++x )
+ *(pDest++) = *(pSrc++);
+ for(; x < int(rRawBitmap.mnScanlineSize); ++x )
+ *(pDest++) = 0;
+ }
+ }
+ else
+ {
+ for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
+ {
+ unsigned char nSrc = 0;
+ for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc )
+ {
+ if( (x & 7) == 0 )
+ nSrc = *(pSrc++);
+ *(pDest++) = (0x7F - nSrc) >> 8;
+ }
+ for(; x < int(rRawBitmap.mnScanlineSize); ++x )
+ *(pDest++) = 0;
+ }
+ }
+
+ if( mbArtBold && !pFTEmbolden )
+ {
+ // overlay with glyph image shifted by one left pixel
+ unsigned char* p = rRawBitmap.mpBits;
+ for( ULONG y=0; y < rRawBitmap.mnHeight; y++ )
+ {
+ unsigned char nLastByte = 0;
+ for( ULONG x=0; x < rRawBitmap.mnWidth; x++ )
+ {
+ unsigned char nTmp = p[x];
+ p[x] |= p[x] | nLastByte;
+ nLastByte = nTmp;
+ }
+ p += rRawBitmap.mnScanlineSize;
+ }
+ }
+
+ if( !bEmbedded && mbUseGamma )
+ {
+ unsigned char* p = rRawBitmap.mpBits;
+ for( ULONG y=0; y < rRawBitmap.mnHeight; y++ )
+ {
+ for( ULONG x=0; x < rRawBitmap.mnWidth; x++ )
+ {
+ p[x] = aGammaTable[ p[x] ];
+ }
+ p += rRawBitmap.mnScanlineSize;
+ }
+ }
+
+ FT_Done_Glyph( pGlyphFT );
+
+ // special case for 0/90/180/270 degree orientation
+ switch( nAngle )
+ {
+ case -900:
+ case +900:
+ case +1800:
+ case +2700:
+ rRawBitmap.Rotate( nAngle );
+ break;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+// determine unicode ranges in font
+// -----------------------------------------------------------------------
+
+// TODO: replace with GetFontCharMap()
+bool FreetypeServerFont::GetFontCodeRanges( CmapResult& rResult ) const
+{
+ rResult.mbSymbolic = mpFontInfo->IsSymbolFont();
+
+ // TODO: is the full CmapResult needed on platforms calling this?
+ if( FT_IS_SFNT( maFaceFT ) )
+ {
+ ULONG nLength = 0;
+ const unsigned char* pCmap = mpFontInfo->GetTable( "cmap", &nLength );
+ if( pCmap && (nLength > 0) )
+ if( ParseCMAP( pCmap, nLength, rResult ) )
+ return true;
+ }
+
+ typedef std::vector<sal_uInt32> U32Vector;
+ U32Vector aCodes;
+
+ // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
+ aCodes.reserve( 0x1000 );
+ FT_UInt nGlyphIndex;
+ for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; )
+ {
+ if( !nGlyphIndex )
+ break;
+ aCodes.push_back( cCode ); // first code inside range
+ sal_uInt32 cNext = cCode;
+ do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode );
+ aCodes.push_back( cCode ); // first code outside range
+ cCode = cNext;
+ }
+
+ const int nCount = aCodes.size();
+ if( !nCount) {
+ if( !rResult.mbSymbolic )
+ return false;
+
+ // we usually get here for Type1 symbol fonts
+ aCodes.push_back( 0xF020 );
+ aCodes.push_back( 0xF100 );
+ }
+
+ sal_uInt32* pCodes = new sal_uInt32[ nCount ];
+ for( int i = 0; i < nCount; ++i )
+ pCodes[i] = aCodes[i];
+ rResult.mpRangeCodes = pCodes;
+ rResult.mnRangeCount = nCount / 2;
+ return true;
+}
+
+// -----------------------------------------------------------------------
+// kerning stuff
+// -----------------------------------------------------------------------
+
+int FreetypeServerFont::GetGlyphKernValue( int nGlyphLeft, int nGlyphRight ) const
+{
+ // if no kerning info is available from Freetype
+ // then we may have to use extra info provided by e.g. psprint
+ if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
+ {
+ int nKernVal = mpFontInfo->GetExtraGlyphKernValue( nGlyphLeft, nGlyphRight );
+ if( !nKernVal )
+ return 0;
+ // scale the kern value to match the font size
+ const ImplFontSelectData& rFSD = GetFontSelData();
+ nKernVal *= rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
+ return (nKernVal + 500) / 1000;
+ }
+
+ // when font faces of different sizes share the same maFaceFT
+ // then we have to make sure that it uses the correct maSizeFT
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ // use Freetype's kerning info
+ FT_Vector aKernVal;
+ FT_Error rcFT = FT_Get_Kerning( maFaceFT, nGlyphLeft, nGlyphRight,
+ FT_KERNING_DEFAULT, &aKernVal );
+ int nResult = (rcFT == FT_Err_Ok) ? (aKernVal.x + 32) >> 6 : 0;
+ return nResult;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG FreetypeServerFont::GetKernPairs( ImplKernPairData** ppKernPairs ) const
+{
+ // if no kerning info is available in the font file
+ *ppKernPairs = NULL;
+ if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
+ {
+ // then we have may have extra kerning info from e.g. psprint
+ int nCount = mpFontInfo->GetExtraKernPairs( ppKernPairs );
+ // scale the kern values to match the font size
+ const ImplFontSelectData& rFSD = GetFontSelData();
+ int nFontWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
+ ImplKernPairData* pKernPair = *ppKernPairs;
+ for( int i = nCount; --i >= 0; ++pKernPair )
+ {
+ long& rVal = pKernPair->mnKern;
+ rVal = ((rVal * nFontWidth) + 500) / 1000;
+ }
+ return nCount;
+ }
+
+ // when font faces of different sizes share the same maFaceFT
+ // then we have to make sure that it uses the correct maSizeFT
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ // first figure out which glyph pairs are involved in kerning
+ ULONG nKernLength = 0;
+ const FT_Byte* const pKern = mpFontInfo->GetTable( "kern", &nKernLength );
+ if( !pKern )
+ return 0;
+
+ // combine TTF/OTF tables from the font file to build a vector of
+ // unicode kerning pairs using Freetype's glyph kerning calculation
+ // for the kerning value
+
+ // TODO: is it worth to share the glyph->unicode mapping between
+ // different instances of the same font face?
+
+ typedef std::vector<ImplKernPairData> KernVector;
+ KernVector aKernGlyphVector;
+ ImplKernPairData aKernPair;
+ aKernPair.mnKern = 0; // To prevent "is used uninitialized" warning...
+
+ const FT_Byte* pBuffer = pKern;
+ ULONG nVersion = GetUShort( pBuffer+0 );
+ USHORT nTableCnt = GetUShort( pBuffer+2 );
+
+ // Microsoft/Old TrueType style kern table
+ if ( nVersion == 0 )
+ {
+ pBuffer += 4;
+
+ for( USHORT nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
+ {
+ // USHORT nSubVersion = GetUShort( pBuffer+0 );
+ // USHORT nSubLength = GetUShort( pBuffer+2 );
+ USHORT nSubCoverage = GetUShort( pBuffer+4 );
+ pBuffer += 6;
+ if( (nSubCoverage&0x03) != 0x01 ) // no interest in minimum info here
+ continue;
+ switch( nSubCoverage >> 8 )
+ {
+ case 0: // version 0, kerning format 0
+ {
+ USHORT nPairs = GetUShort( pBuffer );
+ pBuffer += 8; // skip search hints
+ aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
+ for( int i = 0; i < nPairs; ++i )
+ {
+ aKernPair.mnChar1 = GetUShort( pBuffer+0 );
+ aKernPair.mnChar2 = GetUShort( pBuffer+2 );
+ //long nUnscaledKern= GetSShort( pBuffer );
+ pBuffer += 6;
+ aKernGlyphVector.push_back( aKernPair );
+ }
+ }
+ break;
+
+ case 2: // version 0, kerning format 2
+ {
+ const FT_Byte* pSubTable = pBuffer;
+ //USHORT nRowWidth = GetUShort( pBuffer+0 );
+ USHORT nOfsLeft = GetUShort( pBuffer+2 );
+ USHORT nOfsRight = GetUShort( pBuffer+4 );
+ USHORT nOfsArray = GetUShort( pBuffer+6 );
+ pBuffer += 8;
+
+ const FT_Byte* pTmp = pSubTable + nOfsLeft;
+ USHORT nFirstLeft = GetUShort( pTmp+0 );
+ USHORT nLastLeft = GetUShort( pTmp+2 ) + nFirstLeft - 1;
+
+ pTmp = pSubTable + nOfsRight;
+ USHORT nFirstRight = GetUShort( pTmp+0 );
+ USHORT nLastRight = GetUShort( pTmp+2 ) + nFirstRight - 1;
+
+ ULONG nPairs = (ULONG)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
+ aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
+
+ pTmp = pSubTable + nOfsArray;
+ for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
+ {
+ aKernPair.mnChar1 = nLeft;
+ for( int nRight = 0; nRight < nLastRight; ++nRight )
+ {
+ if( GetUShort( pTmp ) != 0 )
+ {
+ aKernPair.mnChar2 = nRight;
+ aKernGlyphVector.push_back( aKernPair );
+ }
+ pTmp += 2;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // Apple New style kern table
+ pBuffer = pKern;
+ nVersion = NEXT_U32( pBuffer );
+ nTableCnt = NEXT_U32( pBuffer );
+ if ( nVersion == 0x00010000 )
+ {
+ for( USHORT nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
+ {
+ /*ULONG nLength =*/ NEXT_U32( pBuffer );
+ USHORT nCoverage = NEXT_U16( pBuffer );
+ /*USHORT nTupleIndex =*/ NEXT_U16( pBuffer );
+
+ // Kerning sub-table format, 0 through 3
+ sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
+
+ switch( nSubTableFormat )
+ {
+ case 0: // version 0, kerning format 0
+ {
+ USHORT nPairs = NEXT_U16( pBuffer );
+ pBuffer += 6; // skip search hints
+ aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
+ for( int i = 0; i < nPairs; ++i )
+ {
+ aKernPair.mnChar1 = NEXT_U16( pBuffer );
+ aKernPair.mnChar2 = NEXT_U16( pBuffer );
+ /*long nUnscaledKern=*/ NEXT_S16( pBuffer );
+ aKernGlyphVector.push_back( aKernPair );
+ }
+ }
+ break;
+
+ case 2: // version 0, kerning format 2
+ {
+ const FT_Byte* pSubTable = pBuffer;
+ /*USHORT nRowWidth =*/ NEXT_U16( pBuffer );
+ USHORT nOfsLeft = NEXT_U16( pBuffer );
+ USHORT nOfsRight = NEXT_U16( pBuffer );
+ USHORT nOfsArray = NEXT_U16( pBuffer );
+
+ const FT_Byte* pTmp = pSubTable + nOfsLeft;
+ USHORT nFirstLeft = NEXT_U16( pTmp );
+ USHORT nLastLeft = NEXT_U16( pTmp ) + nFirstLeft - 1;
+
+ pTmp = pSubTable + nOfsRight;
+ USHORT nFirstRight = NEXT_U16( pTmp );
+ USHORT nLastRight = NEXT_U16( pTmp ) + nFirstRight - 1;
+
+ ULONG nPairs = (ULONG)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
+ aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
+
+ pTmp = pSubTable + nOfsArray;
+ for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
+ {
+ aKernPair.mnChar1 = nLeft;
+ for( int nRight = 0; nRight < nLastRight; ++nRight )
+ {
+ if( NEXT_S16( pTmp ) != 0 )
+ {
+ aKernPair.mnChar2 = nRight;
+ aKernGlyphVector.push_back( aKernPair );
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ fprintf( stderr, "gcach_ftyp.cxx: Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
+ break;
+ }
+ }
+ }
+
+ // now create VCL's ImplKernPairData[] format for all glyph pairs
+ ULONG nKernCount = aKernGlyphVector.size();
+ if( nKernCount )
+ {
+ // prepare glyphindex to character mapping
+ // TODO: this is needed to support VCL's existing kerning infrastructure,
+ // eliminate it up by redesigning kerning infrastructure to work with glyph indizes
+ typedef std::hash_multimap<USHORT,sal_Unicode> Cmap;
+ Cmap aCmap;
+ for( sal_Unicode aChar = 0x0020; aChar < 0xFFFE; ++aChar )
+ {
+ USHORT nGlyphIndex = GetGlyphIndex( aChar );
+ if( nGlyphIndex )
+ aCmap.insert( Cmap::value_type( nGlyphIndex, aChar ) );
+ }
+
+ // translate both glyph indizes in kerning pairs to characters
+ // problem is that these are 1:n mappings...
+ KernVector aKernCharVector;
+ aKernCharVector.reserve( nKernCount );
+ KernVector::iterator it;
+ for( it = aKernGlyphVector.begin(); it != aKernGlyphVector.end(); ++it )
+ {
+ FT_Vector aKernVal;
+ FT_Error rcFT = FT_Get_Kerning( maFaceFT, it->mnChar1, it->mnChar2,
+ FT_KERNING_DEFAULT, &aKernVal );
+ aKernPair.mnKern = aKernVal.x >> 6;
+ if( (aKernPair.mnKern == 0) || (rcFT != FT_Err_Ok) )
+ continue;
+
+ typedef std::pair<Cmap::iterator,Cmap::iterator> CPair;
+ const CPair p1 = aCmap.equal_range( it->mnChar1 );
+ const CPair p2 = aCmap.equal_range( it->mnChar2 );
+ for( Cmap::const_iterator i1 = p1.first; i1 != p1.second; ++i1 )
+ {
+ aKernPair.mnChar1 = (*i1).second;
+ for( Cmap::const_iterator i2 = p2.first; i2 != p2.second; ++i2 )
+ {
+ aKernPair.mnChar2 = (*i2).second;
+ aKernCharVector.push_back( aKernPair );
+ }
+ }
+ }
+
+ // now move the resulting vector into VCL's ImplKernPairData[] format
+ nKernCount = aKernCharVector.size();
+ ImplKernPairData* pTo = new ImplKernPairData[ nKernCount ];
+ *ppKernPairs = pTo;
+ for( it = aKernCharVector.begin(); it != aKernCharVector.end(); ++it, ++pTo )
+ {
+ pTo->mnChar1 = it->mnChar1;
+ pTo->mnChar2 = it->mnChar2;
+ pTo->mnKern = it->mnKern;
+ }
+ }
+
+ return nKernCount;
+}
+
+// -----------------------------------------------------------------------
+// outline stuff
+// -----------------------------------------------------------------------
+
+class PolyArgs
+{
+public:
+ PolyArgs( PolyPolygon& rPolyPoly, USHORT nMaxPoints );
+ ~PolyArgs();
+
+ void AddPoint( long nX, long nY, PolyFlags);
+ void ClosePolygon();
+
+ long GetPosX() const { return maPosition.x;}
+ long GetPosY() const { return maPosition.y;}
+
+private:
+ PolyPolygon& mrPolyPoly;
+
+ Point* mpPointAry;
+ BYTE* mpFlagAry;
+
+ FT_Vector maPosition;
+ USHORT mnMaxPoints;
+ USHORT mnPoints;
+ USHORT mnPoly;
+ long mnHeight;
+ bool bHasOffline;
+};
+
+// -----------------------------------------------------------------------
+
+PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, USHORT nMaxPoints )
+: mrPolyPoly(rPolyPoly),
+ mnMaxPoints(nMaxPoints),
+ mnPoints(0),
+ mnPoly(0),
+ bHasOffline(false)
+{
+ mpPointAry = new Point[ mnMaxPoints ];
+ mpFlagAry = new BYTE [ mnMaxPoints ];
+}
+
+// -----------------------------------------------------------------------
+
+
+PolyArgs::~PolyArgs()
+{
+ delete[] mpFlagAry;
+ delete[] mpPointAry;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag )
+{
+ DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" );
+ if( mnPoints >= mnMaxPoints )
+ return;
+
+ maPosition.x = nX;
+ maPosition.y = nY;
+ mpPointAry[ mnPoints ] = Point( nX, nY );
+ mpFlagAry[ mnPoints++ ]= aFlag;
+ bHasOffline |= (aFlag != POLY_NORMAL);
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::ClosePolygon()
+{
+ if( !mnPoly++ )
+ return;
+
+ // freetype seems to always close the polygon with an ON_CURVE point
+ // PolyPoly wants to close the polygon itself => remove last point
+ DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" );
+ --mnPoints;
+ DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" );
+ DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" );
+ DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" );
+
+ Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) );
+
+ // #i35928#
+ // This may be a invalid polygons, e.g. the last point is a control point.
+ // So close the polygon (and add the first point again) if the last point
+ // is a control point or different from first.
+ // #i48298#
+ // Now really duplicating the first point, to close or correct the
+ // polygon. Also no longer duplicating the flags, but enforcing
+ // POLY_NORMAL for the newly added last point.
+ const sal_uInt16 nPolySize(aPoly.GetSize());
+ if(nPolySize)
+ {
+ if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1))
+ || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0)))
+ {
+ aPoly.SetSize(nPolySize + 1);
+ aPoly.SetPoint(aPoly.GetPoint(0), nPolySize);
+
+ if(aPoly.HasFlags())
+ {
+ aPoly.SetFlags(nPolySize, POLY_NORMAL);
+ }
+ }
+ }
+
+ mrPolyPoly.Insert( aPoly );
+ mnPoints = 0;
+ bHasOffline = false;
+}
+
+// -----------------------------------------------------------------------
+
+extern "C" {
+
+// TODO: wait till all compilers accept that calling conventions
+// for functions are the same independent of implementation constness,
+// then uncomment the const-tokens in the function interfaces below
+static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs )
+{
+ PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
+
+ // move_to implies a new polygon => finish old polygon first
+ rA.ClosePolygon();
+
+ rA.AddPoint( p0->x, p0->y, POLY_NORMAL );
+ return 0;
+}
+
+static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs )
+{
+ PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
+ rA.AddPoint( p1->x, p1->y, POLY_NORMAL );
+ return 0;
+}
+
+static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs )
+{
+ PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
+
+ // VCL's Polygon only knows cubic beziers
+ const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6;
+ const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6;
+ rA.AddPoint( nX1, nY1, POLY_CONTROL );
+
+ const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6;
+ const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6;
+ rA.AddPoint( nX2, nY2, POLY_CONTROL );
+
+ rA.AddPoint( p2->x, p2->y, POLY_NORMAL );
+ return 0;
+}
+
+static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs )
+{
+ PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
+ rA.AddPoint( p1->x, p1->y, POLY_CONTROL );
+ rA.AddPoint( p2->x, p2->y, POLY_CONTROL );
+ rA.AddPoint( p3->x, p3->y, POLY_NORMAL );
+ return 0;
+}
+
+} // extern "C"
+
+// -----------------------------------------------------------------------
+
+bool FreetypeServerFont::GetGlyphOutline( int nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const
+{
+ if( maSizeFT )
+ pFTActivateSize( maSizeFT );
+
+ rB2DPolyPoly.clear();
+
+ int nGlyphFlags;
+ SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
+
+ FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;
+
+#ifdef FT_LOAD_TARGET_LIGHT
+ // enable "light hinting" if available
+ if( nFTVERSION >= 2103 )
+ nLoadFlags |= FT_LOAD_TARGET_LIGHT;
+#endif
+
+ FT_Error rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
+ if( rc != FT_Err_Ok )
+ return false;
+
+ if( mbArtBold && pFTEmbolden )
+ (*pFTEmbolden)( maFaceFT->glyph );
+
+ FT_Glyph pGlyphFT;
+ rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
+ if( rc != FT_Err_Ok )
+ return false;
+
+ if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE )
+ return false;
+
+ if( mbArtItalic )
+ {
+ FT_Matrix aMatrix;
+ aMatrix.xx = aMatrix.yy = 0x10000L;
+ if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx
+ aMatrix.xy = 0x6000L, aMatrix.yx = 0;
+ else
+ aMatrix.yx = 0x6000L, aMatrix.xy = 0;
+ FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
+ }
+
+ FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline;
+ if( !rOutline.n_points ) // blank glyphs are ok
+ return true;
+
+ long nMaxPoints = 1 + rOutline.n_points * 3;
+ PolyPolygon aToolPolyPolygon;
+ PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints );
+
+ /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
+
+ FT_Outline_Funcs aFuncs;
+ aFuncs.move_to = &FT_move_to;
+ aFuncs.line_to = &FT_line_to;
+ aFuncs.conic_to = &FT_conic_to;
+ aFuncs.cubic_to = &FT_cubic_to;
+ aFuncs.shift = 0;
+ aFuncs.delta = 0;
+ rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg );
+ aPolyArg.ClosePolygon(); // close last polygon
+ FT_Done_Glyph( pGlyphFT );
+
+ // convert to basegfx polypolygon
+ // TODO: get rid of the intermediate tools polypolygon
+ rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon();
+ rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool FreetypeServerFont::ApplyGSUB( const ImplFontSelectData& rFSD )
+{
+#define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
+
+ typedef std::vector<ULONG> ReqFeatureTagList;
+ ReqFeatureTagList aReqFeatureTagList;
+ if( rFSD.mbVertical )
+ aReqFeatureTagList.push_back( MKTAG("vert") );
+ ULONG nRequestedScript = 0; //MKTAG("hani");//### TODO: where to get script?
+ ULONG nRequestedLangsys = 0; //MKTAG("ZHT"); //### TODO: where to get langsys?
+ // TODO: request more features depending on script and language system
+
+ if( aReqFeatureTagList.size() == 0) // nothing to do
+ return true;
+
+ // load GSUB table into memory
+ ULONG nLength = 0;
+ const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength );
+ if( !pGsubBase )
+ return false;
+
+ // parse GSUB header
+ const FT_Byte* pGsubHeader = pGsubBase;
+ const USHORT nOfsScriptList = GetUShort( pGsubHeader+4 );
+ const USHORT nOfsFeatureTable = GetUShort( pGsubHeader+6 );
+ const USHORT nOfsLookupList = GetUShort( pGsubHeader+8 );
+ pGsubHeader += 10;
+
+ typedef std::vector<USHORT> UshortList;
+ UshortList aFeatureIndexList;
+ UshortList aFeatureOffsetList;
+
+ // parse Script Table
+ const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
+ const USHORT nCntScript = GetUShort( pScriptHeader+0 );
+ pScriptHeader += 2;
+ for( USHORT nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
+ {
+ const ULONG nScriptTag = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang
+ const USHORT nOfsScriptTable= GetUShort( pScriptHeader+4 );
+ pScriptHeader += 6; //###
+ if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) )
+ continue;
+
+ const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable;
+ const USHORT nDefaultLangsysOfs = GetUShort( pScriptTable+0 );
+ const USHORT nCntLangSystem = GetUShort( pScriptTable+2 );
+ pScriptTable += 4;
+ USHORT nLangsysOffset = 0;
+
+ for( USHORT nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
+ {
+ const ULONG nTag = GetUInt( pScriptTable+0 ); // e.g. KOR/ZHS/ZHT/JAN
+ const USHORT nOffset= GetUShort( pScriptTable+4 );
+ pScriptTable += 6;
+ if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) )
+ continue;
+ nLangsysOffset = nOffset;
+ break;
+ }
+
+ if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
+ {
+ const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
+ const USHORT nReqFeatureIdx = GetUShort( pLangSys+2 );
+ const USHORT nCntFeature = GetUShort( pLangSys+4 );
+ pLangSys += 6;
+ aFeatureIndexList.push_back( nReqFeatureIdx );
+ for( USHORT i = 0; i < nCntFeature; ++i )
+ {
+ const USHORT nFeatureIndex = GetUShort( pLangSys );
+ pLangSys += 2;
+ aFeatureIndexList.push_back( nFeatureIndex );
+ }
+ }
+
+ if( nLangsysOffset != 0 )
+ {
+ const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
+ const USHORT nReqFeatureIdx = GetUShort( pLangSys+2 );
+ const USHORT nCntFeature = GetUShort( pLangSys+4 );
+ pLangSys += 6;
+ aFeatureIndexList.push_back( nReqFeatureIdx );
+ for( USHORT i = 0; i < nCntFeature; ++i )
+ {
+ const USHORT nFeatureIndex = GetUShort( pLangSys );
+ pLangSys += 2;
+ aFeatureIndexList.push_back( nFeatureIndex );
+ }
+ }
+ }
+
+ if( !aFeatureIndexList.size() )
+ return true;
+
+ UshortList aLookupIndexList;
+ UshortList aLookupOffsetList;
+
+ // parse Feature Table
+ const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
+ const USHORT nCntFeature = GetUShort( pFeatureHeader );
+ pFeatureHeader += 2;
+ for( USHORT nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
+ {
+ const ULONG nTag = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
+ const USHORT nOffset= GetUShort( pFeatureHeader+4 );
+ pFeatureHeader += 6;
+
+ // short circuit some feature lookups
+ if( aFeatureIndexList[0] != nFeatureIndex ) // required feature?
+ {
+ const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
+ if( !nRequested ) // ignore features that are not requested
+ continue;
+ const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
+ if( !nAvailable ) // some fonts don't provide features they request!
+ continue;
+ }
+
+ const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
+ const USHORT nCntLookups = GetUShort( pFeatureTable+0 );
+ pFeatureTable += 2;
+ for( USHORT i = 0; i < nCntLookups; ++i )
+ {
+ const USHORT nLookupIndex = GetUShort( pFeatureTable );
+ pFeatureTable += 2;
+ aLookupIndexList.push_back( nLookupIndex );
+ }
+ if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
+ aLookupIndexList.push_back( 0 );
+ }
+
+ // parse Lookup List
+ const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
+ const USHORT nCntLookupTable = GetUShort( pLookupHeader );
+ pLookupHeader += 2;
+ for( USHORT nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
+ {
+ const USHORT nOffset = GetUShort( pLookupHeader );
+ pLookupHeader += 2;
+ if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
+ aLookupOffsetList.push_back( nOffset );
+ }
+
+ UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
+ for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
+ {
+ const USHORT nOfsLookupTable = *lookup_it;
+ const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
+ const USHORT eLookupType = GetUShort( pLookupTable+0 );
+ const USHORT nCntLookupSubtable = GetUShort( pLookupTable+4 );
+ pLookupTable += 6;
+
+ // TODO: switch( eLookupType )
+ if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst
+ continue;
+
+ for( USHORT nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
+ {
+ const USHORT nOfsSubLookupTable = GetUShort( pLookupTable );
+ pLookupTable += 2;
+ const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
+
+ const USHORT nFmtSubstitution = GetUShort( pSubLookup+0 );
+ const USHORT nOfsCoverage = GetUShort( pSubLookup+2 );
+ pSubLookup += 4;
+
+ typedef std::pair<USHORT,USHORT> GlyphSubst;
+ typedef std::vector<GlyphSubst> SubstVector;
+ SubstVector aSubstVector;
+
+ const FT_Byte* pCoverage = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
+ const USHORT nFmtCoverage = GetUShort( pCoverage+0 );
+ pCoverage += 2;
+ switch( nFmtCoverage )
+ {
+ case 1: // Coverage Format 1
+ {
+ const USHORT nCntGlyph = GetUShort( pCoverage );
+ pCoverage += 2;
+ aSubstVector.reserve( nCntGlyph );
+ for( USHORT i = 0; i < nCntGlyph; ++i )
+ {
+ const USHORT nGlyphId = GetUShort( pCoverage );
+ pCoverage += 2;
+ aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
+ }
+ }
+ break;
+
+ case 2: // Coverage Format 2
+ {
+ const USHORT nCntRange = GetUShort( pCoverage );
+ pCoverage += 2;
+ for( int i = nCntRange; --i >= 0; )
+ {
+ const UINT32 nGlyph0 = GetUShort( pCoverage+0 );
+ const UINT32 nGlyph1 = GetUShort( pCoverage+2 );
+ const USHORT nCovIdx = GetUShort( pCoverage+4 );
+ pCoverage += 6;
+ for( UINT32 j = nGlyph0; j <= nGlyph1; ++j )
+ aSubstVector.push_back( GlyphSubst( static_cast<USHORT>(j + nCovIdx), 0 ) );
+ }
+ }
+ break;
+ }
+
+ SubstVector::iterator it( aSubstVector.begin() );
+
+ switch( nFmtSubstitution )
+ {
+ case 1: // Single Substitution Format 1
+ {
+ const USHORT nDeltaGlyphId = GetUShort( pSubLookup );
+ pSubLookup += 2;
+ for(; it != aSubstVector.end(); ++it )
+ (*it).second = (*it).first + nDeltaGlyphId;
+ }
+ break;
+
+ case 2: // Single Substitution Format 2
+ {
+ const USHORT nCntGlyph = GetUShort( pSubLookup );
+ pSubLookup += 2;
+ for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
+ {
+ const USHORT nGlyphId = GetUShort( pSubLookup );
+ pSubLookup += 2;
+ (*it).second = nGlyphId;
+ }
+ }
+ break;
+ }
+
+ DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
+ // now apply the glyph substitutions that have been collected in this subtable
+ for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
+ maGlyphSubstitution[ (*it).first ] = (*it).second;
+ }
+ }
+
+ return true;
+}
+
+// =======================================================================
+
diff --git a/vcl/source/glyphs/gcach_ftyp.hxx b/vcl/source/glyphs/gcach_ftyp.hxx
new file mode 100644
index 000000000000..5ebe70bcbdf9
--- /dev/null
+++ b/vcl/source/glyphs/gcach_ftyp.hxx
@@ -0,0 +1,255 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GCACHFTYP_HXX
+#define _SV_GCACHFTYP_HXX
+
+#include <vcl/glyphcache.hxx>
+#include <rtl/textcvt.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+class FreetypeServerFont;
+struct FT_GlyphRec_;
+
+// -----------------------------------------------------------------------
+
+// FtFontFile has the responsibility that a font file is only mapped once.
+// (#86621#) the old directly ft-managed solution caused it to be mapped
+// in up to nTTC*nSizes*nOrientation*nSynthetic times
+class FtFontFile
+{
+public:
+ static FtFontFile* FindFontFile( const ::rtl::OString& rNativeFileName );
+
+ bool Map();
+ void Unmap();
+
+ const unsigned char* GetBuffer() const { return mpFileMap; }
+ int GetFileSize() const { return mnFileSize; }
+ const ::rtl::OString* GetFileName() const { return &maNativeFileName; }
+ int GetLangBoost() const { return mnLangBoost; }
+
+private:
+ FtFontFile( const ::rtl::OString& rNativeFileName );
+
+ const ::rtl::OString maNativeFileName;
+ const unsigned char* mpFileMap;
+ int mnFileSize;
+ int mnRefCount;
+ int mnLangBoost;
+};
+
+// -----------------------------------------------------------------------
+
+// FtFontInfo corresponds to an unscaled font face
+class FtFontInfo
+{
+public:
+ FtFontInfo( const ImplDevFontAttributes&,
+ const ::rtl::OString& rNativeFileName,
+ int nFaceNum, sal_IntPtr nFontId, int nSynthetic,
+ const ExtraKernInfo* );
+ ~FtFontInfo();
+
+ const unsigned char* GetTable( const char*, ULONG* pLength=0 ) const;
+
+ FT_FaceRec_* GetFaceFT();
+ void ReleaseFaceFT( FT_FaceRec_* );
+
+ const ::rtl::OString* GetFontFileName() const { return mpFontFile->GetFileName(); }
+ int GetFaceNum() const { return mnFaceNum; }
+ int GetSynthetic() const { return mnSynthetic; }
+ sal_IntPtr GetFontId() const { return mnFontId; }
+ bool IsSymbolFont() const { return maDevFontAttributes.IsSymbolFont(); }
+ const ImplFontAttributes& GetFontAttributes() const { return maDevFontAttributes; }
+
+ void AnnounceFont( ImplDevFontList* );
+
+ int GetGlyphIndex( sal_UCS4 cChar ) const;
+ void CacheGlyphIndex( sal_UCS4 cChar, int nGI ) const;
+
+ bool HasExtraKerning() const;
+ int GetExtraKernPairs( ImplKernPairData** ) const;
+ int GetExtraGlyphKernValue( int nLeftGlyph, int nRightGlyph ) const;
+
+private:
+ FT_FaceRec_* maFaceFT;
+ FtFontFile* mpFontFile;
+ const int mnFaceNum;
+ int mnRefCount;
+ const int mnSynthetic;
+
+ sal_IntPtr mnFontId;
+ ImplDevFontAttributes maDevFontAttributes;
+
+ // cache unicode->glyphid mapping because looking it up is expensive
+ // TODO: change to hash_multimap when a use case requires a m:n mapping
+ typedef ::std::hash_map<int,int> Int2IntMap;
+ mutable Int2IntMap* mpChar2Glyph;
+ mutable Int2IntMap* mpGlyph2Char;
+ void InitHashes() const;
+
+ const ExtraKernInfo* mpExtraKernInfo;
+};
+
+// these two inlines are very important for performance
+
+inline int FtFontInfo::GetGlyphIndex( sal_UCS4 cChar ) const
+{
+ if( !mpChar2Glyph )
+ return -1;
+ Int2IntMap::const_iterator it = mpChar2Glyph->find( cChar );
+ if( it == mpChar2Glyph->end() )
+ return -1;
+ return it->second;
+}
+
+inline void FtFontInfo::CacheGlyphIndex( sal_UCS4 cChar, int nIndex ) const
+{
+ if( !mpChar2Glyph )
+ InitHashes();
+ (*mpChar2Glyph)[ cChar ] = nIndex;
+ (*mpGlyph2Char)[ nIndex ] = cChar;
+}
+
+// -----------------------------------------------------------------------
+
+class FreetypeManager
+{
+public:
+ FreetypeManager();
+ ~FreetypeManager();
+
+ long AddFontDir( const String& rUrlName );
+ void AddFontFile( const rtl::OString& rNormalizedName,
+ int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes&,
+ const ExtraKernInfo* );
+ void AnnounceFonts( ImplDevFontList* ) const;
+ void ClearFontList();
+
+ FreetypeServerFont* CreateFont( const ImplFontSelectData& );
+
+private:
+ typedef ::std::hash_map<sal_IntPtr,FtFontInfo*> FontList;
+ FontList maFontList;
+
+ sal_IntPtr mnMaxFontId;
+ sal_IntPtr mnNextFontId;
+};
+
+// -----------------------------------------------------------------------
+
+class FreetypeServerFont : public ServerFont
+{
+public:
+ FreetypeServerFont( const ImplFontSelectData&, FtFontInfo* );
+ virtual ~FreetypeServerFont();
+
+ virtual const ::rtl::OString* GetFontFileName() const { return mpFontInfo->GetFontFileName(); }
+ virtual int GetFontFaceNum() const { return mpFontInfo->GetFaceNum(); }
+ virtual bool TestFont() const;
+ virtual void* GetFtFace() const;
+ virtual void SetFontOptions( const ImplFontOptions&);
+ virtual int GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); }
+ virtual bool NeedsArtificialBold() const { return mbArtBold; }
+ virtual bool NeedsArtificialItalic() const { return mbArtItalic; }
+
+ virtual void FetchFontMetric( ImplFontMetricData&, long& rFactor ) const;
+
+ virtual int GetGlyphIndex( sal_UCS4 ) const;
+ int GetRawGlyphIndex( sal_UCS4 ) const;
+ int FixupGlyphIndex( int nGlyphIndex, sal_UCS4 ) const;
+
+ virtual bool GetAntialiasAdvice( void ) const;
+ virtual bool GetGlyphBitmap1( int nGlyphIndex, RawBitmap& ) const;
+ virtual bool GetGlyphBitmap8( int nGlyphIndex, RawBitmap& ) const;
+ virtual bool GetGlyphOutline( int nGlyphIndex, ::basegfx::B2DPolyPolygon& ) const;
+ virtual int GetGlyphKernValue( int nLeftGlyph, int nRightGlyph ) const;
+ virtual ULONG GetKernPairs( ImplKernPairData** ) const;
+
+ const unsigned char* GetTable( const char* pName, ULONG* pLength )
+ { return mpFontInfo->GetTable( pName, pLength ); }
+ int GetEmUnits() const;
+ const FT_Size_Metrics& GetMetricsFT() const { return maSizeFT->metrics; }
+
+protected:
+ friend class GlyphCache;
+
+ int ApplyGlyphTransform( int nGlyphFlags, FT_GlyphRec_*, bool ) const;
+ virtual void InitGlyphData( int nGlyphIndex, GlyphData& ) const;
+ virtual bool GetFontCodeRanges( CmapResult& ) const;
+ bool ApplyGSUB( const ImplFontSelectData& );
+ virtual ServerFontLayoutEngine* GetLayoutEngine();
+
+private:
+ int mnWidth;
+ int mnPrioEmbedded;
+ int mnPrioAntiAlias;
+ int mnPrioAutoHint;
+ FtFontInfo* mpFontInfo;
+ FT_Int mnLoadFlags;
+ double mfStretch;
+ FT_FaceRec_* maFaceFT;
+ FT_SizeRec_* maSizeFT;
+
+ bool mbFaceOk;
+ bool mbArtItalic;
+ bool mbArtBold;
+ bool mbUseGamma;
+
+ typedef ::std::hash_map<int,int> GlyphSubstitution;
+ GlyphSubstitution maGlyphSubstitution;
+ rtl_UnicodeToTextConverter maRecodeConverter;
+
+ ServerFontLayoutEngine* mpLayoutEngine;
+};
+
+// -----------------------------------------------------------------------
+
+class ImplFTSFontData : public ImplFontData
+{
+private:
+ FtFontInfo* mpFtFontInfo;
+ enum { IFTSFONT_MAGIC = 0x1F150A1C };
+
+public:
+ ImplFTSFontData( FtFontInfo*, const ImplDevFontAttributes& );
+
+ FtFontInfo* GetFtFontInfo() const { return mpFtFontInfo; }
+
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ virtual ImplFontData* Clone() const { return new ImplFTSFontData( *this ); }
+ virtual sal_IntPtr GetFontId() const { return mpFtFontInfo->GetFontId(); }
+
+ static bool CheckFontData( const ImplFontData& r ) { return r.CheckMagic( IFTSFONT_MAGIC ); }
+};
+
+// -----------------------------------------------------------------------
+
+#endif // _SV_GCACHFTYP_HXX
diff --git a/vcl/source/glyphs/gcach_layout.cxx b/vcl/source/glyphs/gcach_layout.cxx
new file mode 100644
index 000000000000..a9f9167062ba
--- /dev/null
+++ b/vcl/source/glyphs/gcach_layout.cxx
@@ -0,0 +1,644 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define ENABLE_ICU_LAYOUT
+#include <gcach_ftyp.hxx>
+#include <vcl/sallayout.hxx>
+#include <vcl/salgdi.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include <sal/alloca.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdio>
+#endif
+#include <rtl/instance.hxx>
+
+namespace { struct SimpleLayoutEngine : public rtl::Static< ServerFontLayoutEngine, SimpleLayoutEngine > {}; }
+
+// =======================================================================
+// layout implementation for ServerFont
+// =======================================================================
+
+ServerFontLayout::ServerFontLayout( ServerFont& rFont )
+: mrServerFont( rFont )
+{}
+
+void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
+{
+ rSalGraphics.DrawServerFontLayout( *this );
+}
+
+// -----------------------------------------------------------------------
+
+bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ ServerFontLayoutEngine* pLE = NULL;
+ if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED) )
+ pLE = mrServerFont.GetLayoutEngine();
+ if( !pLE )
+ pLE = &SimpleLayoutEngine::get();
+
+ bool bRet = (*pLE)( *this, rArgs );
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ GenericSalLayout::AdjustLayout( rArgs );
+
+ // apply asian kerning if the glyphs are not already formatted
+ if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN)
+ && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) )
+ if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
+ ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
+
+ // insert kashidas where requested by the formatting array
+ if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray )
+ {
+ int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
+ if( nKashidaIndex != 0 )
+ {
+ const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
+ KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
+ // TODO: kashida-GSUB/GPOS
+ }
+ }
+}
+
+// =======================================================================
+
+bool ServerFontLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
+{
+ FreetypeServerFont& rFont = static_cast<FreetypeServerFont&>(rLayout.GetServerFont());
+
+ Point aNewPos( 0, 0 );
+ int nOldGlyphId = -1;
+ int nGlyphWidth = 0;
+ GlyphItem aPrevItem;
+ bool bRightToLeft;
+ for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); )
+ {
+ sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
+ if( (cChar >= 0xD800) && (cChar <= 0xDFFF) )
+ {
+ if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
+ continue;
+ cChar = 0x10000 + ((cChar - 0xD800) << 10)
+ + (rArgs.mpStr[ nCharPos+1 ] - 0xDC00);
+ }
+
+ if( bRightToLeft )
+ cChar = GetMirroredChar( cChar );
+ int nGlyphIndex = rFont.GetGlyphIndex( cChar );
+ // when glyph fallback is needed update LayoutArgs
+ if( !nGlyphIndex ) {
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+ if( cChar >= 0x10000 ) // handle surrogate pairs
+ rArgs.NeedFallback( nCharPos+1, bRightToLeft );
+ }
+
+ // apply pair kerning to prev glyph if requested
+ if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
+ {
+ int nKernValue = rFont.GetGlyphKernValue( nOldGlyphId, nGlyphIndex );
+ nGlyphWidth += nKernValue;
+ aPrevItem.mnNewWidth = nGlyphWidth;
+ }
+
+ // finish previous glyph
+ if( nOldGlyphId >= 0 )
+ rLayout.AppendGlyph( aPrevItem );
+ aNewPos.X() += nGlyphWidth;
+
+ // prepare GlyphItem for appending it in next round
+ nOldGlyphId = nGlyphIndex;
+ const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
+ nGlyphWidth = rGM.GetCharWidth();
+ int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
+ aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
+ }
+
+ // append last glyph item if any
+ if( nOldGlyphId >= 0 )
+ rLayout.AppendGlyph( aPrevItem );
+
+ return true;
+}
+
+// =======================================================================
+// bridge to ICU LayoutEngine
+// =======================================================================
+
+#ifdef ENABLE_ICU_LAYOUT
+
+#define bool_t signed char
+
+// disable warnings in icu layout headers
+#if defined __SUNPRO_CC
+#pragma disable_warn
+#endif
+
+#include <layout/LayoutEngine.h>
+#include <layout/LEFontInstance.h>
+#include <layout/LEScripts.h>
+
+// enable warnings again
+#if defined __SUNPRO_CC
+#pragma enable_warn
+#endif
+
+#include <unicode/uscript.h>
+#include <unicode/ubidi.h>
+
+using namespace U_ICU_NAMESPACE;
+
+static const LEGlyphID ICU_DELETED_GLYPH = 0xFFFF;
+static const LEGlyphID ICU_MARKED_GLYPH = 0xFFFE;
+
+// -----------------------------------------------------------------------
+
+class IcuFontFromServerFont
+: public LEFontInstance
+{
+private:
+ FreetypeServerFont& mrServerFont;
+
+public:
+ IcuFontFromServerFont( FreetypeServerFont& rFont )
+ : mrServerFont( rFont )
+ {}
+
+ virtual const void* getFontTable(LETag tableTag) const;
+ virtual le_int32 getUnitsPerEM() const;
+ virtual float getXPixelsPerEm() const;
+ virtual float getYPixelsPerEm() const;
+ virtual float getScaleFactorX() const;
+ virtual float getScaleFactorY() const;
+
+ using LEFontInstance::mapCharToGlyph;
+ virtual LEGlyphID mapCharToGlyph( LEUnicode32 ch ) const;
+
+ virtual le_int32 getAscent() const;
+ virtual le_int32 getDescent() const;
+ virtual le_int32 getLeading() const;
+
+ virtual void getGlyphAdvance( LEGlyphID glyph, LEPoint &advance ) const;
+ virtual le_bool getGlyphPoint( LEGlyphID glyph, le_int32 pointNumber, LEPoint& point ) const;
+};
+
+// -----------------------------------------------------------------------
+
+const void* IcuFontFromServerFont::getFontTable( LETag nICUTableTag ) const
+{
+ char pTagName[5];
+ pTagName[0] = (char)(nICUTableTag >> 24);
+ pTagName[1] = (char)(nICUTableTag >> 16);
+ pTagName[2] = (char)(nICUTableTag >> 8);
+ pTagName[3] = (char)(nICUTableTag);
+ pTagName[4] = 0;
+
+ ULONG nLength;
+ const unsigned char* pBuffer = mrServerFont.GetTable( pTagName, &nLength );
+#ifdef VERBOSE_DEBUG
+ fprintf(stderr,"IcuGetTable(\"%s\") => %p\n", pTagName, pBuffer);
+ int mnHeight = mrServerFont.GetFontSelData().mnHeight;
+ const char* pName = mrServerFont.GetFontFileName()->getStr();
+ fprintf(stderr,"font( h=%d, \"%s\" )\n", mnHeight, pName );
+#endif
+ return (const void*)pBuffer;
+}
+
+// -----------------------------------------------------------------------
+
+le_int32 IcuFontFromServerFont::getUnitsPerEM() const
+{
+ return mrServerFont.GetEmUnits();
+}
+
+// -----------------------------------------------------------------------
+
+float IcuFontFromServerFont::getXPixelsPerEm() const
+{
+ const ImplFontSelectData& r = mrServerFont.GetFontSelData();
+ float fX = r.mnWidth ? r.mnWidth : r.mnHeight;
+ return fX;
+}
+
+// -----------------------------------------------------------------------
+
+float IcuFontFromServerFont::getYPixelsPerEm() const
+{
+ float fY = mrServerFont.GetFontSelData().mnHeight;
+ return fY;
+}
+
+// -----------------------------------------------------------------------
+
+float IcuFontFromServerFont::getScaleFactorX() const
+{
+ return 1.0;
+}
+
+// -----------------------------------------------------------------------
+
+float IcuFontFromServerFont::getScaleFactorY() const
+{
+ return 1.0;
+}
+
+// -----------------------------------------------------------------------
+
+LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch ) const
+{
+ LEGlyphID nGlyphIndex = mrServerFont.GetRawGlyphIndex( ch );
+ return nGlyphIndex;
+}
+
+// -----------------------------------------------------------------------
+
+le_int32 IcuFontFromServerFont::getAscent() const
+{
+ const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
+ le_int32 nAscent = (+rMetrics.ascender + 32) >> 6;
+ return nAscent;
+}
+
+// -----------------------------------------------------------------------
+
+le_int32 IcuFontFromServerFont::getDescent() const
+{
+ const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
+ le_int32 nDescent = (-rMetrics.descender + 32) >> 6;
+ return nDescent;
+}
+
+// -----------------------------------------------------------------------
+
+le_int32 IcuFontFromServerFont::getLeading() const
+{
+ const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
+ le_int32 nLeading = ((rMetrics.height - rMetrics.ascender + rMetrics.descender) + 32) >> 6;
+ return nLeading;
+}
+
+// -----------------------------------------------------------------------
+
+void IcuFontFromServerFont::getGlyphAdvance( LEGlyphID nGlyphIndex,
+ LEPoint &advance ) const
+{
+ if( (nGlyphIndex == ICU_MARKED_GLYPH)
+ || (nGlyphIndex == ICU_DELETED_GLYPH) )
+ {
+ // deleted glyph or mark glyph has not advance
+ advance.fX = 0;
+ }
+ else
+ {
+ const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nGlyphIndex );
+ advance.fX = rGM.GetCharWidth();
+ }
+
+ advance.fY = 0;
+}
+
+// -----------------------------------------------------------------------
+
+le_bool IcuFontFromServerFont::getGlyphPoint( LEGlyphID,
+ le_int32
+#if OSL_DEBUG_LEVEL > 1
+pointNumber
+#endif
+ ,
+ LEPoint& ) const
+{
+ //TODO: replace dummy implementation
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr,"getGlyphPoint(%d)\n", pointNumber );
+#endif
+ return false;
+}
+
+// =======================================================================
+
+class IcuLayoutEngine : public ServerFontLayoutEngine
+{
+private:
+ IcuFontFromServerFont maIcuFont;
+
+ le_int32 meScriptCode;
+ LayoutEngine* mpIcuLE;
+
+public:
+ IcuLayoutEngine( FreetypeServerFont& );
+ virtual ~IcuLayoutEngine();
+
+ virtual bool operator()( ServerFontLayout&, ImplLayoutArgs& );
+};
+
+// -----------------------------------------------------------------------
+
+IcuLayoutEngine::IcuLayoutEngine( FreetypeServerFont& rServerFont )
+: maIcuFont( rServerFont ),
+ meScriptCode( USCRIPT_INVALID_CODE ),
+ mpIcuLE( NULL )
+{}
+
+// -----------------------------------------------------------------------
+
+IcuLayoutEngine::~IcuLayoutEngine()
+{
+ if( mpIcuLE )
+ delete mpIcuLE;
+}
+
+// -----------------------------------------------------------------------
+
+static bool lcl_CharIsJoiner(sal_Unicode cChar)
+{
+ return ((cChar == 0x200C) || (cChar == 0x200D));
+}
+
+bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
+{
+ LEUnicode* pIcuChars;
+ if( sizeof(LEUnicode) == sizeof(*rArgs.mpStr) )
+ pIcuChars = (LEUnicode*)rArgs.mpStr;
+ else
+ {
+ // this conversion will only be needed when either
+ // ICU's or OOo's unicodes stop being unsigned shorts
+ // TODO: watch out for surrogates!
+ pIcuChars = (LEUnicode*)alloca( rArgs.mnLength * sizeof(LEUnicode) );
+ for( xub_StrLen ic = 0; ic < rArgs.mnLength; ++ic )
+ pIcuChars[ic] = static_cast<LEUnicode>( rArgs.mpStr[ic] );
+ }
+
+ // allocate temporary arrays, note: round to even
+ int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1;
+
+ struct IcuPosition{ float fX, fY; };
+ const int nAllocSize = sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(IcuPosition);
+ LEGlyphID* pIcuGlyphs = (LEGlyphID*)alloca( (nGlyphCapacity * nAllocSize) + sizeof(IcuPosition) );
+ le_int32* pCharIndices = (le_int32*)((char*)pIcuGlyphs + nGlyphCapacity * sizeof(LEGlyphID) );
+ IcuPosition* pGlyphPositions = (IcuPosition*)((char*)pCharIndices + nGlyphCapacity * sizeof(le_int32) );
+
+ FreetypeServerFont& rFont = reinterpret_cast<FreetypeServerFont&>(rLayout.GetServerFont());
+
+ UErrorCode rcI18n = U_ZERO_ERROR;
+ LEErrorCode rcIcu = LE_NO_ERROR;
+ Point aNewPos( 0, 0 );
+ for( int nGlyphCount = 0;; )
+ {
+ int nMinRunPos, nEndRunPos;
+ bool bRightToLeft;
+ if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) )
+ break;
+
+ // find matching script
+ // TODO: split up bidi run into script runs
+ le_int32 eScriptCode = -1;
+ for( int i = nMinRunPos; i < nEndRunPos; ++i )
+ {
+ eScriptCode = uscript_getScript( pIcuChars[i], &rcI18n );
+ if( (eScriptCode > 0) && (eScriptCode != latnScriptCode) )
+ break;
+ }
+ if( eScriptCode < 0 ) // TODO: handle errors better
+ eScriptCode = latnScriptCode;
+
+ // get layout engine matching to this script
+ // no engine change necessary if script is latin
+ if( !mpIcuLE || ((eScriptCode != meScriptCode) && (eScriptCode > USCRIPT_INHERITED)) )
+ {
+ // TODO: cache multiple layout engines when multiple scripts are used
+ delete mpIcuLE;
+ meScriptCode = eScriptCode;
+ le_int32 eLangCode = 0; // TODO: get better value
+ mpIcuLE = LayoutEngine::layoutEngineFactory( &maIcuFont, eScriptCode, eLangCode, rcIcu );
+ if( LE_FAILURE(rcIcu) )
+ {
+ delete mpIcuLE;
+ mpIcuLE = NULL;
+ }
+ }
+
+ // fall back to default layout if needed
+ if( !mpIcuLE )
+ break;
+
+ // run ICU layout engine
+ // TODO: get enough context, remove extra glyps below
+ int nRawRunGlyphCount = mpIcuLE->layoutChars( pIcuChars,
+ nMinRunPos, nEndRunPos - nMinRunPos, rArgs.mnLength,
+ bRightToLeft, aNewPos.X(), aNewPos.Y(), rcIcu );
+ if( LE_FAILURE(rcIcu) )
+ return false;
+
+ // import layout info from icu
+ mpIcuLE->getGlyphs( pIcuGlyphs, rcIcu );
+ mpIcuLE->getCharIndices( pCharIndices, rcIcu );
+ mpIcuLE->getGlyphPositions( &pGlyphPositions->fX, rcIcu );
+ mpIcuLE->reset(); // TODO: get rid of this, PROBLEM: crash at exit when removed
+ if( LE_FAILURE(rcIcu) )
+ return false;
+
+ // layout bidi/script runs and export them to a ServerFontLayout
+ // convert results to GlyphItems
+ int nLastCharPos = -1;
+ int nClusterMinPos = -1;
+ int nClusterMaxPos = -1;
+ bool bClusterStart = true;
+ int nFilteredRunGlyphCount = 0;
+ const IcuPosition* pPos = pGlyphPositions;
+ for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos )
+ {
+ LEGlyphID nGlyphIndex = pIcuGlyphs[i];
+ // ignore glyphs which were marked or deleted by ICU
+ if( (nGlyphIndex == ICU_MARKED_GLYPH)
+ || (nGlyphIndex == ICU_DELETED_GLYPH) )
+ continue;
+
+ // adjust the relative char pos
+ int nCharPos = pCharIndices[i];
+ if( nCharPos >= 0 ) {
+ nCharPos += nMinRunPos;
+ // ICU seems to return bad pCharIndices
+ // for some combinations of ICU+font+text
+ // => better give up now than crash later
+ if( nCharPos >= nEndRunPos )
+ continue;
+ }
+
+ // if needed request glyph fallback by updating LayoutArgs
+ if( !nGlyphIndex )
+ {
+ if( nCharPos >= 0 )
+ {
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+ if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) )
+ rArgs.NeedFallback( nCharPos-1, bRightToLeft );
+ else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) )
+ rArgs.NeedFallback( nCharPos+1, bRightToLeft );
+ }
+
+ if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags )
+ continue;
+ }
+
+
+ // apply vertical flags, etc.
+ bool bDiacritic = false;
+ if( nCharPos >= 0 )
+ {
+ sal_UCS4 aChar = rArgs.mpStr[ nCharPos ];
+#if 0 // TODO: enable if some unicodes>0xFFFF should need glyph flags!=0
+ if( (aChar >= 0xD800) && (aChar <= 0xDFFF) )
+ {
+ if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
+ continue;
+ // calculate unicode scalar value of surrogate pair
+ aChar = 0x10000 + ((aChar - 0xD800) << 10);
+ sal_UCS4 aLow = rArgs.mpStr[ nCharPos+1 ];
+ aChar += aLow & 0x03FF;
+ }
+#endif
+ nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar );
+
+ // #i99367# HACK: try to detect all diacritics
+ if( aChar>=0x0300 && aChar<0x2100 )
+ bDiacritic = IsDiacritic( aChar );
+ }
+
+ // get glyph position and its metrics
+ aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
+ const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
+ int nGlyphWidth = rGM.GetCharWidth();
+ if( nGlyphWidth <= 0 )
+ bDiacritic |= true;
+ // #i99367# force all diacritics to zero width
+ // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth
+ else if( bDiacritic )
+ nGlyphWidth = 0;
+
+ // heuristic to detect glyph clusters
+ bool bInCluster = true;
+ if( nLastCharPos == -1 )
+ {
+ nClusterMinPos = nClusterMaxPos = nCharPos;
+ bInCluster = false;
+ }
+ else if( !bRightToLeft )
+ {
+ // left-to-right case
+ if( nClusterMinPos > nCharPos )
+ nClusterMinPos = nCharPos; // extend cluster
+ else if( nCharPos <= nClusterMaxPos )
+ /*NOTHING*/; // inside cluster
+ else if( bDiacritic )
+ nClusterMaxPos = nCharPos; // add diacritic to cluster
+ else {
+ nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
+ bInCluster = false;
+ }
+ }
+ else
+ {
+ // right-to-left case
+ if( nClusterMaxPos < nCharPos )
+ nClusterMaxPos = nCharPos; // extend cluster
+ else if( nCharPos >= nClusterMinPos )
+ /*NOTHING*/; // inside cluster
+ else if( bDiacritic )
+ {
+ nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*]
+ if( bClusterStart ) {
+ nClusterMaxPos = nCharPos;
+ bInCluster = false;
+ }
+ }
+ else
+ {
+ nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
+ bInCluster = !bClusterStart;
+ }
+ }
+
+ long nGlyphFlags = 0;
+ if( bInCluster )
+ nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
+ if( bRightToLeft )
+ nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
+ if( bDiacritic )
+ nGlyphFlags |= GlyphItem::IS_DIACRITIC;
+
+ // add resulting glyph item to layout
+ const GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
+ rLayout.AppendGlyph( aGI );
+ ++nFilteredRunGlyphCount;
+ nLastCharPos = nCharPos;
+ bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath
+ }
+ aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
+ nGlyphCount += nFilteredRunGlyphCount;
+ }
+
+ // sort glyphs in visual order
+ // and then in logical order (e.g. diacritics after cluster start)
+ rLayout.SortGlyphItems();
+
+ // determine need for kashida justification
+ if( (rArgs.mpDXArray || rArgs.mnLayoutWidth)
+ && ((meScriptCode == arabScriptCode) || (meScriptCode == syrcScriptCode)) )
+ rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
+
+ return true;
+}
+
+#endif // ENABLE_ICU_LAYOUT
+
+// =======================================================================
+
+ServerFontLayoutEngine* FreetypeServerFont::GetLayoutEngine()
+{
+ // find best layout engine for font, platform, script and language
+#ifdef ENABLE_ICU_LAYOUT
+ if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) )
+ mpLayoutEngine = new IcuLayoutEngine( *this );
+#endif // ENABLE_ICU_LAYOUT
+
+ return mpLayoutEngine;
+}
+
+// =======================================================================
+
diff --git a/vcl/source/glyphs/gcach_rbmp.cxx b/vcl/source/glyphs/gcach_rbmp.cxx
new file mode 100644
index 000000000000..5ea80da77794
--- /dev/null
+++ b/vcl/source/glyphs/gcach_rbmp.cxx
@@ -0,0 +1,274 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/glyphcache.hxx>
+#include <string.h>
+
+//------------------------------------------------------------------------
+
+RawBitmap::RawBitmap()
+: mpBits(0), mnAllocated(0)
+{}
+
+//------------------------------------------------------------------------
+
+RawBitmap::~RawBitmap()
+{
+ delete[] mpBits;
+ mpBits = 0;
+ mnAllocated = 0;
+}
+
+//------------------------------------------------------------------------
+
+// used by 90 and 270 degree rotations on 8 bit deep bitmaps
+static void ImplRotate8_90( unsigned char* p1, const unsigned char* p2,
+ int xmax, int ymax, int dx, int dy, int nPad )
+{
+ for( int y = ymax; --y >= 0; p2 += dy )
+ {
+ for( int x = xmax; --x >= 0; p2 += dx )
+ *(p1++) = *p2;
+ for( int i = nPad; --i >= 0; )
+ *(p1++) = 0;
+ }
+}
+
+//------------------------------------------------------------------------
+
+// used by inplace 180 degree rotation on 8 bit deep bitmaps
+static void ImplRotate8_180( unsigned char* p1, int xmax, int ymax, int nPad )
+{
+ unsigned char* p2 = p1 + ymax * (xmax + nPad);
+ for( int y = ymax/2; --y >= 0; )
+ {
+ p2 -= nPad;
+ for( int x = xmax; --x >= 0; )
+ {
+ unsigned char cTmp = *(--p2);
+ *p2 = *p1;
+ *(p1++) = cTmp;
+ }
+ p1 += nPad;
+ }
+
+ // reverse middle line
+ p2 -= nPad;
+ while( p1 < p2 )
+ {
+ unsigned char cTmp = *(--p2);
+ *p2 = *p1;
+ *(p1++) = cTmp;
+ }
+}
+
+//------------------------------------------------------------------------
+
+// used by 90 or 270 degree rotations on 1 bit deep bitmaps
+static void ImplRotate1_90( unsigned char* p1, const unsigned char* p2,
+ int xmax, int ymax, int dx, int nShift, int nDeltaShift, int nPad )
+{
+ for( int y = ymax; --y >= 0; )
+ {
+ unsigned nTemp = 1;
+ const unsigned char* p20 = p2;
+ for( int x = xmax; --x >= 0; p2 += dx )
+ {
+ // build bitwise and store when byte finished
+ nTemp += nTemp + ((*p2 >> nShift) & 1);
+ if( nTemp >= 0x100U )
+ {
+ *(p1++) = (unsigned char)nTemp;
+ nTemp = 1;
+ }
+ }
+ p2 = p20;
+
+ // store left aligned remainder if needed
+ if( nTemp > 1 )
+ {
+ for(; nTemp < 0x100U; nTemp += nTemp ) ;
+ *(p1++) = (unsigned char)nTemp;
+ }
+ // pad scanline with zeroes
+ for( int i = nPad; --i >= 0;)
+ *(p1++) = 0;
+
+ // increase/decrease shift, but keep bound inside 0 to 7
+ nShift += nDeltaShift;
+ if( nShift != (nShift & 7) )
+ p2 -= nDeltaShift;
+ nShift &= 7;
+ }
+}
+
+//------------------------------------------------------------------------
+
+// used by 180 degrees rotations on 1 bit deep bitmaps
+static void ImplRotate1_180( unsigned char* p1, const unsigned char* p2,
+ int xmax, int ymax, int nPad )
+{
+ --p2;
+ for( int y = ymax; --y >= 0; )
+ {
+ p2 -= nPad;
+
+ unsigned nTemp = 1;
+ unsigned nInp = (0x100 + *p2) >> (-xmax & 7);
+ for( int x = xmax; --x >= 0; )
+ {
+ // build bitwise and store when byte finished
+ nTemp += nTemp + (nInp & 1);
+ if( nTemp >= 0x100 )
+ {
+ *(p1++) = (unsigned char)nTemp;
+ nTemp = 1;
+ }
+ // update input byte if needed (and available)
+ if( (nInp >>= 1) <= 1 && ((y != 0) || (x != 0)) )
+ nInp = 0x100 + *(--p2);
+ }
+
+ // store left aligned remainder if needed
+ if( nTemp > 1 )
+ {
+ for(; nTemp < 0x100; nTemp += nTemp ) ;
+ *(p1++) = (unsigned char)nTemp;
+ }
+ // scanline pad is already clean
+ p1 += nPad;
+ }
+}
+
+//------------------------------------------------------------------------
+
+bool RawBitmap::Rotate( int nAngle )
+{
+ ULONG nNewScanlineSize = 0;
+ ULONG nNewHeight = 0;
+ ULONG nNewWidth = 0;
+
+ // do inplace rotation or prepare double buffered rotation
+ switch( nAngle )
+ {
+ case 0: // nothing to do
+ case 3600:
+ return true;
+ default: // non rectangular angles not allowed
+ return false;
+ case 1800: // rotate by 180 degrees
+ mnXOffset = -(mnXOffset + mnWidth);
+ mnYOffset = -(mnYOffset + mnHeight);
+ if( mnBitCount == 8 )
+ {
+ ImplRotate8_180( mpBits, mnWidth, mnHeight, mnScanlineSize-mnWidth );
+ return true;
+ }
+ nNewWidth = mnWidth;
+ nNewHeight = mnHeight;
+ nNewScanlineSize = mnScanlineSize;
+ break;
+ case +900: // left by 90 degrees
+ case -900:
+ case 2700: // right by 90 degrees
+ nNewWidth = mnHeight;
+ nNewHeight = mnWidth;
+ if( mnBitCount==1 )
+ nNewScanlineSize = (nNewWidth + 7) / 8;
+ else
+ nNewScanlineSize = (nNewWidth + 3) & -4;
+ break;
+ }
+
+ unsigned int nBufSize = nNewHeight * nNewScanlineSize;
+ unsigned char* pBuf = new unsigned char[ nBufSize ];
+ if( !pBuf )
+ return false;
+
+ memset( pBuf, 0, nBufSize );
+ int i;
+
+ // dispatch non-inplace rotations
+ switch( nAngle )
+ {
+ case 1800: // rotate by 180 degrees
+ // we know we only need to deal with 1 bit depth
+ ImplRotate1_180( pBuf, mpBits + mnHeight * mnScanlineSize,
+ mnWidth, mnHeight, mnScanlineSize - (mnWidth + 7) / 8 );
+ break;
+ case +900: // rotate left by 90 degrees
+ i = mnXOffset;
+ mnXOffset = mnYOffset;
+ mnYOffset = -nNewHeight - i;
+ if( mnBitCount == 8 )
+ ImplRotate8_90( pBuf, mpBits + mnWidth - 1,
+ nNewWidth, nNewHeight, +mnScanlineSize, -1-mnHeight*mnScanlineSize,
+ nNewScanlineSize - nNewWidth );
+ else
+ ImplRotate1_90( pBuf, mpBits + (mnWidth - 1) / 8,
+ nNewWidth, nNewHeight, +mnScanlineSize,
+ (-mnWidth & 7), +1, nNewScanlineSize - (nNewWidth + 7) / 8 );
+ break;
+ case 2700: // rotate right by 90 degrees
+ case -900:
+ i = mnXOffset;
+ mnXOffset = -(nNewWidth + mnYOffset);
+ mnYOffset = i;
+ if( mnBitCount == 8 )
+ ImplRotate8_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
+ nNewWidth, nNewHeight, -mnScanlineSize, +1+mnHeight*mnScanlineSize,
+ nNewScanlineSize - nNewWidth );
+ else
+ ImplRotate1_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
+ nNewWidth, nNewHeight, -mnScanlineSize,
+ +7, -1, nNewScanlineSize - (nNewWidth + 7) / 8 );
+ break;
+ }
+
+ mnWidth = nNewWidth;
+ mnHeight = nNewHeight;
+ mnScanlineSize = nNewScanlineSize;
+
+ if( nBufSize < mnAllocated )
+ {
+ memcpy( mpBits, pBuf, nBufSize );
+ delete[] pBuf;
+ }
+ else
+ {
+ delete[] mpBits;
+ mpBits = pBuf;
+ mnAllocated = nBufSize;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------
diff --git a/vcl/source/glyphs/gcach_vdev.cxx b/vcl/source/glyphs/gcach_vdev.cxx
new file mode 100644
index 000000000000..8cd45cf58224
--- /dev/null
+++ b/vcl/source/glyphs/gcach_vdev.cxx
@@ -0,0 +1,287 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <gcach_vdev.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/outfont.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/metric.hxx>
+
+// =======================================================================
+// VirtDevServerFont
+// =======================================================================
+
+// -----------------------------------------------------------------------
+
+void VirtDevServerFont::AnnounceFonts( ImplDevFontList* pToAdd )
+{
+ // TODO: get fonts on server but not on client,
+ // problem is that currently there is no serverside virtual device...
+ VirtualDevice vdev( 1 );
+ long nCount = vdev.GetDevFontCount();
+
+ for( int i = 0; i < nCount; ++i )
+ {
+ const FontInfo aFontInfo = vdev.GetDevFont( i );
+
+ ImplFontData& rData = *new ImplFontData;
+ rData.SetSysData( new FontSysData( (void*)SERVERFONT_MAGIC ) );
+
+ rData.maName = aFontInfo.GetName();
+ rData.maStyleName = aFontInfo.GetStyleName();
+ rData.mnWidth = aFontInfo.GetWidth();
+ rData.mnHeight = aFontInfo.GetHeight();
+ rData.meFamily = aFontInfo.GetFamily();
+ rData.meCharSet = aFontInfo.GetCharSet();
+ rData.mePitch = aFontInfo.GetPitch();
+ rData.meWidthType = aFontInfo.GetWidthType();
+ rData.meWeight = aFontInfo.GetWeight();
+ rData.meItalic = aFontInfo.GetItalic();
+ rData.meType = aFontInfo.GetType();
+ rData.meFamily = aFontInfo.GetFamily();
+
+ rData.mbOrientation = true; // TODO: where to get this info?
+ rData.mbDevice = false;
+ rData.mnQuality = 0; // prefer client-side fonts if available
+
+ pToAdd->Add( &rData );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void VirtDevServerFont::ClearFontList()
+{
+ // TODO
+}
+
+// -----------------------------------------------------------------------
+
+VirtDevServerFont* VirtDevServerFont::CreateFont( const ImplFontSelectData& rFSD )
+{
+ VirtDevServerFont* pServerFont = NULL;
+ // TODO: search list of VirtDevServerFonts, return NULL if not found
+ // pServerFont = new VirtDevServerFont( rFSD );
+ return pServerFont;
+}
+
+// -----------------------------------------------------------------------
+
+VirtDevServerFont::VirtDevServerFont( const ImplFontSelectData& rFSD )
+: ServerFont( rFSD)
+{}
+
+// -----------------------------------------------------------------------
+
+void VirtDevServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
+{
+ const ImplFontSelectData& aFSD = GetFontSelData();
+
+ Font aFont;
+ aFont.SetName ( aFSD.maName );
+ aFont.SetStyleName ( aFSD.maStyleName );
+ aFont.SetHeight ( aFSD.mnHeight );
+ aFont.SetWidth ( aFSD.mnWidth );
+ aFont.SetOrientation( aFSD.mnOrientation );
+ aFont.SetVertical ( GetFontSelData().mbVertical );
+
+ VirtualDevice vdev( 1 );
+ FontMetric aMetric( vdev.GetFontMetric( aFont ) );
+
+ rFactor = 0x100;
+
+ rTo.mnAscent = aMetric.GetAscent();
+ rTo.mnDescent = aMetric.GetDescent();
+ rTo.mnIntLeading = aMetric.GetIntLeading();
+ rTo.mnExtLeading = aMetric.GetExtLeading();
+ rTo.mnSlant = aMetric.GetSlant();
+ rTo.meType = aMetric.GetType();
+ rTo.mnFirstChar = 0x0020; // TODO: where to get this info?
+ rTo.mnLastChar = 0xFFFE; // TODO: where to get this info?
+
+ rTo.mnWidth = aFSD.mnWidth;
+ rTo.maName = aFSD.maName;
+ rTo.maStyleName = aFSD.maStyleName;
+ rTo.mnOrientation = aFSD.mnOrientation;
+ rTo.meFamily = aFSD.meFamily;
+ rTo.meCharSet = aFSD.meCharSet;
+ rTo.meWeight = aFSD.meWeight;
+ rTo.meItalic = aFSD.meItalic;
+ rTo.mePitch = aFSD.mePitch;
+ rTo.mbDevice = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+int VirtDevServerFont::GetGlyphIndex( sal_Unicode aChar ) const
+{
+ return aChar;
+}
+
+// -----------------------------------------------------------------------
+
+void VirtDevServerFont::InitGlyphData( int nGlyphIndex, GlyphData& rGD ) const
+{
+ Font aFont;
+ aFont.SetName ( GetFontSelData().maName );
+ aFont.SetStyleName ( GetFontSelData().maStyleName );
+ aFont.SetHeight ( GetFontSelData().mnHeight );
+ aFont.SetWidth ( GetFontSelData().mnWidth );
+ aFont.SetOrientation( GetFontSelData().mnOrientation );
+ aFont.SetVertical ( GetFontSelData().mbVertical );
+
+ VirtualDevice vdev( 1 );
+ vdev.SetFont( aFont );
+
+ // get glyph metrics
+ sal_Int32 nCharWidth = 10;
+// TODO: vdev.GetCharWidth( nGlyphIndex, nGlyphIndex, &nCharWidth );
+ rGD.SetCharWidth( nCharWidth );
+
+ sal_Unicode aChar = nGlyphIndex;
+ String aGlyphStr( &aChar, 1 );
+ Rectangle aRect;
+ if( vdev.GetTextBoundRect( aRect, aGlyphStr, 0, 1 ) )
+ {
+ rGD.SetOffset( aRect.Top(), aRect.Left() );
+ rGD.SetDelta( vdev.GetTextWidth( nGlyphIndex ), 0 );
+ rGD.SetSize( aRect.GetSize() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool VirtDevServerFont::GetAntialiasAdvice( void ) const
+{
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+bool VirtDevServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& ) const
+{
+ /*
+ sal_Unicode aChar = nGlyphIndex;
+ String aGlyphStr( &aChar, 1 );
+
+ // draw bitmap
+ vdev.SetOutputSizePixel( aSize, TRUE );
+ vdev.DrawText( Point(0,0)-rGD.GetMetric().GetOffset(), aGlyphStr );
+
+ // create new glyph item
+
+ const Bitmap& rBitmap = vdev.GetBitmap( Point(0,0), aSize );
+ rGD.SetBitmap( new Bitmap( rBitmap ) );
+ return true;
+ */
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+bool VirtDevServerFont::GetGlyphBitmap8( int nGlyphIndex, RawBitmap& ) const
+{
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+int VirtDevServerFont::GetGlyphKernValue( int, int ) const
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG VirtDevServerFont::GetKernPairs( ImplKernPairData** ppImplKernPairs ) const
+{
+ Font aFont;
+ aFont.SetName ( GetFontSelData().maName );
+ aFont.SetStyleName ( GetFontSelData().maStyleName );
+ aFont.SetHeight ( GetFontSelData().mnHeight );
+ aFont.SetWidth ( GetFontSelData().mnWidth );
+ aFont.SetOrientation( GetFontSelData().mnOrientation );
+ aFont.SetVertical ( GetFontSelData().mbVertical );
+
+ VirtualDevice vdev( 1 );
+ vdev.SetFont( aFont );
+
+ ULONG nPairs = vdev.GetKerningPairCount();
+ if( nPairs > 0 )
+ {
+ KerningPair* const pKernPairs = new KerningPair[ nPairs ];
+ vdev.GetKerningPairs( nPairs, pKernPairs );
+
+ *ppImplKernPairs = new ImplKernPairData[ nPairs ];
+ ImplKernPairData* pTo = *ppImplKernPairs;
+ KerningPair* pFrom = pKernPairs;
+ for ( ULONG n = 0; n < nPairs; n++ )
+ {
+ pTo->mnChar1 = pFrom->nChar1;
+ pTo->mnChar2 = pFrom->nChar2;
+ pTo->mnKern = pFrom->nKern;
+ ++pFrom;
+ ++pTo;
+ }
+
+ delete[] pKernPairs;
+ }
+
+ return nPairs;
+}
+
+// -----------------------------------------------------------------------
+
+bool VirtDevServerFont::GetGlyphOutline( int nGlyphIndex, PolyPolygon& rPolyPoly ) const
+{
+ return false;
+ /*
+ Font aFont;
+ aFont.SetName ( GetFontSelData().maName );
+ aFont.SetStyleName ( GetFontSelData().maStyleName );
+ aFont.SetHeight ( GetFontSelData().mnHeight );
+ aFont.SetWidth ( GetFontSelData().mnWidth );
+ aFont.SetOrientation( GetFontSelData().mnOrientation );
+ aFont.SetVertical ( GetFontSelData().mbVertical );
+
+ VirtualDevice vdev( 1 );
+ vdev.SetFont( aFont );
+
+ const bool bOptimize = true;
+
+ sal_Unicode aChar = nGlyphIndex;
+ String aGlyphStr( &aChar, 1 );
+ return vdev.GetTextOutline( rPolyPoly, aGlyphStr, 0, 1, bOptimize );
+ */
+}
+
+// =======================================================================
diff --git a/vcl/source/glyphs/gcach_vdev.hxx b/vcl/source/glyphs/gcach_vdev.hxx
new file mode 100644
index 000000000000..e2349169ee13
--- /dev/null
+++ b/vcl/source/glyphs/gcach_vdev.hxx
@@ -0,0 +1,57 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include <vcl/glyphcache.hxx>
+
+// -----------------------------------------------------------------------
+
+class VirtDevServerFont : public ServerFont
+{
+public:
+ virtual bool GetAntialiasAdvice( void ) const;
+ virtual bool GetGlyphBitmap1( int nGlyphIndex, RawBitmap& ) const;
+ virtual bool GetGlyphBitmap8( int nGlyphIndex, RawBitmap& ) const;
+ virtual bool GetGlyphOutline( int nGlyphIndex, PolyPolygon& ) const;
+
+protected:
+ friend class GlyphCache;
+ static void AnnounceFonts( ImplDevFontList* );
+ static void ClearFontList();
+
+ static VirtDevServerFont* CreateFont( const ImplFontSelectData& );
+ virtual void FetchFontMetric( ImplFontMetricData&, long& rFactor ) const;
+ virtual ULONG GetKernPairs( ImplKernPairData** ) const;
+ virtual int GetGlyphKernValue( int, int ) const;
+
+ virtual int GetGlyphIndex( sal_Unicode ) const;
+ virtual void InitGlyphData( int nGlyphIndex, GlyphData& ) const;
+
+private:
+ VirtDevServerFont( const ImplFontSelectData& );
+};
+
+// -----------------------------------------------------------------------
diff --git a/vcl/source/glyphs/glyphcache.cxx b/vcl/source/glyphs/glyphcache.cxx
new file mode 100644
index 000000000000..1953ecf553c4
--- /dev/null
+++ b/vcl/source/glyphs/glyphcache.cxx
@@ -0,0 +1,596 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <vcl/salbtype.hxx>
+#include <gcach_ftyp.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/outfont.hxx>
+
+#ifdef ENABLE_GRAPHITE
+#include <vcl/graphite_features.hxx>
+#endif
+
+#include <rtl/ustring.hxx> // used only for string=>hashvalue
+#include <osl/file.hxx>
+#include <tools/debug.hxx>
+
+// =======================================================================
+// GlyphCache
+// =======================================================================
+
+static GlyphCache* pInstance = NULL;
+
+GlyphCache::GlyphCache( GlyphCachePeer& rPeer )
+: mrPeer( rPeer ),
+ mnMaxSize( 1500000 ),
+ mnBytesUsed(sizeof(GlyphCache)),
+ mnLruIndex(0),
+ mnGlyphCount(0),
+ mpCurrentGCFont(NULL),
+ mpFtManager(NULL)
+{
+ pInstance = this;
+ mpFtManager = new FreetypeManager;
+}
+
+// -----------------------------------------------------------------------
+
+GlyphCache::~GlyphCache()
+{
+ InvalidateAllGlyphs();
+ if( mpFtManager )
+ delete mpFtManager;
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::InvalidateAllGlyphs()
+{
+#if 0 // TODO: implement uncaching of all glyph shapes and metrics
+ for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
+ delete const_cast<ServerFont*>( it->second );
+ maFontList.clear();
+ mpCurrentGCFont = NULL;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+inline
+size_t GlyphCache::IFSD_Hash::operator()( const ImplFontSelectData& rFontSelData ) const
+{
+ // TODO: is it worth to improve this hash function?
+ sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFontSelData.mpFontData );
+#ifdef ENABLE_GRAPHITE
+ if (rFontSelData.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
+ != STRING_NOTFOUND)
+ {
+ rtl::OString aFeatName = rtl::OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ nFontId ^= aFeatName.hashCode();
+ }
+#endif
+ size_t nHash = nFontId << 8;
+ nHash += rFontSelData.mnHeight;
+ nHash += rFontSelData.mnOrientation;
+ nHash += rFontSelData.mbVertical;
+ nHash += rFontSelData.meItalic;
+ nHash += rFontSelData.meWeight;
+#ifdef ENABLE_GRAPHITE
+ nHash += rFontSelData.meLanguage;
+#endif
+ return nHash;
+}
+
+// -----------------------------------------------------------------------
+
+bool GlyphCache::IFSD_Equal::operator()( const ImplFontSelectData& rA, const ImplFontSelectData& rB) const
+{
+ // check font ids
+ sal_IntPtr nFontIdA = reinterpret_cast<sal_IntPtr>( rA.mpFontData );
+ sal_IntPtr nFontIdB = reinterpret_cast<sal_IntPtr>( rB.mpFontData );
+ if( nFontIdA != nFontIdB )
+ return false;
+
+ // compare with the requested metrics
+ if( (rA.mnHeight != rB.mnHeight)
+ || (rA.mnOrientation != rB.mnOrientation)
+ || (rA.mbVertical != rB.mbVertical)
+ || (rA.mbNonAntialiased != rB.mbNonAntialiased) )
+ return false;
+
+ if( (rA.meItalic != rB.meItalic)
+ || (rA.meWeight != rB.meWeight) )
+ return false;
+
+ // NOTE: ignoring meFamily deliberately
+
+ // compare with the requested width, allow default width
+ if( (rA.mnWidth != rB.mnWidth)
+ && ((rA.mnHeight != rB.mnWidth) || (rA.mnWidth != 0)) )
+ return false;
+#ifdef ENABLE_GRAPHITE
+ if (rA.meLanguage != rB.meLanguage)
+ return false;
+ // check for features
+ if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
+ != STRING_NOTFOUND ||
+ rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
+ != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
+ return false;
+#endif
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+GlyphCache& GlyphCache::GetInstance()
+{
+ return *pInstance;
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::LoadFonts()
+{
+ if( const char* pFontPath = ::getenv( "SAL_FONTPATH_PRIVATE" ) )
+ AddFontPath( String::CreateFromAscii( pFontPath ) );
+ const String& rFontPath = Application::GetFontPath();
+ if( rFontPath.Len() > 0 )
+ AddFontPath( rFontPath );
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::ClearFontPath()
+{
+ if( mpFtManager )
+ mpFtManager->ClearFontList();
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::AddFontPath( const String& rFontPath )
+{
+ if( !mpFtManager )
+ return;
+
+ for( xub_StrLen nBreaker1 = 0, nBreaker2 = 0; nBreaker2 != STRING_LEN; nBreaker1 = nBreaker2 + 1 )
+ {
+ nBreaker2 = rFontPath.Search( ';', nBreaker1 );
+ if( nBreaker2 == STRING_NOTFOUND )
+ nBreaker2 = STRING_LEN;
+
+ ::rtl::OUString aUrlName;
+ osl::FileBase::getFileURLFromSystemPath( rFontPath.Copy( nBreaker1, nBreaker2 ), aUrlName );
+ mpFtManager->AddFontDir( aUrlName );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::AddFontFile( const rtl::OString& rNormalizedName, int nFaceNum,
+ sal_IntPtr nFontId, const ImplDevFontAttributes& rDFA, const ExtraKernInfo* pExtraKern )
+{
+ if( mpFtManager )
+ mpFtManager->AddFontFile( rNormalizedName, nFaceNum, nFontId, rDFA, pExtraKern );
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::AnnounceFonts( ImplDevFontList* pList ) const
+{
+ if( mpFtManager )
+ mpFtManager->AnnounceFonts( pList );
+ // VirtDevServerFont::AnnounceFonts( pList );
+}
+
+// -----------------------------------------------------------------------
+
+ServerFont* GlyphCache::CacheFont( const ImplFontSelectData& rFontSelData )
+{
+ // a serverfont request has pFontData
+ if( rFontSelData.mpFontData == NULL )
+ return NULL;
+ // a serverfont request has a fontid > 0
+ sal_IntPtr nFontId = rFontSelData.mpFontData->GetFontId();
+ if( nFontId <= 0 )
+ return NULL;
+
+ // the FontList's key mpFontData member is reinterpreted as font id
+ ImplFontSelectData aFontSelData = rFontSelData;
+ aFontSelData.mpFontData = reinterpret_cast<ImplFontData*>( nFontId );
+ FontList::iterator it = maFontList.find( aFontSelData );
+ if( it != maFontList.end() )
+ {
+ ServerFont* pFound = it->second;
+ if( pFound )
+ pFound->AddRef();
+ return pFound;
+ }
+
+ // font not cached yet => create new font item
+ ServerFont* pNew = NULL;
+ if( mpFtManager )
+ pNew = mpFtManager->CreateFont( aFontSelData );
+ // TODO: pNew = VirtDevServerFont::CreateFont( aFontSelData );
+
+ if( pNew )
+ {
+ maFontList[ aFontSelData ] = pNew;
+ mnBytesUsed += pNew->GetByteCount();
+
+ // enable garbage collection for new font
+ if( !mpCurrentGCFont )
+ {
+ mpCurrentGCFont = pNew;
+ pNew->mpNextGCFont = pNew;
+ pNew->mpPrevGCFont = pNew;
+ }
+ else
+ {
+ pNew->mpNextGCFont = mpCurrentGCFont;
+ pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont;
+ pNew->mpPrevGCFont->mpNextGCFont = pNew;
+ mpCurrentGCFont->mpPrevGCFont = pNew;
+ }
+ }
+
+ return pNew;
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::UncacheFont( ServerFont& rServerFont )
+{
+ // the interface for rServerFont must be const because a
+ // user who wants to release it only got const ServerFonts.
+ // The caching algorithm needs a non-const object
+ ServerFont* pFont = const_cast<ServerFont*>( &rServerFont );
+ if( (pFont->Release() <= 0)
+ && (mnMaxSize <= (mnBytesUsed + mrPeer.GetByteCount())) )
+ {
+ mpCurrentGCFont = pFont;
+ GarbageCollect();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG GlyphCache::CalcByteCount() const
+{
+ ULONG nCacheSize = sizeof(*this);
+ for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
+ {
+ const ServerFont* pSF = it->second;
+ if( pSF )
+ nCacheSize += pSF->GetByteCount();
+ }
+ // TODO: also account something for hashtable management
+ return nCacheSize;
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::GarbageCollect()
+{
+ // when current GC font has been destroyed get another one
+ if( !mpCurrentGCFont )
+ {
+ FontList::iterator it = maFontList.begin();
+ if( it != maFontList.end() )
+ mpCurrentGCFont = it->second;
+ }
+
+ // unless there is no other font to collect
+ if( !mpCurrentGCFont )
+ return;
+
+ // prepare advance to next font for garbage collection
+ ServerFont* const pServerFont = mpCurrentGCFont;
+ mpCurrentGCFont = pServerFont->mpNextGCFont;
+
+ if( (pServerFont == mpCurrentGCFont) // no other fonts
+ || (pServerFont->GetRefCount() > 0) ) // font still used
+ {
+ // try to garbage collect at least a few bytes
+ pServerFont->GarbageCollect( mnLruIndex - mnGlyphCount/2 );
+ }
+ else // current GC font is unreferenced
+ {
+ DBG_ASSERT( (pServerFont->GetRefCount() == 0),
+ "GlyphCache::GC detected RefCount underflow" );
+
+ // free all pServerFont related data
+ pServerFont->GarbageCollect( mnLruIndex+0x10000000 );
+ if( pServerFont == mpCurrentGCFont )
+ mpCurrentGCFont = NULL;
+ const ImplFontSelectData& rIFSD = pServerFont->GetFontSelData();
+ maFontList.erase( rIFSD );
+ mrPeer.RemovingFont( *pServerFont );
+ mnBytesUsed -= pServerFont->GetByteCount();
+
+ // remove font from list of garbage collected fonts
+ if( pServerFont->mpPrevGCFont )
+ pServerFont->mpPrevGCFont->mpNextGCFont = pServerFont->mpNextGCFont;
+ if( pServerFont->mpNextGCFont )
+ pServerFont->mpNextGCFont->mpPrevGCFont = pServerFont->mpPrevGCFont;
+ if( pServerFont == mpCurrentGCFont )
+ mpCurrentGCFont = NULL;
+
+ delete pServerFont;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline void GlyphCache::UsingGlyph( ServerFont&, GlyphData& rGlyphData )
+{
+ rGlyphData.SetLruValue( mnLruIndex++ );
+}
+
+// -----------------------------------------------------------------------
+
+inline void GlyphCache::AddedGlyph( ServerFont& rServerFont, GlyphData& rGlyphData )
+{
+ ++mnGlyphCount;
+ mnBytesUsed += sizeof( rGlyphData );
+ UsingGlyph( rServerFont, rGlyphData );
+ GrowNotify();
+}
+
+// -----------------------------------------------------------------------
+
+void GlyphCache::GrowNotify()
+{
+ if( (mnBytesUsed + mrPeer.GetByteCount()) > mnMaxSize )
+ GarbageCollect();
+}
+
+// -----------------------------------------------------------------------
+
+inline void GlyphCache::RemovingGlyph( ServerFont& rSF, GlyphData& rGD, int nGlyphIndex )
+{
+ mrPeer.RemovingGlyph( rSF, rGD, nGlyphIndex );
+ mnBytesUsed -= sizeof( GlyphData );
+ --mnGlyphCount;
+}
+
+// =======================================================================
+// ServerFont
+// =======================================================================
+
+ServerFont::ServerFont( const ImplFontSelectData& rFSD )
+: maGlyphList( 0),
+ maFontSelData(rFSD),
+ mnExtInfo(0),
+ mnRefCount(1),
+ mnBytesUsed( sizeof(ServerFont) ),
+ mpPrevGCFont( NULL ),
+ mpNextGCFont( NULL ),
+ mnCos( 0x10000),
+ mnSin( 0 ),
+ mnZWJ( 0 ),
+ mnZWNJ( 0 ),
+ mbCollectedZW( false )
+{
+ // TODO: move update of mpFontEntry into FontEntry class when
+ // it becomes reponsible for the ServerFont instantiation
+ ((ImplServerFontEntry*)rFSD.mpFontEntry)->SetServerFont( this );
+
+ if( rFSD.mnOrientation != 0 )
+ {
+ const double dRad = rFSD.mnOrientation * ( F_2PI / 3600.0 );
+ mnCos = static_cast<long>( 0x10000 * cos( dRad ) + 0.5 );
+ mnSin = static_cast<long>( 0x10000 * sin( dRad ) + 0.5 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ServerFont::~ServerFont()
+{
+ ReleaseFromGarbageCollect();
+}
+
+// -----------------------------------------------------------------------
+
+void ServerFont::ReleaseFromGarbageCollect()
+{
+ // remove from GC list
+ ServerFont* pPrev = mpPrevGCFont;
+ ServerFont* pNext = mpNextGCFont;
+ if( pPrev ) pPrev->mpNextGCFont = pNext;
+ if( pNext ) pNext->mpPrevGCFont = pPrev;
+ mpPrevGCFont = NULL;
+ mpNextGCFont = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+long ServerFont::Release() const
+{
+ DBG_ASSERT( mnRefCount > 0, "ServerFont: RefCount underflow" );
+ return --mnRefCount;
+}
+
+// -----------------------------------------------------------------------
+
+GlyphData& ServerFont::GetGlyphData( int nGlyphIndex )
+{
+ // usually the GlyphData is cached
+ GlyphList::iterator it = maGlyphList.find( nGlyphIndex );
+ if( it != maGlyphList.end() ) {
+ GlyphData& rGlyphData = it->second;
+ GlyphCache::GetInstance().UsingGlyph( *this, rGlyphData );
+ return rGlyphData;
+ }
+
+ // sometimes not => we need to create and initialize it ourselves
+ GlyphData& rGlyphData = maGlyphList[ nGlyphIndex ];
+ mnBytesUsed += sizeof( GlyphData );
+ InitGlyphData( nGlyphIndex, rGlyphData );
+ GlyphCache::GetInstance().AddedGlyph( *this, rGlyphData );
+ return rGlyphData;
+}
+
+// -----------------------------------------------------------------------
+
+void ServerFont::GarbageCollect( long nMinLruIndex )
+{
+ GlyphList::iterator it_next = maGlyphList.begin();
+ while( it_next != maGlyphList.end() )
+ {
+ GlyphList::iterator it = it_next++;
+ GlyphData& rGD = it->second;
+ if( (nMinLruIndex - rGD.GetLruValue()) > 0 )
+ {
+ OSL_ASSERT( mnBytesUsed >= sizeof(GlyphData) );
+ mnBytesUsed -= sizeof( GlyphData );
+ GlyphCache::GetInstance().RemovingGlyph( *this, rGD, it->first );
+ maGlyphList.erase( it );
+ it_next = maGlyphList.begin();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Point ServerFont::TransformPoint( const Point& rPoint ) const
+{
+ if( mnCos == 0x10000 )
+ return rPoint;
+ // TODO: use 32x32=>64bit intermediate
+ const double dCos = mnCos * (1.0 / 0x10000);
+ const double dSin = mnSin * (1.0 / 0x10000);
+ long nX = (long)(rPoint.X() * dCos + rPoint.Y() * dSin);
+ long nY = (long)(rPoint.Y() * dCos - rPoint.X() * dSin);
+ return Point( nX, nY );
+}
+
+bool ServerFont::IsGlyphInvisible( int nGlyphIndex )
+{
+ if (!mbCollectedZW)
+ {
+ mnZWJ = GetGlyphIndex( 0x200D );
+ mnZWNJ = GetGlyphIndex( 0x200C );
+ mbCollectedZW = true;
+ }
+
+ if( !nGlyphIndex ) // don't hide the NotDef glyph
+ return false;
+ if( (nGlyphIndex == mnZWNJ) || (nGlyphIndex == mnZWJ) )
+ return true;
+
+ return false;
+}
+
+// =======================================================================
+
+ImplServerFontEntry::ImplServerFontEntry( ImplFontSelectData& rFSD )
+: ImplFontEntry( rFSD )
+, mpServerFont( NULL )
+, mbGotFontOptions( false )
+, mbValidFontOptions( false )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplServerFontEntry::~ImplServerFontEntry()
+{
+ // TODO: remove the ServerFont here instead of in the GlyphCache
+}
+
+// =======================================================================
+
+ExtraKernInfo::ExtraKernInfo( sal_IntPtr nFontId )
+: mbInitialized( false ),
+ mnFontId( nFontId ),
+ maUnicodeKernPairs( 0 )
+{}
+
+//--------------------------------------------------------------------------
+
+bool ExtraKernInfo::HasKernPairs() const
+{
+ if( !mbInitialized )
+ Initialize();
+ return !maUnicodeKernPairs.empty();
+}
+
+//--------------------------------------------------------------------------
+
+int ExtraKernInfo::GetUnscaledKernPairs( ImplKernPairData** ppKernPairs ) const
+{
+ if( !mbInitialized )
+ Initialize();
+
+ // return early if no kerning available
+ if( maUnicodeKernPairs.empty() )
+ return 0;
+
+ // allocate kern pair table
+ int nKernCount = maUnicodeKernPairs.size();
+ *ppKernPairs = new ImplKernPairData[ nKernCount ];
+
+ // fill in unicode kern pairs with the kern value scaled to the font width
+ ImplKernPairData* pKernData = *ppKernPairs;
+ UnicodeKernPairs::const_iterator it = maUnicodeKernPairs.begin();
+ for(; it != maUnicodeKernPairs.end(); ++it )
+ *(pKernData++) = *it;
+
+ return nKernCount;
+}
+
+//--------------------------------------------------------------------------
+
+int ExtraKernInfo::GetUnscaledKernValue( sal_Unicode cLeft, sal_Unicode cRight ) const
+{
+ if( !mbInitialized )
+ Initialize();
+
+ if( maUnicodeKernPairs.empty() )
+ return 0;
+
+ ImplKernPairData aKernPair = { cLeft, cRight, 0 };
+ UnicodeKernPairs::const_iterator it = maUnicodeKernPairs.find( aKernPair );
+ if( it == maUnicodeKernPairs.end() )
+ return 0;
+
+ int nUnscaledValue = (*it).mnKern;
+ return nUnscaledValue;
+}
+
+// =======================================================================
+
diff --git a/vcl/source/glyphs/graphite_adaptors.cxx b/vcl/source/glyphs/graphite_adaptors.cxx
new file mode 100644
index 000000000000..f82e3afe39c8
--- /dev/null
+++ b/vcl/source/glyphs/graphite_adaptors.cxx
@@ -0,0 +1,336 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// Description: Implements the Graphite interfaces with access to the
+// platform's font and graphics systems.
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// We need this to enable namespace support in libgrengine headers.
+#define GR_NAMESPACE
+
+// Header files
+//
+// Standard Library
+#include <string>
+#include <cassert>
+// Libraries
+#include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
+#include <i18npool/mslangid.hxx>
+// Platform
+#ifndef WNT
+#include <saldisp.hxx>
+
+#include <vcl/salgdi.hxx>
+
+#include <freetype/ftsynth.h>
+
+// Module
+#include "gcach_ftyp.hxx"
+
+#include <vcl/graphite_features.hxx>
+#include <vcl/graphite_adaptors.hxx>
+
+// Module private type definitions and forward declarations.
+//
+using gr::GrResult;
+namespace
+{
+ inline float from_hinted(const int x) {
+ return static_cast<float>(x + 32) / 64.0;
+ }
+ typedef std::hash_map<long,bool> SilfMap;
+ SilfMap sSilfMap;
+}
+extern FT_Error (*pFTEmbolden)(FT_GlyphSlot);
+extern FT_Error (*pFTOblique)(FT_GlyphSlot);
+
+// class CharacterRenderProperties implentation.
+//
+FontProperties::FontProperties(const FreetypeServerFont &font) throw()
+{
+ clrFore = gr::kclrBlack;
+ clrBack = gr::kclrTransparent;
+
+ pixHeight = from_hinted(font.GetMetricsFT().height);
+
+ switch (font.GetFontSelData().meWeight)
+ {
+ case WEIGHT_SEMIBOLD: case WEIGHT_BOLD:
+ case WEIGHT_ULTRABOLD: case WEIGHT_BLACK:
+ fBold = true;
+ break;
+ default :
+ fBold = false;
+ }
+
+ switch (font.GetFontSelData().meItalic)
+ {
+ case ITALIC_NORMAL: case ITALIC_OBLIQUE:
+ fItalic = true;
+ break;
+ default :
+ fItalic = false;
+ }
+
+ // Get the font name, but prefix with file name hash in case
+ // there are 2 fonts on the system with the same face name
+ sal_Int32 nHashCode = font.GetFontFileName()->hashCode();
+ ::rtl::OUStringBuffer nHashFaceName;
+ nHashFaceName.append(nHashCode, 16);
+ const sal_Unicode * name = font.GetFontSelData().maName.GetBuffer();
+ nHashFaceName.append(name);
+
+ const size_t name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1,
+ static_cast<size_t>(nHashFaceName.getLength()));
+
+ std::copy(nHashFaceName.getStr(), nHashFaceName.getStr() + name_sz, szFaceName);
+ szFaceName[name_sz] = '\0';
+}
+
+// class GraphiteFontAdaptor implementaion.
+//
+GraphiteFontAdaptor::GraphiteFontAdaptor(ServerFont & sfont, const sal_Int32 dpiX, const sal_Int32 dpiY)
+ : mrFont(static_cast<FreetypeServerFont &>(sfont)),
+ maFontProperties(static_cast<FreetypeServerFont &>(sfont)),
+ mnDpiX(dpiX),
+ mnDpiY(dpiY),
+ mfAscent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().ascender)),
+ mfDescent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().descender)),
+ mfEmUnits(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().y_ppem),
+ mpFeatures(NULL)
+{
+ const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( sfont.GetFontSelData().meLanguage );
+ rtl::OString name = rtl::OUStringToOString(
+ sfont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 );
+#ifdef DEBUG
+ printf("GraphiteFontAdaptor %lx %s italic=%u bold=%u\n", (long)this, name.getStr(),
+ maFontProperties.fItalic, maFontProperties.fBold);
+#endif
+ sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
+ if (nFeat > 0)
+ {
+ rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
+ mpFeatures = new grutils::GrFeatureParser(*this, aFeat.getStr(), aLang.getStr());
+#ifdef DEBUG
+ printf("GraphiteFontAdaptor %s/%s/%s %x language %d features %d errors\n",
+ rtl::OUStringToOString( sfont.GetFontSelData().maName,
+ RTL_TEXTENCODING_UTF8 ).getStr(),
+ rtl::OUStringToOString( sfont.GetFontSelData().maTargetName,
+ RTL_TEXTENCODING_UTF8 ).getStr(),
+ rtl::OUStringToOString( sfont.GetFontSelData().maSearchName,
+ RTL_TEXTENCODING_UTF8 ).getStr(),
+ sfont.GetFontSelData().meLanguage,
+ (int)mpFeatures->getFontFeatures(NULL), mpFeatures->parseErrors());
+#endif
+ }
+ else
+ {
+ mpFeatures = new grutils::GrFeatureParser(*this, aLang.getStr());
+ }
+}
+
+GraphiteFontAdaptor::GraphiteFontAdaptor(const GraphiteFontAdaptor &rhs) throw()
+ : Font(rhs),
+ mrFont (rhs.mrFont), maFontProperties(rhs.maFontProperties),
+ mnDpiX(rhs.mnDpiX), mnDpiY(rhs.mnDpiY),
+ mfAscent(rhs.mfAscent), mfDescent(rhs.mfDescent), mfEmUnits(rhs.mfEmUnits),
+ mpFeatures(NULL)
+{
+ if (rhs.mpFeatures) mpFeatures = new grutils::GrFeatureParser(*(rhs.mpFeatures));
+}
+
+
+GraphiteFontAdaptor::~GraphiteFontAdaptor() throw()
+{
+ maGlyphMetricMap.clear();
+ if (mpFeatures) delete mpFeatures;
+ mpFeatures = NULL;
+}
+
+void GraphiteFontAdaptor::UniqueCacheInfo(ext_std::wstring & face_name_out, bool & bold_out, bool & italic_out)
+{
+ face_name_out = maFontProperties.szFaceName;
+ bold_out = maFontProperties.fBold;
+ italic_out = maFontProperties.fItalic;
+}
+
+bool GraphiteFontAdaptor::IsGraphiteEnabledFont(ServerFont & font) throw()
+{
+ // NOTE: this assumes that the same FTFace pointer won't be reused,
+ // so FtFontInfo::ReleaseFaceFT must only be called at shutdown.
+ FreetypeServerFont & aFtFont = dynamic_cast<FreetypeServerFont &>(font);
+ FT_Face aFace = reinterpret_cast<FT_FaceRec_*>(aFtFont.GetFtFace());
+ SilfMap::iterator i = sSilfMap.find(reinterpret_cast<long>(aFace));
+ if (i != sSilfMap.end())
+ {
+#ifdef DEBUG
+ if (static_cast<bool>(aFtFont.GetTable("Silf", 0)) != (*i).second)
+ printf("Silf cache font mismatch\n");
+#endif
+ return (*i).second;
+ }
+ bool bHasSilf = aFtFont.GetTable("Silf", 0);
+ sSilfMap[reinterpret_cast<long>(aFace)] = bHasSilf;
+ return bHasSilf;
+}
+
+
+gr::Font * GraphiteFontAdaptor::copyThis() {
+ return new GraphiteFontAdaptor(*this);
+}
+
+
+unsigned int GraphiteFontAdaptor::getDPIx() {
+ return mnDpiX;
+}
+
+
+unsigned int GraphiteFontAdaptor::getDPIy() {
+ return mnDpiY;
+}
+
+
+float GraphiteFontAdaptor::ascent() {
+ return mfAscent;
+}
+
+
+float GraphiteFontAdaptor::descent() {
+ return mfDescent;
+}
+
+
+bool GraphiteFontAdaptor::bold() {
+ return maFontProperties.fBold;
+}
+
+
+bool GraphiteFontAdaptor::italic() {
+ return maFontProperties.fItalic;
+}
+
+
+float GraphiteFontAdaptor::height() {
+ return maFontProperties.pixHeight;
+}
+
+
+void GraphiteFontAdaptor::getFontMetrics(float * ascent_out, float * descent_out, float * em_square_out) {
+ if (ascent_out) *ascent_out = mfAscent;
+ if (descent_out) *descent_out = mfDescent;
+ if (em_square_out) *em_square_out = mfEmUnits;
+}
+
+
+const void * GraphiteFontAdaptor::getTable(gr::fontTableId32 table_id, size_t * buffer_sz)
+{
+ char tag_name[5] = {char(table_id >> 24), char(table_id >> 16), char(table_id >> 8), char(table_id), 0};
+ ULONG temp = *buffer_sz;
+
+ const void * const tbl_buf = static_cast<FreetypeServerFont &>(mrFont).GetTable(tag_name, &temp);
+ *buffer_sz = temp;
+
+ return tbl_buf;
+}
+
+#define fix26_6(x) (x >> 6) + (x & 32 ? (x > 0 ? 1 : 0) : (x < 0 ? -1 : 0))
+
+// Return the glyph's metrics in pixels.
+void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId, gr::Rect & aBounding, gr::Point & advances)
+{
+ // There used to be problems when orientation was set however, this no
+ // longer seems to be the case and the Glyph Metric cache in
+ // FreetypeServerFont is more efficient since it lasts between calls to VCL
+#if 1
+ const GlyphMetric & metric = mrFont.GetGlyphMetric(nGlyphId);
+
+ aBounding.right = aBounding.left = metric.GetOffset().X();
+ aBounding.bottom = aBounding.top = -metric.GetOffset().Y();
+ aBounding.right += metric.GetSize().Width();
+ aBounding.bottom -= metric.GetSize().Height();
+
+ advances.x = metric.GetDelta().X();
+ advances.y = -metric.GetDelta().Y();
+
+#else
+ // The problem with the code below is that the cache only lasts
+ // as long as the life time of the GraphiteFontAdaptor, which
+ // is created once per call to X11SalGraphics::GetTextLayout
+ GlyphMetricMap::const_iterator gm_itr = maGlyphMetricMap.find(nGlyphId);
+ if (gm_itr != maGlyphMetricMap.end())
+ {
+ // We've cached the results from last time.
+ aBounding = gm_itr->second.first;
+ advances = gm_itr->second.second;
+ }
+ else
+ {
+ // We need to look up the glyph.
+ FT_Int nLoadFlags = mrFont.GetLoadFlags();
+
+ FT_Face aFace = reinterpret_cast<FT_Face>(mrFont.GetFtFace());
+ if (!aFace)
+ {
+ aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
+ advances.x = advances.y = 0;
+ return;
+ }
+ FT_Error aStatus = -1;
+ aStatus = FT_Load_Glyph(aFace, nGlyphId, nLoadFlags);
+ if( aStatus != FT_Err_Ok || (!aFace->glyph))
+ {
+ aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
+ advances.x = advances.y = 0;
+ return;
+ }
+ // check whether we need synthetic bold/italic otherwise metric is wrong
+ if (mrFont.NeedsArtificialBold() && pFTEmbolden)
+ (*pFTEmbolden)(aFace->glyph);
+
+ if (mrFont.NeedsArtificialItalic() && pFTOblique)
+ (*pFTOblique)(aFace->glyph);
+
+ const FT_Glyph_Metrics &gm = aFace->glyph->metrics;
+
+ // Fill out the bounding box an advances.
+ aBounding.top = aBounding.bottom = fix26_6(gm.horiBearingY);
+ aBounding.bottom -= fix26_6(gm.height);
+ aBounding.left = aBounding.right = fix26_6(gm.horiBearingX);
+ aBounding.right += fix26_6(gm.width);
+ advances.x = fix26_6(gm.horiAdvance);
+ advances.y = 0;
+
+ // Now add an entry to our metrics map.
+ maGlyphMetricMap[nGlyphId] = std::make_pair(aBounding, advances);
+ }
+#endif
+}
+
+#endif
diff --git a/vcl/source/glyphs/graphite_cache.cxx b/vcl/source/glyphs/graphite_cache.cxx
new file mode 100644
index 000000000000..389accd631f0
--- /dev/null
+++ b/vcl/source/glyphs/graphite_cache.cxx
@@ -0,0 +1,200 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifdef WNT
+#include <tools/svwin.h>
+#include <svsys.h>
+#endif
+
+#include <tools/debug.hxx>
+#include <vcl/sallayout.hxx>
+
+#include <tools/preextstl.h>
+#include <graphite/GrClient.h>
+#include <graphite/Segment.h>
+#include <tools/postextstl.h>
+
+#include <rtl/ustring.hxx>
+#include <vcl/graphite_layout.hxx>
+#include <vcl/graphite_cache.hxx>
+
+#include "graphite_textsrc.hxx"
+
+GrSegRecord::GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl)
+ : m_rope(rope), m_text(textSrc), m_seg(seg), m_nextKey(NULL),
+ m_fontScale(0.0f), mbIsRtl(bIsRtl), m_lockCount(0)
+{
+ m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter();
+ m_startChar = seg->startCharacter();
+}
+
+GrSegRecord::~GrSegRecord()
+{
+ clear();
+}
+
+void GrSegRecord::reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl)
+{
+ clear();
+ mnWidth = 0;
+ m_rope = rope;
+ m_text = textSrc;
+ m_seg = seg;
+ m_nextKey = NULL;
+ m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter();
+ m_startChar = seg->startCharacter();
+ mbIsRtl = bIsRtl;
+}
+
+void GrSegRecord::clearVectors()
+{
+ mvGlyphs.clear();
+ mvCharDxs.clear();
+ mvChar2BaseGlyph.clear();
+ mvGlyph2Char.clear();
+}
+
+void GrSegRecord::clear()
+{
+#ifdef GR_DEBUG_TEXT
+ if (m_lockCount != 0)
+ OutputDebugString("GrSegRecord locked!");
+#endif
+ clearVectors();
+ delete m_rope;
+ delete m_seg;
+ delete m_text;
+ m_rope = NULL;
+ m_seg = NULL;
+ m_text = NULL;
+ m_fontScale = 0.0f;
+ m_lockCount = 0;
+}
+
+GrSegRecord * GraphiteSegmentCache::cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl)
+{
+ GrSegRecord * record = NULL;
+ // We keep a record of the oldest key and the last key added
+ // when the next key is added, the record for the prevKey's m_nextKey field
+ // is updated to the newest key so that m_oldestKey can be updated to the
+ // next oldest key when the record for m_oldestKey is deleted
+ if (m_segMap.size() > m_nSegCacheSize)
+ {
+ GraphiteSegMap::iterator oldestPair = m_segMap.find(reinterpret_cast<long>(m_oldestKey));
+ // oldest record may no longer exist if a buffer was changed
+ if (oldestPair != m_segMap.end())
+ {
+ record = oldestPair->second;
+ m_segMap.erase(reinterpret_cast<long>(m_oldestKey));
+ GrRMEntry range = m_ropeMap.equal_range((*(record->m_rope)).hashCode());
+ while (range.first != range.second)
+ {
+ if (range.first->second == record)
+ {
+ m_ropeMap.erase(range.first);
+ break;
+ }
+ ++range.first;
+ }
+ m_oldestKey = record->m_nextKey;
+ // record will be reused, so don't delete
+ }
+ }
+
+
+// const int seg_char_limit = min(adapter->maLayoutArgs().mnLength,
+// adapter->maLayoutArgs().mnEndCharPos
+// + GraphiteLayout::EXTRA_CONTEXT_LENGTH);
+// if (seg->stopCharacter() - seg->startCharacter() <= 0)
+// OutputDebugString("Invalid seg indices\n");
+ rtl::OUString * pRope = new rtl::OUString(adapter->getLayoutArgs().mpStr + seg->startCharacter(),
+ seg->stopCharacter() - seg->startCharacter());
+ if (!pRope) return NULL;
+ bool reuse = false;
+ if (record)
+ record->reuse(pRope, adapter, seg, bIsRtl);
+ else
+ record = new GrSegRecord(pRope, adapter, seg, bIsRtl);
+ if (!record)
+ {
+ delete pRope;
+ return NULL;
+ }
+ GraphiteSegMap::iterator iMap =
+ m_segMap.find(reinterpret_cast<long>(record->m_pStr));
+ if (iMap != m_segMap.end())
+ {
+ // the buffer has changed, so the old cached Segment is useless
+ reuse = true;
+ GrSegRecord * found = iMap->second;
+ // Note: we reuse the old next key to avoid breaking our history
+ // chain. This means it will be prematurely deleted, but this is
+ // unlikely to happen very often.
+ record->m_nextKey = found->m_nextKey;
+ // overwrite the old record
+ m_segMap[reinterpret_cast<long>(record->m_pStr)] = record;
+ // erase the old rope key and save the new one
+ GrRMEntry range = m_ropeMap.equal_range((*(found->m_rope)).hashCode());
+ while (range.first != range.second)
+ {
+ if (range.first->second == found)
+ {
+ m_ropeMap.erase(range.first);
+ break;
+ }
+ ++range.first;
+ }
+ GraphiteRopeMap::value_type mapEntry(record->m_rope->hashCode(), record);
+ m_ropeMap.insert(mapEntry);
+ // remove the old record
+ delete found;
+ record->m_lockCount++;
+ return record;
+ }
+ m_segMap[reinterpret_cast<long>(record->m_pStr)] = record;
+ GraphiteRopeMap::value_type mapEntry((*(record->m_rope)).hashCode(), record);
+ m_ropeMap.insert(mapEntry);
+
+ if (m_oldestKey == NULL)
+ {
+ m_oldestKey = record->m_pStr;
+ m_prevKey = record->m_pStr;
+ }
+ else if (reuse == false)
+ {
+ DBG_ASSERT(m_segMap.count(reinterpret_cast<long>(m_prevKey)),
+ "Previous key got lost somehow!");
+ m_segMap.find(reinterpret_cast<long>(m_prevKey))
+ ->second->m_nextKey = record->m_pStr;
+ m_prevKey = record->m_pStr;
+ }
+ record->m_lockCount++;
+ return record;
+}
diff --git a/vcl/source/glyphs/graphite_features.cxx b/vcl/source/glyphs/graphite_features.cxx
new file mode 100644
index 000000000000..1cb25306c4ee
--- /dev/null
+++ b/vcl/source/glyphs/graphite_features.cxx
@@ -0,0 +1,286 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// Description:
+// Parse a string of features specified as & separated pairs.
+// e.g.
+// 1001=1&2002=2&fav1=0
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <sal/types.h>
+
+#ifdef WNT
+#include <tools/svwin.h>
+#include <svsys.h>
+#endif
+
+#include <vcl/graphite_features.hxx>
+
+using namespace grutils;
+// These mustn't conflict with font name lists which use ; and ,
+const char GrFeatureParser::FEAT_PREFIX = ':';
+const char GrFeatureParser::FEAT_SEPARATOR = '&';
+const char GrFeatureParser::FEAT_ID_VALUE_SEPARATOR = '=';
+const std::string GrFeatureParser::ISO_LANG("lang");
+
+GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string lang)
+ : mnNumSettings(0), mbErrors(false)
+{
+ maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0';
+ setLang(font, lang);
+}
+
+GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string features, const std::string lang)
+ : mnNumSettings(0), mbErrors(false)
+{
+ size_t nEquals = 0;
+ size_t nFeatEnd = 0;
+ size_t pos = 0;
+ maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0';
+ setLang(font, lang);
+ while (pos < features.length() && mnNumSettings < MAX_FEATURES)
+ {
+ nEquals = features.find(FEAT_ID_VALUE_SEPARATOR,pos);
+ if (nEquals == std::string::npos)
+ {
+ mbErrors = true;
+ break;
+ }
+ // check for a lang=xxx specification
+ if (features.compare(pos, nEquals - pos, ISO_LANG) == 0)
+ {
+ pos = nEquals + 1;
+ nFeatEnd = features.find(FEAT_SEPARATOR, pos);
+ if (nFeatEnd == std::string::npos)
+ {
+ nFeatEnd = features.length();
+ }
+ if (nFeatEnd - pos > 3)
+ mbErrors = true;
+ else
+ {
+ gr::isocode aLang = maLang;
+ for (size_t i = pos; i < nFeatEnd; i++)
+ aLang.rgch[i-pos] = features[i];
+ ext_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported
+ = font.getSupportedLanguages();
+ gr::LanguageIterator iL = aSupported.first;
+ while (iL != aSupported.second)
+ {
+ gr::isocode aSupportedLang = *iL;
+ // here we only expect full 3 letter codes
+ if (aLang.rgch[0] == aSupportedLang.rgch[0] &&
+ aLang.rgch[1] == aSupportedLang.rgch[1] &&
+ aLang.rgch[2] == aSupportedLang.rgch[2] &&
+ aLang.rgch[3] == aSupportedLang.rgch[3]) break;
+ ++iL;
+ }
+ if (iL == aSupported.second) mbErrors = true;
+ else maLang = aLang;
+ }
+ }
+ else
+ {
+ if (isCharId(features, pos, nEquals - pos))
+ maSettings[mnNumSettings].id = getCharId(features, pos, nEquals - pos);
+ else maSettings[mnNumSettings].id = getIntValue(features, pos, nEquals - pos);
+ pos = nEquals + 1;
+ nFeatEnd = features.find(FEAT_SEPARATOR, pos);
+ if (nFeatEnd == std::string::npos)
+ {
+ nFeatEnd = features.length();
+ }
+ if (isCharId(features, pos, nFeatEnd - pos))
+ maSettings[mnNumSettings].value = getCharId(features, pos, nFeatEnd - pos);
+ else
+ maSettings[mnNumSettings].value= getIntValue(features, pos, nFeatEnd - pos);
+ if (isValid(font, maSettings[mnNumSettings]))
+ mnNumSettings++;
+ else
+ mbErrors = true;
+ }
+ pos = nFeatEnd + 1;
+ }
+}
+
+void GrFeatureParser::setLang(gr::Font & font, const std::string & lang)
+{
+ gr::isocode aLang = {{0,0,0,0}};
+ if (lang.length() > 2)
+ {
+ for (size_t i = 0; i < lang.length() && i < 3; i++)
+ {
+ if (lang[i] == '-') break;
+ aLang.rgch[i] = lang[i];
+ }
+ ext_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported
+ = font.getSupportedLanguages();
+ gr::LanguageIterator iL = aSupported.first;
+ while (iL != aSupported.second)
+ {
+ gr::isocode aSupportedLang = *iL;
+ if (aLang.rgch[0] == aSupportedLang.rgch[0] &&
+ aLang.rgch[1] == aSupportedLang.rgch[1] &&
+ aLang.rgch[2] == aSupportedLang.rgch[2] &&
+ aLang.rgch[3] == aSupportedLang.rgch[3]) break;
+ ++iL;
+ }
+ if (iL != aSupported.second)
+ maLang = aLang;
+#ifdef DEBUG
+ else
+ printf("%s has no features\n", aLang.rgch);
+#endif
+ }
+}
+
+GrFeatureParser::GrFeatureParser(const GrFeatureParser & aCopy)
+ : maLang(aCopy.maLang), mbErrors(aCopy.mbErrors)
+{
+ mnNumSettings = aCopy.getFontFeatures(maSettings);
+}
+
+GrFeatureParser::~GrFeatureParser()
+{
+}
+
+size_t GrFeatureParser::getFontFeatures(gr::FeatureSetting settings[64]) const
+{
+ if (settings)
+ {
+ std::copy(maSettings, maSettings + mnNumSettings, settings);
+ }
+ return mnNumSettings;
+}
+
+bool GrFeatureParser::isValid(gr::Font & font, gr::FeatureSetting & setting)
+{
+ gr::FeatureIterator i = font.featureWithID(setting.id);
+ if (font.getFeatures().second == i)
+ {
+ return false;
+ }
+ ext_std::pair< gr::FeatureSettingIterator, gr::FeatureSettingIterator >
+ validValues = font.getFeatureSettings(i);
+ gr::FeatureSettingIterator j = validValues.first;
+ while (j != validValues.second)
+ {
+ if (*j == setting.value) return true;
+ ++j;
+ }
+ return false;
+}
+
+bool GrFeatureParser::isCharId(const std::string & id, size_t offset, size_t length)
+{
+ if (length > 4) return false;
+ for (size_t i = 0; i < length; i++)
+ {
+ if (i > 0 && id[offset+i] == '\0') continue;
+ if ((id[offset+i]) < 0x20 || (id[offset+i]) < 0)
+ return false;
+ if (i==0 && id[offset+i] < 0x41)
+ return false;
+ }
+ return true;
+}
+
+int GrFeatureParser::getCharId(const std::string & id, size_t offset, size_t length)
+{
+ FeatId charId;
+ charId.num = 0;
+#ifdef WORDS_BIGENDIAN
+ for (size_t i = 0; i < length; i++)
+ {
+ charId.label[i] = id[offset+i];
+ }
+#else
+ for (size_t i = 0; i < length; i++)
+ {
+ charId.label[3-i] = id[offset+i];
+ }
+#endif
+ return charId.num;
+}
+
+int GrFeatureParser::getIntValue(const std::string & id, size_t offset, size_t length)
+{
+ int value = 0;
+ int sign = 1;
+ for (size_t i = 0; i < length; i++)
+ {
+ switch (id[offset + i])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ value *= 10;
+ if (sign < 0)
+ {
+ value = -(id[offset + i] - '0');
+ sign = 1;
+ }
+ value += (id[offset + i] - '0');
+ break;
+ case '-':
+ if (i == 0)
+ sign = -1;
+ else
+ {
+ mbErrors = true;
+ break;
+ }
+ default:
+ mbErrors = true;
+ break;
+ }
+ }
+ return value;
+}
+
+
+sal_Int32 GrFeatureParser::hashCode() const
+{
+ union IsoHash { sal_Int32 mInt; gr::isocode mCode; };
+ IsoHash isoHash;
+ isoHash.mCode = maLang;
+ sal_Int32 hash = isoHash.mInt;
+ for (size_t i = 0; i < mnNumSettings; i++)
+ {
+ hash = (hash << 16) ^ ((maSettings[i].id << 8) | maSettings[i].value);
+ }
+ return hash;
+}
diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx
new file mode 100644
index 000000000000..ae7ec8246e33
--- /dev/null
+++ b/vcl/source/glyphs/graphite_layout.cxx
@@ -0,0 +1,1516 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// Description: An implementation of the SalLayout interface that uses the
+// Graphite engine.
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// We need this to enable namespace support in libgrengine headers.
+#define GR_NAMESPACE
+
+// Enable lots of debug info
+#ifdef DEBUG
+//#define GRLAYOUT_DEBUG 1
+//#undef NDEBUG
+#endif
+
+// Header files
+//
+// Standard Library
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <limits>
+#include <numeric>
+#include <deque>
+
+// Platform
+#ifdef WNT
+#include <tools/svwin.h>
+#include <svsys.h>
+#endif
+
+#ifdef UNX
+#include <vcl/graphite_adaptors.hxx>
+#endif
+
+#include <vcl/salgdi.hxx>
+
+#include <unicode/uchar.h>
+#include <unicode/ubidi.h>
+#include <unicode/uscript.h>
+
+// Graphite Libraries (must be after vcl headers on windows)
+#include <tools/preextstl.h>
+#include <graphite/GrClient.h>
+#include <graphite/Font.h>
+#include <graphite/ITextSource.h>
+#include <graphite/Segment.h>
+#include <graphite/SegmentPainter.h>
+#include <tools/postextstl.h>
+
+#include <vcl/graphite_layout.hxx>
+#include <vcl/graphite_features.hxx>
+#include "graphite_textsrc.hxx"
+
+
+// Module private type definitions and forward declarations.
+//
+// Module private names.
+//
+
+#ifdef GRLAYOUT_DEBUG
+FILE * grLogFile = NULL;
+FILE * grLog()
+{
+#ifdef WNT
+ std::string logFileName(getenv("TEMP"));
+ logFileName.append("\\graphitelayout.log");
+ if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w");
+ else fflush(grLogFile);
+ return grLogFile;
+#else
+ return stdout;
+#endif
+}
+#endif
+
+#ifdef GRCACHE
+#include <vcl/graphite_cache.hxx>
+#endif
+
+
+namespace
+{
+ typedef ext_std::pair<gr::GlyphIterator, gr::GlyphIterator> glyph_range_t;
+ typedef ext_std::pair<gr::GlyphSetIterator, gr::GlyphSetIterator> glyph_set_range_t;
+
+ inline long round(const float n) {
+ return long(n + (n < 0 ? -0.5 : 0.5));
+ }
+
+
+ template<typename T>
+ inline bool in_range(const T i, const T b, const T e) {
+ return !(b > i) && i < e;
+ }
+
+
+ template<typename T>
+ inline bool is_subrange(const T sb, const T se, const T b, const T e) {
+ return !(b > sb || se > e);
+ }
+
+
+ template<typename T>
+ inline bool is_subrange(const std::pair<T, T> &s, const T b, const T e) {
+ return is_subrange(s.first, s.second, b, e);
+ }
+
+ int findSameDirLimit(const xub_Unicode* buffer, int charCount, bool rtl)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
+ int limit = 0;
+ ubidi_setPara(ubidi, reinterpret_cast<const UChar *>(buffer), charCount,
+ (rtl)?UBIDI_DEFAULT_RTL:UBIDI_DEFAULT_LTR, NULL, &status);
+ UBiDiLevel level = 0;
+ ubidi_getLogicalRun(ubidi, 0, &limit, &level);
+ ubidi_close(ubidi);
+ if ((rtl && !(level & 1)) || (!rtl && (level & 1)))
+ {
+ limit = 0;
+ }
+ return limit;
+ }
+
+} // namespace
+
+
+
+// Impementation of the GraphiteLayout::Glyphs container class.
+// This is an extended vector class with methods added to enable
+// o Correctly filling with glyphs.
+// o Querying clustering relationships.
+// o manipulations that affect neighouring glyphs.
+
+const int GraphiteLayout::EXTRA_CONTEXT_LENGTH = 10;
+#ifdef GRCACHE
+GraphiteCacheHandler GraphiteCacheHandler::instance;
+#endif
+
+// The Graphite glyph stream is really a sequence of glyph attachment trees
+// each rooted at a non-attached base glyph. fill_from walks the glyph stream
+// find each non-attached base glyph and calls append to record them as a
+// sequence of clusters.
+void
+GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs,
+ bool bRtl, long &rWidth, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs)
+{
+ // Create a glyph item for each of the glyph and append it to the base class glyph list.
+ typedef ext_std::pair< gr::GlyphSetIterator, gr::GlyphSetIterator > GrGlyphSet;
+ int nChar = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
+ glyph_range_t iGlyphs = rSegment.glyphs();
+ int nGlyphs = iGlyphs.second - iGlyphs.first;
+ gr::GlyphIterator prevBase = iGlyphs.second;
+ float fSegmentAdvance = rSegment.advanceWidth();
+ float fMinX = fSegmentAdvance;
+ float fMaxX = 0.0f;
+ rGlyph2Char.assign(nGlyphs, -1);
+ long nDxOffset = 0;
+ int nGlyphIndex = (bRtl)? (nGlyphs - 1) : 0;
+ // OOo always expects the glyphs in ltr order
+ int nDelta = (bRtl)? -1 : 1;
+
+ int nLastGlyph = (bRtl)? nGlyphs - 1: 0;
+ int nNextChar = (bRtl)? (rSegment.stopCharacter() - 1) : rSegment.startCharacter();//rArgs.mnMinCharPos;
+ // current glyph number (Graphite glyphs)
+ //int currGlyph = 0;
+ int nFirstCharInCluster = nNextChar;
+ int nFirstGlyphInCluster = nLastGlyph;
+
+ // ltr first char in cluster is lowest, same is true for rtl
+ // ltr first glyph in cluster is lowest, rtl first glyph is highest
+
+ // loop over the glyphs determining which characters are linked to them
+ gr::GlyphIterator gi;
+ for (gi = iGlyphs.first + nGlyphIndex;
+ nGlyphIndex >= 0 && nGlyphIndex < nGlyphs;
+ nGlyphIndex+= nDelta, gi = iGlyphs.first + nGlyphIndex)
+ {
+ gr::GlyphInfo info = (*gi);
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Glyph %d %f,%f\n", (int)info.logicalIndex(), info.origin(), info.yOffset());
+#endif
+ // the last character associated with this glyph is after
+ // our current cluster buffer position
+ if ((bRtl && ((signed)info.firstChar() <= nNextChar)) ||
+ (!bRtl && ((signed)info.lastChar() >= nNextChar)))
+ {
+ if ((bRtl && nGlyphIndex < nLastGlyph) ||
+ (!bRtl && nGlyphIndex > nLastGlyph))
+ {
+ // this glyph is after the previous one left->right
+ // if insertion is allowed before it then we are in a
+ // new cluster
+ int nAttachedBase = (*(info.attachedClusterBase())).logicalIndex();
+ if (!info.isAttached() ||
+ !in_range(nAttachedBase, nFirstGlyphInCluster, nGlyphIndex))
+ {
+ if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) &&
+ nFirstGlyphInCluster != nGlyphIndex)
+ {
+ std::pair <float,float> aBounds =
+ appendCluster(rSegment, rArgs, bRtl,
+ fSegmentAdvance, nFirstCharInCluster,
+ nNextChar, nFirstGlyphInCluster, nGlyphIndex, fScaling,
+ rChar2Base, rGlyph2Char, rCharDxs, nDxOffset);
+ fMinX = std::min(aBounds.first, fMinX);
+ fMaxX = std::max(aBounds.second, fMaxX);
+ }
+ nFirstCharInCluster = (bRtl)? info.lastChar() : info.firstChar();
+ nFirstGlyphInCluster = nGlyphIndex;
+ }
+ nLastGlyph = (bRtl)? std::min(nGlyphIndex, nAttachedBase) :
+ std::max(nGlyphIndex, nAttachedBase);
+ }
+ // loop over chacters associated with this glyph and characters
+ // between nextChar and the last character associated with this glyph
+ // giving them the current cluster id. This allows for character /glyph
+ // order reversal.
+ // For each character we do a reverse glyph id look up
+ // and store the glyph id with the highest logical index in nLastGlyph
+ while ((bRtl && ((signed)info.firstChar() <= nNextChar)) ||
+ (!bRtl && (signed)info.lastChar() >= nNextChar))
+ {
+ GrGlyphSet charGlyphs = rSegment.charToGlyphs(nNextChar);
+ nNextChar += nDelta;
+ gr::GlyphSetIterator gj = charGlyphs.first;
+ while (gj != charGlyphs.second)
+ {
+ nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*gj).logicalIndex()) : max(nLastGlyph, (signed)(*gj).logicalIndex());
+ ++gj;
+ }
+ }
+ // Loop over attached glyphs and make sure they are all in the cluster since you
+ // can have glyphs attached with another base glyph in between
+ glyph_set_range_t iAttached = info.attachedClusterGlyphs();
+ for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi)
+ {
+ nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*agi).logicalIndex()) : max(nLastGlyph, (signed)(*agi).logicalIndex());
+ }
+
+ // if this is a rtl attached glyph, then we need to include its
+ // base in the cluster, which will have a lower graphite index
+ if (bRtl)
+ {
+ if ((signed)info.attachedClusterBase()->logicalIndex() < nLastGlyph)
+ {
+ nLastGlyph = info.attachedClusterBase()->logicalIndex();
+ }
+ }
+ }
+
+ // it is possible for the lastChar to be after nextChar and
+ // firstChar to be before the nFirstCharInCluster in rare
+ // circumstances e.g. Myanmar word for cemetery
+ if ((bRtl && ((signed)info.lastChar() > nFirstCharInCluster)) ||
+ (!bRtl && ((signed)info.firstChar() < nFirstCharInCluster)))
+ {
+ nFirstCharInCluster = info.firstChar();
+ }
+ }
+ // process last cluster
+ if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) &&
+ nFirstGlyphInCluster != nGlyphIndex)
+ {
+ std::pair <float,float> aBounds =
+ appendCluster(rSegment, rArgs, bRtl, fSegmentAdvance,
+ nFirstCharInCluster, nNextChar,
+ nFirstGlyphInCluster, nGlyphIndex, fScaling,
+ rChar2Base, rGlyph2Char, rCharDxs, nDxOffset);
+ fMinX = std::min(aBounds.first, fMinX);
+ fMaxX = std::max(aBounds.second, fMaxX);
+ }
+ long nXOffset = round(fMinX * fScaling);
+ rWidth = round(fMaxX * fScaling) - nXOffset + nDxOffset;
+ if (rWidth < 0)
+ {
+ // This can happen when there was no base inside the range
+ rWidth = 0;
+ }
+ // fill up non-base char dx with cluster widths from previous base glyph
+ if (bRtl)
+ {
+ if (rCharDxs[nChar-1] == -1)
+ rCharDxs[nChar-1] = 0;
+ else
+ rCharDxs[nChar-1] -= nXOffset;
+ for (int i = nChar - 2; i >= 0; i--)
+ {
+ if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i+1];
+ else rCharDxs[i] -= nXOffset;
+ }
+ }
+ else
+ {
+ if (rCharDxs[0] == -1)
+ rCharDxs[0] = 0;
+ else
+ rCharDxs[0] -= nXOffset;
+ for (int i = 1; i < nChar; i++)
+ {
+ if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i-1];
+ else rCharDxs[i] -= nXOffset;
+ }
+ }
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Glyphs xOff%ld dropDx%ld w%ld\n", nXOffset, nDxOffset, rWidth);
+#endif
+ // remove offset due to context if there is one
+ if (nXOffset != 0)
+ {
+ for (size_t i = 0; i < size(); i++)
+ (*this)[i].maLinearPos.X() -= nXOffset;
+ }
+}
+
+std::pair<float,float> GraphiteLayout::Glyphs::appendCluster(gr::Segment& rSeg,
+ ImplLayoutArgs & rArgs, bool bRtl,float fSegmentAdvance,
+ int nFirstCharInCluster, int nNextChar, int nFirstGlyphInCluster,
+ int nNextGlyph, float fScaling, std::vector<int> & rChar2Base,
+ std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset)
+{
+ glyph_range_t iGlyphs = rSeg.glyphs();
+ int nGlyphs = iGlyphs.second - iGlyphs.first;
+ int nDelta = (bRtl)? -1 : 1;
+ gr::GlyphInfo aFirstGlyph = *(iGlyphs.first + nFirstGlyphInCluster);
+ std::pair <float, float> aBounds;
+ aBounds.first = aFirstGlyph.origin();
+ aBounds.second = aFirstGlyph.origin();
+ // before we add the glyphs to this vector, we record the
+ // glyph's index in the vector (which is not the same as
+ // the Segment's glyph index!)
+ assert(size() < rGlyph2Char.size());
+ rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] = size();
+ rGlyph2Char[size()] = nFirstCharInCluster;
+
+ // can we break before this cluster?
+ // Glyphs may have either a positive or negative breakWeight refering to
+ // the position after or before the glyph respectively
+ int nPrevBreakWeight = 0;
+ if (nFirstGlyphInCluster > 0)
+ {
+ nPrevBreakWeight = (iGlyphs.first + (nFirstGlyphInCluster - 1))->breakweight();
+ }
+ int nBreakWeight = aFirstGlyph.breakweight();
+ if (nBreakWeight < 0)
+ {
+ // negative means it applies to the position before the glyph's character
+ nBreakWeight *= -1;
+ if (nPrevBreakWeight > 0 && nPrevBreakWeight < nBreakWeight)
+ {
+ // prevBreakWeight wins
+ nBreakWeight = nPrevBreakWeight;
+ }
+ }
+ else
+ {
+ nBreakWeight = 0;
+ // positive means break after
+ if (nPrevBreakWeight > 0)
+ nBreakWeight = nPrevBreakWeight;
+ }
+ if (nBreakWeight > gr::klbNoBreak/*0*/ &&
+ // nBreakWeight <= gr::klbHyphenBreak) // uses Graphite hyphenation
+ nBreakWeight <= gr::klbLetterBreak) // Needed for issue 111272
+ {
+ if (nBreakWeight < gr::klbHyphenBreak)
+ rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE;
+ else
+ rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= HYPHEN_BREAK_BEFORE;
+ }
+ // always allow a break before a space even if graphite doesn't
+ if (rArgs.mpStr[nFirstCharInCluster] == 0x20)
+ rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE;
+
+ bool bBaseGlyph = true;
+ for (int j = nFirstGlyphInCluster;
+ j != nNextGlyph; j += nDelta)
+ {
+ long nNextOrigin;
+ float fNextOrigin;
+ gr::GlyphInfo aGlyph = *(iGlyphs.first + j);
+ if (j + nDelta >= nGlyphs || j + nDelta < 0) // at rhs ltr,rtl
+ {
+ fNextOrigin = fSegmentAdvance;
+ nNextOrigin = round(fSegmentAdvance * fScaling + rDXOffset);
+ aBounds.second = std::max(fSegmentAdvance, aBounds.second);
+ }
+ else
+ {
+ gr::GlyphInfo aNextGlyph = *(iGlyphs.first + j + nDelta);
+ fNextOrigin = std::max(aNextGlyph.attachedClusterBase()->origin(), aNextGlyph.origin());
+ aBounds.second = std::max(fNextOrigin, aBounds.second);
+ nNextOrigin = round(fNextOrigin * fScaling + rDXOffset);
+ }
+ aBounds.first = std::min(aGlyph.origin(), aBounds.first);
+ if ((signed)aGlyph.firstChar() < rArgs.mnEndCharPos &&
+ (signed)aGlyph.firstChar() >= rArgs.mnMinCharPos)
+ {
+ rCharDxs[aGlyph.firstChar()-rArgs.mnMinCharPos] = nNextOrigin;
+ }
+ if ((signed)aGlyph.attachedClusterBase()->logicalIndex() == j)
+ {
+ append(rSeg, rArgs, aGlyph, fNextOrigin, fScaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, bBaseGlyph);
+ bBaseGlyph = false;
+ }
+ }
+ // from the point of view of the dx array, the xpos is
+ // the origin of the first glyph of the next cluster ltr
+ // rtl it is the origin of the 1st glyph of the cluster
+ long nXPos = (bRtl)?
+ round(aFirstGlyph.attachedClusterBase()->origin() * fScaling) + rDXOffset :
+ round(aBounds.second * fScaling) + rDXOffset;
+ // force the last char in range to have the width of the cluster
+ if (bRtl)
+ {
+ for (int n = nNextChar + 1; n <= nFirstCharInCluster; n++)
+ {
+ if ((n < rArgs.mnEndCharPos) && (n >= rArgs.mnMinCharPos))
+ rCharDxs[n-rArgs.mnMinCharPos] = nXPos;
+ }
+ }
+ else
+ {
+ for (int n = nNextChar - 1; n >= nFirstCharInCluster; n--)
+ {
+ if (n < rArgs.mnEndCharPos && n >= rArgs.mnMinCharPos)
+ rCharDxs[n-rArgs.mnMinCharPos] = nXPos;
+ }
+ }
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Cluster g[%d-%d) c[%d-%d)%x x%ld y%f bw%d\n", nFirstGlyphInCluster, nNextGlyph, nFirstCharInCluster, nNextChar, rArgs.mpStr[nFirstCharInCluster], nXPos, aFirstGlyph.yOffset(), nBreakWeight);
+#endif
+ return aBounds;
+}
+
+// append walks an attachment tree, flattening it, and converting it into a
+// sequence of GlyphItem objects which we can later manipulate.
+void
+GraphiteLayout::Glyphs::append(gr::Segment &segment, ImplLayoutArgs &args, gr::GlyphInfo & gi, float nextGlyphOrigin, float scaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset, bool bIsBase)
+{
+ float nextOrigin = nextGlyphOrigin;
+ int firstChar = std::min(gi.firstChar(), gi.lastChar());
+ assert(size() < rGlyph2Char.size());
+ if (!bIsBase) rGlyph2Char[size()] = firstChar;
+ // is the next glyph attached or in the next cluster?
+ glyph_set_range_t iAttached = gi.attachedClusterGlyphs();
+ if (iAttached.first != iAttached.second)
+ {
+ nextOrigin = iAttached.first->origin();
+ }
+ long glyphId = gi.glyphID();
+ long deltaOffset = 0;
+ int glyphWidth = round(nextOrigin * scaling) - round(gi.origin() * scaling);
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"c%d g%d gWidth%d x%f ", firstChar, (int)gi.logicalIndex(), glyphWidth, nextOrigin);
+#endif
+ if (glyphId == 0)
+ {
+ args.NeedFallback(
+ firstChar,
+ gr::RightToLeftDir(gr::DirCode(gi.directionality())));
+ if( (SAL_LAYOUT_FOR_FALLBACK & args.mnFlags ))
+ {
+ glyphId = GF_DROPPED;
+ deltaOffset -= glyphWidth;
+ glyphWidth = 0;
+ }
+ }
+ else if(args.mnFlags & SAL_LAYOUT_FOR_FALLBACK)
+ {
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"fallback c%d %x in run %d\n", firstChar, args.mpStr[firstChar],
+ args.maRuns.PosIsInAnyRun(firstChar));
+#endif
+ // glyphs that aren't requested for fallback will be taken from base
+ // layout, so mark them as dropped (should this wait until Simplify(false) is called?)
+ if (!args.maRuns.PosIsInAnyRun(firstChar) &&
+ in_range(firstChar, args.mnMinCharPos, args.mnEndCharPos))
+ {
+ glyphId = GF_DROPPED;
+ deltaOffset -= glyphWidth;
+ glyphWidth = 0;
+ }
+ }
+ // append this glyph.
+ long nGlyphFlags = bIsBase ? 0 : GlyphItem::IS_IN_CLUSTER;
+ // directionality seems to be unreliable
+ //nGlyphFlags |= gr::RightToLeftDir(gr::DirCode(gi.attachedClusterBase()->directionality())) ? GlyphItem::IS_RTL_GLYPH : 0;
+ nGlyphFlags |= (gi.directionLevel() & 0x1)? GlyphItem::IS_RTL_GLYPH : 0;
+ GlyphItem aGlyphItem(size(),//gi.logicalIndex(),
+ glyphId,
+ Point(round(gi.origin() * scaling + rDXOffset),
+ round((-gi.yOffset() * scaling) - segment.AscentOffset()* scaling)),
+ nGlyphFlags,
+ glyphWidth);
+ aGlyphItem.mnOrigWidth = round(gi.advanceWidth() * scaling);
+ push_back(aGlyphItem);
+
+ // update the offset if this glyph was dropped
+ rDXOffset += deltaOffset;
+
+ // Recursively apply append all the attached glyphs.
+ for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi)
+ {
+ if (agi + 1 == iAttached.second)
+ append(segment, args, *agi, nextGlyphOrigin, scaling, rChar2Base, rGlyph2Char,rCharDxs, rDXOffset, false);
+ else
+ append(segment, args, *agi, (agi + 1)->origin(), scaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, false);
+ }
+}
+
+//
+// An implementation of the SalLayout interface to enable Graphite enabled fonts to be used.
+//
+GraphiteLayout::GraphiteLayout(const gr::Font & font, const grutils::GrFeatureParser * pFeatures) throw()
+ : mpTextSrc(0),
+ mrFont(font),
+ mnWidth(0),
+ mfScaling(1.0),
+ mpFeatures(pFeatures)
+{
+ // Line settings can have subtle affects on space handling
+ // since we don't really know whether it is the end of a line or just a run
+ // in the middle, it is hard to know what to set them to.
+ // If true, it can cause end of line spaces to be hidden e.g. Doulos SIL
+ maLayout.setStartOfLine(false);
+ maLayout.setEndOfLine(false);
+ maLayout.setDumbFallback(true);
+ // trailing ws doesn't seem to always take affect if end of line is true
+ maLayout.setTrailingWs(gr::ktwshAll);
+#ifdef GRLAYOUT_DEBUG
+ gr::ScriptDirCode aDirCode = font.getSupportedScriptDirections();
+ fprintf(grLog(),"GraphiteLayout scripts %x %lx\n", aDirCode, long(this));
+#endif
+}
+
+
+GraphiteLayout::~GraphiteLayout() throw()
+{
+ clear();
+ // the features are owned by the platform layers
+ mpFeatures = NULL;
+}
+
+void GraphiteLayout::clear()
+{
+ // Destroy the segment and text source from any previous invocation of
+ // LayoutText
+ mvGlyphs.clear();
+ mvCharDxs.clear();
+ mvChar2BaseGlyph.clear();
+ mvGlyph2Char.clear();
+
+#ifndef GRCACHE
+ delete mpTextSrc;
+#endif
+
+ // Reset the state to the empty state.
+ mpTextSrc=0;
+ mnWidth = 0;
+ // Don't reset the scaling, because it is set before LayoutText
+}
+
+// This method shouldn't be called on windows, since it needs the dc reset
+bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs)
+{
+#ifdef GRCACHE
+ GrSegRecord * pSegRecord = NULL;
+ gr::Segment * pSegment = CreateSegment(rArgs, &pSegRecord);
+ if (!pSegment)
+ return false;
+
+ // layout the glyphs as required by OpenOffice
+ bool success = LayoutGlyphs(rArgs, pSegment, pSegRecord);
+
+ if (pSegRecord) pSegRecord->unlock();
+ else delete pSegment;
+#else
+ gr::Segment * pSegment = CreateSegment(rArgs);
+ if (!pSegment)
+ return false;
+ bool success = LayoutGlyphs(rArgs, pSegment);
+ delete pSegment;
+#endif
+ return success;
+}
+
+#ifdef GRCACHE
+class GrFontHasher : public gr::Font
+{
+public:
+ GrFontHasher(const gr::Font & aFont) : gr::Font(aFont), mrRealFont(const_cast<gr::Font&>(aFont)) {};
+ ~GrFontHasher(){};
+ virtual bool bold() { return mrRealFont.bold(); };
+ virtual bool italic() { return mrRealFont.italic(); };
+ virtual float ascent() { return mrRealFont.ascent(); };
+ virtual float descent() { return mrRealFont.descent(); };
+ virtual float height() { return mrRealFont.height(); };
+ virtual gr::Font* copyThis() { return mrRealFont.copyThis(); };
+ virtual unsigned int getDPIx() { return mrRealFont.getDPIx(); };
+ virtual unsigned int getDPIy() { return mrRealFont.getDPIy(); };
+ virtual const void* getTable(gr::fontTableId32 nId, size_t* nSize)
+ { return mrRealFont.getTable(nId,nSize); }
+ virtual void getFontMetrics(float*pA, float*pB, float*pC) { mrRealFont.getFontMetrics(pA,pB,pC); };
+
+ sal_Int32 hashCode(const grutils::GrFeatureParser * mpFeatures)
+ {
+ // is this sufficient?
+ ext_std::wstring aFace;
+ bool bBold;
+ bool bItalic;
+ UniqueCacheInfo(aFace, bBold, bItalic);
+ sal_Unicode uName[32]; // max length used in gr::Font
+ // Note: graphite stores font names as UTF-16 even if wchar_t is 32bit
+ // this conversion should be OK.
+ for (size_t i = 0; i < aFace.size() && i < 32; i++)
+ {
+ uName[i] = aFace[i];
+ }
+ size_t iSize = aFace.size();
+ if (0 == iSize) return 0;
+ sal_Int32 hash = rtl_ustr_hashCode_WithLength(uName, iSize);
+ hash ^= static_cast<sal_Int32>(height());
+ hash |= (bBold)? 0x1000000 : 0;
+ hash |= (bItalic)? 0x2000000 : 0;
+ if (mpFeatures)
+ hash ^= mpFeatures->hashCode();
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(), "font hash %x size %f\n", (int)hash, height());
+#endif
+ return hash;
+ };
+protected:
+ virtual void UniqueCacheInfo(std::wstring & stuFace, bool & fBold, bool & fItalic)
+ {
+#ifdef WIN32
+ dynamic_cast<GraphiteWinFont&>(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic);
+#else
+#ifdef UNX
+ dynamic_cast<GraphiteFontAdaptor&>(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic);
+#else
+#error Unknown base type for gr::Font::UniqueCacheInfo
+#endif
+#endif
+ }
+private:
+ gr::Font & mrRealFont;
+};
+#endif
+
+#ifdef GRCACHE
+gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs, GrSegRecord ** pSegRecord)
+#else
+gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs)
+#endif
+{
+ assert(rArgs.mnLength >= 0);
+
+ gr::Segment * pSegment = NULL;
+
+ // Set the SalLayouts values to be the inital ones.
+ SalLayout::AdjustLayout(rArgs);
+ // TODO check if this is needed
+ if (mnUnitsPerPixel > 1)
+ mfScaling = 1.0f / mnUnitsPerPixel;
+
+ // Clear out any previous buffers
+ clear();
+ bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
+ try
+ {
+ // Don't set RTL if font doesn't support it otherwise it forces rtl on
+ // everything
+ if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl))
+ maLayout.setRightToLeft(bRtl);
+
+ // Context is often needed beyond the specified end, however, we don't
+ // want it if there has been a direction change, since it is hard
+ // to tell between reordering within one direction and multi-directional
+ // text. Extra context, can also cause problems with ligatures stradling
+ // a hyphenation point, so disable if CTL is disabled.
+ const int nSegCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH);
+ int limit = rArgs.mnEndCharPos;
+ if ((nSegCharLimit > limit) && !(SAL_LAYOUT_COMPLEX_DISABLED & rArgs.mnFlags))
+ {
+ limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos,
+ nSegCharLimit - rArgs.mnEndCharPos, bRtl);
+ }
+
+#ifdef GRCACHE
+ GrFontHasher hasher(mrFont);
+ sal_Int32 aFontHash = hasher.hashCode(mpFeatures);
+ GraphiteSegmentCache * pCache =
+ (GraphiteCacheHandler::instance).getCache(aFontHash);
+ if (pCache)
+ {
+ *pSegRecord = pCache->getSegment(rArgs, bRtl, nSegCharLimit);
+ if (*pSegRecord)
+ {
+ pSegment = (*pSegRecord)->getSegment();
+ mpTextSrc = (*pSegRecord)->getTextSrc();
+ maLayout.setRightToLeft((*pSegRecord)->isRtl());
+ if (rArgs.mpStr != mpTextSrc->getLayoutArgs().mpStr ||
+ rArgs.mnMinCharPos != mpTextSrc->getLayoutArgs().mnMinCharPos ||
+ rArgs.mnEndCharPos != mpTextSrc->getLayoutArgs().mnEndCharPos ||
+ (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) )
+ {
+ (*pSegRecord)->clearVectors();
+ }
+ mpTextSrc->switchLayoutArgs(rArgs);
+ return pSegment;
+ }
+ }
+#endif
+
+ // Create a new TextSource object for the engine.
+ mpTextSrc = new TextSourceAdaptor(rArgs, limit);
+ if (mpFeatures) mpTextSrc->setFeatures(mpFeatures);
+
+ pSegment = new gr::RangeSegment((gr::Font *)&mrFont, mpTextSrc, &maLayout, mnMinCharPos, limit);
+ if (pSegment != NULL)
+ {
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Gr::LayoutText %d-%d, context %d,len%d rtl%d/%d scaling %f\n", rArgs.mnMinCharPos,
+ rArgs.mnEndCharPos, limit, rArgs.mnLength, maLayout.rightToLeft(), pSegment->rightToLeft(), mfScaling);
+#endif
+#ifdef GRCACHE
+ // on a new segment rightToLeft should be correct
+ *pSegRecord = pCache->cacheSegment(mpTextSrc, pSegment, pSegment->rightToLeft());
+#endif
+ }
+ else
+ {
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(), "Gr::LayoutText failed: ");
+ for (int i = mnMinCharPos; i < limit; i++)
+ {
+ fprintf(grLog(), "%04x ", rArgs.mpStr[i]);
+ }
+ fprintf(grLog(), "\n");
+#endif
+ clear();
+ return NULL;
+ }
+ }
+ catch (...)
+ {
+ clear(); // destroy the text source and any partially built segments.
+ return NULL;
+ }
+ return pSegment;
+}
+
+#ifdef GRCACHE
+bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment, GrSegRecord * pSegRecord)
+#else
+bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment)
+#endif
+{
+#ifdef GRCACHE
+#ifdef GRCACHE_REUSE_VECTORS
+ // if we have an exact match, then we can reuse the glyph vectors from before
+ if (pSegRecord && (pSegRecord->glyphs().size() > 0) &&
+ (pSegRecord->fontScale() == mfScaling) &&
+ !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) )
+ {
+ mnWidth = pSegRecord->width();
+ mvGlyphs = pSegRecord->glyphs();
+ mvCharDxs = pSegRecord->charDxs();
+ mvChar2BaseGlyph = pSegRecord->char2BaseGlyph();
+ mvGlyph2Char = pSegRecord->glyph2Char();
+ return true;
+ }
+#endif
+#endif
+ // Calculate the initial character dxs.
+ mvCharDxs.assign(mnEndCharPos - mnMinCharPos, -1);
+ mvChar2BaseGlyph.assign(mnEndCharPos - mnMinCharPos, -1);
+ mnWidth = 0;
+ if (mvCharDxs.size() > 0)
+ {
+ // Discover all the clusters.
+ try
+ {
+ // Note: we use the layout rightToLeft() because in cached segments
+ // rightToLeft() may no longer be valid if the engine has been run
+ // ltr since the segment was created.
+#ifdef GRCACHE
+ bool bRtl = pSegRecord? pSegRecord->isRtl() : pSegment->rightToLeft();
+#else
+ bool bRtl = pSegment->rightToLeft();
+#endif
+ mvGlyphs.fill_from(*pSegment, rArgs, bRtl,
+ mnWidth, mfScaling, mvChar2BaseGlyph, mvGlyph2Char, mvCharDxs);
+
+ if (bRtl)
+ {
+ // not needed for adjacent differences, but for mouse clicks to char
+ std::transform(mvCharDxs.begin(), mvCharDxs.end(), mvCharDxs.begin(),
+ std::bind1st(std::minus<long>(), mnWidth));
+ // fixup last dx to ensure it always equals the width
+ mvCharDxs[mvCharDxs.size() - 1] = mnWidth;
+ }
+#ifdef GRCACHE
+#ifdef GRCACHE_REUSE_VECTORS
+ if (pSegRecord && rArgs.maReruns.IsEmpty() &&
+ !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags))
+ {
+ pSegRecord->setGlyphVectors(mnWidth, mvGlyphs, mvCharDxs,
+ mvChar2BaseGlyph, mvGlyph2Char,
+ mfScaling);
+ }
+#endif
+#endif
+ }
+ catch (std::exception e)
+ {
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"LayoutGlyphs failed %s\n", e.what());
+#endif
+ return false;
+ }
+ catch (...)
+ {
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"LayoutGlyphs failed with exception");
+#endif
+ return false;
+ }
+ }
+ else
+ {
+ mnWidth = 0;
+ }
+ return true;
+}
+
+int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) const
+{
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Gr::GetTextBreak c[%d-%d) maxWidth %ld char extra %ld factor %d\n",
+ mnMinCharPos, mnEndCharPos, maxmnWidth, char_extra, factor);
+#endif
+
+ // return quickly if this segment is narrower than the target width
+ if (maxmnWidth > mnWidth * factor + char_extra * (mnEndCharPos - mnMinCharPos - 1))
+ return STRING_LEN;
+
+ long nWidth = mvCharDxs[0] * factor;
+ int nLastBreak = -1;
+ for (size_t i = 1; i < mvCharDxs.size(); i++)
+ {
+ nWidth += char_extra;
+ if (nWidth > maxmnWidth) break;
+ if (mvChar2BaseGlyph[i] != -1)
+ {
+ if (mvChar2BaseGlyph[i] & (WORD_BREAK_BEFORE | HYPHEN_BREAK_BEFORE))
+ nLastBreak = static_cast<int>(i);
+ }
+ nWidth += (mvCharDxs[i] - mvCharDxs[i-1]) * factor;
+ }
+ int nBreak = mnMinCharPos;
+ if (nLastBreak > -1)
+ nBreak += nLastBreak;
+
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(), "Gr::GetTextBreak break after %d\n", nBreak - mnMinCharPos);
+#endif
+
+ if (nBreak > mnEndCharPos) nBreak = STRING_LEN;
+ else if (nBreak < mnMinCharPos) nBreak = mnMinCharPos;
+ return nBreak;
+}
+
+
+long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const
+{
+ if (mnEndCharPos == mnMinCharPos)
+ // Then we must be zero width!
+ return 0;
+
+ if (pDXArray)
+ {
+ for (size_t i = 0; i < mvCharDxs.size(); i++)
+ {
+ assert( (mvChar2BaseGlyph[i] == -1) ||
+ ((signed)(mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK) < (signed)mvGlyphs.size()));
+ if (mvChar2BaseGlyph[i] != -1 &&
+ mvGlyphs[mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK].mnGlyphIndex == GF_DROPPED)
+ {
+ // when used in MultiSalLayout::GetTextBreak dropped glyphs
+ // must have zero width
+ pDXArray[i] = 0;
+ }
+ else
+ {
+ pDXArray[i] = mvCharDxs[i];
+ if (i > 0) pDXArray[i] -= mvCharDxs[i-1];
+ }
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
+#endif
+ }
+ //std::adjacent_difference(mvCharDxs.begin(), mvCharDxs.end(), pDXArray);
+ //for (size_t i = 0; i < mvCharDxs.size(); i++)
+ // fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
+ //fprintf(grLog(),"FillDX %ld,%d\n", mnWidth, std::accumulate(pDXArray, pDXArray + mvCharDxs.size(), 0));
+ }
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"FillDXArray %d-%d,%d=%ld\n", mnMinCharPos, mnEndCharPos, (int)mpTextSrc->getLength(), mnWidth);
+#endif
+ return mnWidth;
+}
+
+
+void GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs)
+{
+ SalLayout::AdjustLayout(rArgs);
+ if(rArgs.mpDXArray)
+ {
+ std::vector<int> vDeltaWidths(mvGlyphs.size(), 0);
+ ApplyDXArray(rArgs, vDeltaWidths);
+
+ if( (mnLayoutFlags & SAL_LAYOUT_BIDI_RTL) &&
+ !(rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
+ {
+ // check if this is a kashida script
+ bool bKashidaScript = false;
+ for (int i = rArgs.mnMinCharPos; i < rArgs.mnEndCharPos; i++)
+ {
+ UErrorCode aStatus = U_ZERO_ERROR;
+ UScriptCode scriptCode = uscript_getScript(rArgs.mpStr[i], &aStatus);
+ if (scriptCode == USCRIPT_ARABIC || scriptCode == USCRIPT_SYRIAC)
+ {
+ bKashidaScript = true;
+ break;
+ }
+ }
+ int nKashidaWidth = 0;
+ int nKashidaIndex = getKashidaGlyph(nKashidaWidth);
+ if( nKashidaIndex != 0 && bKashidaScript)
+ {
+ kashidaJustify( vDeltaWidths, nKashidaIndex, nKashidaWidth );
+ }
+ }
+ }
+ else if (rArgs.mnLayoutWidth > 0)
+ {
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(), "AdjustLayout width %ld=>%ld\n", mnWidth, rArgs.mnLayoutWidth);
+#endif
+ expandOrCondense(rArgs);
+ }
+}
+
+void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs)
+{
+ int nDeltaWidth = rArgs.mnLayoutWidth - mnWidth;
+ if (nDeltaWidth > 0) // expand, just expand between clusters
+ {
+ int nClusterCount = 0;
+ for (size_t j = 0; j < mvGlyphs.size(); j++)
+ {
+ if (mvGlyphs[j].IsClusterStart())
+ {
+ ++nClusterCount;
+ }
+ }
+ if (nClusterCount > 1)
+ {
+ float fExtraPerCluster = static_cast<float>(nDeltaWidth) / static_cast<float>(nClusterCount - 1);
+ int nCluster = 0;
+ int nOffset = 0;
+ for (size_t i = 0; i < mvGlyphs.size(); i++)
+ {
+ if (mvGlyphs[i].IsClusterStart())
+ {
+ nOffset = fExtraPerCluster * nCluster;
+ size_t nCharIndex = mvGlyph2Char[i];
+ mvCharDxs[nCharIndex] += nOffset;
+ // adjust char dxs for rest of characters in cluster
+ while (++nCharIndex < mvGlyph2Char.size())
+ {
+ int nChar2Base = (mvChar2BaseGlyph[nCharIndex] == -1)? -1 : mvChar2BaseGlyph[nCharIndex] & GLYPH_INDEX_MASK;
+ if (nChar2Base == -1 || nChar2Base == static_cast<int>(i))
+ mvCharDxs[nCharIndex] += nOffset;
+ }
+ ++nCluster;
+ }
+ mvGlyphs[i].maLinearPos.X() += nOffset;
+ }
+ }
+ }
+ else // condense - apply a factor to all glyph positions
+ {
+ if (mvGlyphs.size() == 0) return;
+ Glyphs::iterator iLastGlyph = mvGlyphs.begin() + (mvGlyphs.size() - 1);
+ // position last glyph using original width
+ float fXFactor = static_cast<float>(rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth) / static_cast<float>(iLastGlyph->maLinearPos.X());
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(), "Condense by factor %f\n", fXFactor);
+#endif
+ iLastGlyph->maLinearPos.X() = rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth;
+ Glyphs::iterator iGlyph = mvGlyphs.begin();
+ while (iGlyph != iLastGlyph)
+ {
+ iGlyph->maLinearPos.X() = static_cast<float>(iGlyph->maLinearPos.X()) * fXFactor;
+ ++iGlyph;
+ }
+ for (size_t i = 0; i < mvCharDxs.size(); i++)
+ {
+ mvCharDxs[i] = fXFactor * static_cast<float>(mvCharDxs[i]);
+ }
+ }
+}
+
+void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDeltaWidth)
+{
+ const size_t nChars = args.mnEndCharPos - args.mnMinCharPos;
+ if (nChars == 0) return;
+
+#ifdef GRLAYOUT_DEBUG
+ for (size_t iDx = 0; iDx < mvCharDxs.size(); iDx++)
+ fprintf(grLog(),"%d,%d,%d ", (int)iDx, (int)mvCharDxs[iDx], args.mpDXArray[iDx]);
+ fprintf(grLog(),"ApplyDx\n");
+#endif
+ bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
+ int nXOffset = 0;
+ if (bRtl)
+ {
+ nXOffset = args.mpDXArray[nChars - 1] - mvCharDxs[nChars - 1];
+ }
+ int nPrevClusterGlyph = (bRtl)? mvGlyphs.size() : -1;
+ int nPrevClusterLastChar = -1;
+ for (size_t i = 0; i < nChars; i++)
+ {
+ int nChar2Base = (mvChar2BaseGlyph[i] == -1)? -1 : mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK;
+ if ((nChar2Base > -1) && (nChar2Base != nPrevClusterGlyph))
+ {
+ assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size()));
+ GlyphItem & gi = mvGlyphs[nChar2Base];
+ if (!gi.IsClusterStart())
+ continue;
+
+ // find last glyph of this cluster
+ size_t j = i + 1;
+ int nLastChar = i;
+ int nLastGlyph = nChar2Base;
+ for (; j < nChars; j++)
+ {
+ int nChar2BaseJ = (mvChar2BaseGlyph[j] == -1)? -1 : mvChar2BaseGlyph[j] & GLYPH_INDEX_MASK;
+ assert((nChar2BaseJ >= -1) && (nChar2BaseJ < (signed)mvGlyphs.size()));
+ if (nChar2BaseJ != -1 && mvGlyphs[nChar2BaseJ].IsClusterStart())
+ {
+ nLastGlyph = nChar2BaseJ + ((bRtl)? 1 : -1);
+ nLastChar = j - 1;
+ break;
+ }
+ }
+ if (nLastGlyph < 0)
+ {
+ nLastGlyph = nChar2Base;
+ }
+ // Its harder to find the last glyph rtl, since the first of
+ // cluster is still on the left so we need to search towards
+ // the previous cluster to the right
+ if (bRtl)
+ {
+ nLastGlyph = nChar2Base;
+ while (nLastGlyph + 1 < (signed)mvGlyphs.size() &&
+ !mvGlyphs[nLastGlyph+1].IsClusterStart())
+ {
+ ++nLastGlyph;
+ }
+ }
+ if (j == nChars)
+ {
+ nLastChar = nChars - 1;
+ if (!bRtl) nLastGlyph = mvGlyphs.size() - 1;
+ }
+ assert((nLastChar > -1) && (nLastChar < (signed)nChars));
+ long nNewClusterWidth = args.mpDXArray[nLastChar];
+ long nOrigClusterWidth = mvCharDxs[nLastChar];
+ long nDGlyphOrigin = 0;
+ if (nPrevClusterLastChar > - 1)
+ {
+ assert(nPrevClusterLastChar < (signed)nChars);
+ nNewClusterWidth -= args.mpDXArray[nPrevClusterLastChar];
+ nOrigClusterWidth -= mvCharDxs[nPrevClusterLastChar];
+ nDGlyphOrigin = args.mpDXArray[nPrevClusterLastChar] - mvCharDxs[nPrevClusterLastChar];
+ }
+ long nDWidth = nNewClusterWidth - nOrigClusterWidth;
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(), "c%lu last glyph %d/%lu\n", i, nLastGlyph, mvGlyphs.size());
+#endif
+ assert((nLastGlyph > -1) && (nLastGlyph < (signed)mvGlyphs.size()));
+ mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
+ if (gi.mnGlyphIndex != GF_DROPPED)
+ mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
+ else
+ nDGlyphOrigin += nDWidth;
+ // update glyph positions
+ if (bRtl)
+ {
+ for (int n = nChar2Base; n <= nLastGlyph; n++)
+ {
+ assert((n > - 1) && (n < (signed)mvGlyphs.size()));
+ mvGlyphs[n].maLinearPos.X() += -nDGlyphOrigin + nXOffset;
+ }
+ }
+ else
+ {
+ for (int n = nChar2Base; n <= nLastGlyph; n++)
+ {
+ assert((n > - 1) && (n < (signed)mvGlyphs.size()));
+ mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + nXOffset;
+ }
+ }
+ rDeltaWidth[nChar2Base] = nDWidth;
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"c%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld\t", (int)i, nChar2Base, nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[nChar2Base].maLinearPos.X());
+#endif
+ nPrevClusterGlyph = nChar2Base;
+ nPrevClusterLastChar = nLastChar;
+ i = nLastChar;
+ }
+ }
+ // Update the dx vector with the new values.
+ std::copy(args.mpDXArray, args.mpDXArray + nChars,
+ mvCharDxs.begin() + (args.mnMinCharPos - mnMinCharPos));
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"ApplyDx %d(%ld)\n", args.mpDXArray[nChars - 1], mnWidth);
+#endif
+ mnWidth = args.mpDXArray[nChars - 1];
+}
+
+void GraphiteLayout::kashidaJustify(std::vector<int>& rDeltaWidths, sal_GlyphId nKashidaIndex, int nKashidaWidth)
+{
+ // skip if the kashida glyph in the font looks suspicious
+ if( nKashidaWidth <= 0 )
+ return;
+
+ // calculate max number of needed kashidas
+ Glyphs::iterator i = mvGlyphs.begin();
+ int nKashidaCount = 0;
+ int nOrigGlyphIndex = -1;
+ int nGlyphIndex = -1;
+ while (i != mvGlyphs.end())
+ {
+ nOrigGlyphIndex++;
+ nGlyphIndex++;
+ // only inject kashidas in RTL contexts
+ if( !(*i).IsRTLGlyph() )
+ {
+ ++i;
+ continue;
+ }
+ // no kashida-injection for blank justified expansion either
+ if( IsSpacingGlyph( (*i).mnGlyphIndex ) )
+ {
+ ++i;
+ continue;
+ }
+ // calculate gap, ignore if too small
+ int nGapWidth = rDeltaWidths[nOrigGlyphIndex];
+ // worst case is one kashida even for mini-gaps
+ if( 3 * nGapWidth < nKashidaWidth )
+ {
+ ++i;
+ continue;
+ }
+ nKashidaCount = 1 + (nGapWidth / nKashidaWidth);
+#ifdef GRLAYOUT_DEBUG
+ printf("inserting %d kashidas at %u\n", nKashidaCount, (*i).mnGlyphIndex);
+#endif
+ GlyphItem glyphItem = *i;
+ Point aPos(0, 0);
+ aPos.X() = (*i).maLinearPos.X();
+ GlyphItem newGi(glyphItem.mnCharPos, nKashidaIndex, aPos,
+ GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaWidth);
+ mvGlyphs.reserve(mvGlyphs.size() + nKashidaCount);
+ i = mvGlyphs.begin() + nGlyphIndex;
+ mvGlyphs.insert(i, nKashidaCount, newGi);
+ i = mvGlyphs.begin() + nGlyphIndex;
+ nGlyphIndex += nKashidaCount;
+ // now fix up the kashida positions
+ for (int j = 0; j < nKashidaCount; j++)
+ {
+ (*(i)).maLinearPos.X() -= nGapWidth;
+ nGapWidth -= nKashidaWidth;
+ i++;
+ }
+
+ // fixup rightmost kashida for gap remainder
+ if( nGapWidth < 0 )
+ {
+ if( nKashidaCount <= 1 )
+ nGapWidth /= 2; // for small gap move kashida to middle
+ (*(i-1)).mnNewWidth += nGapWidth; // adjust kashida width to gap width
+ (*(i-1)).maLinearPos.X() += nGapWidth;
+ }
+
+ (*i).mnNewWidth = (*i).mnOrigWidth;
+ ++i;
+ }
+
+}
+
+void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const
+{
+ // For each character except the last discover the caret positions
+ // immediatly before and after that character.
+ // This is used for underlines in the GUI amongst other things.
+ // It may be used from MultiSalLayout, in which case it must take into account
+ // glyphs that have been moved.
+ std::fill(pCaretXArray, pCaretXArray + nArraySize, -1);
+ // the layout method doesn't modify the layout even though it isn't
+ // const in the interface
+ bool bRtl = const_cast<GraphiteLayout*>(this)->maLayout.rightToLeft();
+ int prevBase = -1;
+ long prevClusterWidth = 0;
+ for (int i = 0, nCharSlot = 0; i < nArraySize && nCharSlot < static_cast<int>(mvCharDxs.size()); ++nCharSlot, i+=2)
+ {
+ if (mvChar2BaseGlyph[nCharSlot] != -1)
+ {
+ int nChar2Base = mvChar2BaseGlyph[nCharSlot] & GLYPH_INDEX_MASK;
+ assert((mvChar2BaseGlyph[nCharSlot] > -1) && (nChar2Base < (signed)mvGlyphs.size()));
+ GlyphItem gi = mvGlyphs[nChar2Base];
+ if (gi.mnGlyphIndex == GF_DROPPED)
+ {
+ continue;
+ }
+ int nCluster = nChar2Base;
+ long origClusterWidth = gi.mnNewWidth;
+ long nMin = gi.maLinearPos.X();
+ long nMax = gi.maLinearPos.X() + gi.mnNewWidth;
+ // attached glyphs are always stored after their base rtl or ltr
+ while (++nCluster < static_cast<int>(mvGlyphs.size()) &&
+ !mvGlyphs[nCluster].IsClusterStart())
+ {
+ origClusterWidth += mvGlyphs[nCluster].mnNewWidth;
+ if (mvGlyph2Char[nCluster] == nCharSlot)
+ {
+ nMin = std::min(nMin, mvGlyphs[nCluster].maLinearPos.X());
+ nMax = std::min(nMax, mvGlyphs[nCluster].maLinearPos.X() + mvGlyphs[nCluster].mnNewWidth);
+ }
+ }
+ if (bRtl)
+ {
+ pCaretXArray[i+1] = nMin;
+ pCaretXArray[i] = nMax;
+ }
+ else
+ {
+ pCaretXArray[i] = nMin;
+ pCaretXArray[i+1] = nMax;
+ }
+ prevBase = nChar2Base;
+ prevClusterWidth = origClusterWidth;
+ }
+ else if (prevBase > -1)
+ {
+ // this could probably be improved
+ assert((prevBase > -1) && (prevBase < (signed)mvGlyphs.size()));
+ GlyphItem gi = mvGlyphs[prevBase];
+ int nGlyph = prevBase + 1;
+ // try to find a better match, otherwise default to complete cluster
+ for (; nGlyph < static_cast<int>(mvGlyphs.size()) &&
+ !mvGlyphs[nGlyph].IsClusterStart(); nGlyph++)
+ {
+ if (mvGlyph2Char[nGlyph] == nCharSlot)
+ {
+ gi = mvGlyphs[nGlyph];
+ break;
+ }
+ }
+ long nGWidth = gi.mnNewWidth;
+ // if no match position at end of cluster
+ if (nGlyph == static_cast<int>(mvGlyphs.size()) ||
+ mvGlyphs[nGlyph].IsClusterStart())
+ {
+ nGWidth = prevClusterWidth;
+ if (bRtl)
+ {
+ pCaretXArray[i+1] = gi.maLinearPos.X();
+ pCaretXArray[i] = gi.maLinearPos.X();
+ }
+ else
+ {
+ pCaretXArray[i] = gi.maLinearPos.X() + prevClusterWidth;
+ pCaretXArray[i+1] = gi.maLinearPos.X() + prevClusterWidth;
+ }
+ }
+ else
+ {
+ if (bRtl)
+ {
+ pCaretXArray[i+1] = gi.maLinearPos.X();
+ pCaretXArray[i] = gi.maLinearPos.X() + gi.mnNewWidth;
+ }
+ else
+ {
+ pCaretXArray[i] = gi.maLinearPos.X();
+ pCaretXArray[i+1] = gi.maLinearPos.X() + gi.mnNewWidth;
+ }
+ }
+ }
+ else
+ {
+ pCaretXArray[i] = pCaretXArray[i+1] = 0;
+ }
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"%d,%d-%d\t", nCharSlot, pCaretXArray[i], pCaretXArray[i+1]);
+#endif
+ }
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"\n");
+#endif
+}
+
+
+// GetNextGlyphs returns a contiguous sequence of glyphs that can be
+// rendered together. It should never return a dropped glyph.
+// The glyph_slot returned should be the index of the next visible
+// glyph after the last glyph returned by this call.
+// The char_index array should be filled with the characters corresponding
+// to each glyph returned.
+// glyph_adv array should be a virtual width such that if successive
+// glyphs returned by this method are added one after the other they
+// have the correct spacing.
+// The logic in this method must match that expected in MultiSalLayout which
+// is used when glyph fallback is in operation.
+int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out,
+ ::Point & aPosOut, int &glyph_slot, sal_Int32 * glyph_adv, int *char_index) const
+{
+ // Sanity check on the slot index.
+ if (glyph_slot >= signed(mvGlyphs.size()))
+ {
+ glyph_slot = mvGlyphs.size();
+ return 0;
+ }
+ assert(glyph_slot >= 0);
+ // Find the first glyph in the substring.
+ for (; glyph_slot < signed(mvGlyphs.size()) &&
+ ((mvGlyphs.begin() + glyph_slot)->mnGlyphIndex == GF_DROPPED);
+ ++glyph_slot) {};
+
+ // Update the length
+ const int nGlyphSlotEnd = std::min(size_t(glyph_slot + length), mvGlyphs.size());
+
+ // We're all out of glyphs here.
+ if (glyph_slot == nGlyphSlotEnd)
+ {
+ return 0;
+ }
+
+ // Find as many glyphs as we can which can be drawn in one go.
+ Glyphs::const_iterator glyph_itr = mvGlyphs.begin() + glyph_slot;
+ const int glyph_slot_begin = glyph_slot;
+ const int initial_y_pos = glyph_itr->maLinearPos.Y();
+
+ // Set the position to the position of the start glyph.
+ ::Point aStartPos = glyph_itr->maLinearPos;
+ //aPosOut = glyph_itr->maLinearPos;
+ aPosOut = GetDrawPosition(aStartPos);
+
+
+ for (;;) // Forever
+ {
+ // last index of the range from glyph_to_chars does not include this glyph
+ if (char_index)
+ {
+ assert((glyph_slot >= -1) && (glyph_slot < (signed)mvGlyph2Char.size()));
+ if (mvGlyph2Char[glyph_slot] == -1)
+ *char_index++ = mvCharDxs.size();
+ else
+ *char_index++ = mvGlyph2Char[glyph_slot];
+ }
+ // Copy out this glyphs data.
+ ++glyph_slot;
+ *glyph_out++ = glyph_itr->mnGlyphIndex;
+
+ // Find the actual advance - this must be correct if called from
+ // MultiSalLayout::AdjustLayout which requests one glyph at a time.
+ const long nGlyphAdvance = (glyph_slot == static_cast<int>(mvGlyphs.size()))?
+ glyph_itr->mnNewWidth :
+ ((glyph_itr+1)->maLinearPos.X() - glyph_itr->maLinearPos.X());
+
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"GetNextGlyphs g%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", glyph_slot - 1,
+ GLYPH_INDEX_MASK&mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance,
+ aPosOut.X(), aPosOut.Y());
+#endif
+
+ if (glyph_adv) // If we are returning advance store it.
+ *glyph_adv++ = nGlyphAdvance;
+ else // Stop when next advance is unexpected.
+ if (glyph_itr->mnOrigWidth != nGlyphAdvance) break;
+
+ // Have fetched all the glyphs we need to
+ if (glyph_slot == nGlyphSlotEnd)
+ break;
+
+ ++glyph_itr;
+ // Stop when next y position is unexpected.
+ if (initial_y_pos != glyph_itr->maLinearPos.Y())
+ break;
+
+ // Stop if glyph dropped
+ if (glyph_itr->mnGlyphIndex == GF_DROPPED)
+ break;
+ }
+ int numGlyphs = glyph_slot - glyph_slot_begin;
+ // move the next glyph_slot to a glyph that hasn't been dropped
+ while (glyph_slot < static_cast<int>(mvGlyphs.size()) &&
+ (mvGlyphs.begin() + glyph_slot)->mnGlyphIndex == GF_DROPPED)
+ ++glyph_slot;
+ return numGlyphs;
+}
+
+
+void GraphiteLayout::MoveGlyph( int nGlyphIndex, long nNewPos )
+{
+ // TODO it might be better to actualy implement simplify properly, but this
+ // needs to be done carefully so the glyph/char maps are maintained
+ // If a glyph has been dropped then it wasn't returned by GetNextGlyphs, so
+ // the index here may be wrong
+ while ((mvGlyphs[nGlyphIndex].mnGlyphIndex == GF_DROPPED) &&
+ (nGlyphIndex < (signed)mvGlyphs.size()))
+ {
+ nGlyphIndex++;
+ }
+ const long dx = nNewPos - mvGlyphs[nGlyphIndex].maLinearPos.X();
+
+ if (dx == 0) return;
+ // GenericSalLayout only changes maLinearPos, mvCharDxs doesn't change
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Move %d (%ld,%ld) c%d by %ld\n", nGlyphIndex, mvGlyphs[nGlyphIndex].maLinearPos.X(), nNewPos, mvGlyph2Char[nGlyphIndex], dx);
+#endif
+ for (size_t gi = nGlyphIndex; gi < mvGlyphs.size(); gi++)
+ {
+ mvGlyphs[gi].maLinearPos.X() += dx;
+ }
+ // width does need to be updated for correct fallback
+ mnWidth += dx;
+}
+
+
+void GraphiteLayout::DropGlyph( int nGlyphIndex )
+{
+ if(nGlyphIndex >= signed(mvGlyphs.size()))
+ return;
+
+ GlyphItem & glyph = mvGlyphs[nGlyphIndex];
+ glyph.mnGlyphIndex = GF_DROPPED;
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Dropped %d\n", nGlyphIndex);
+#endif
+}
+
+void GraphiteLayout::Simplify( bool isBaseLayout )
+{
+ const sal_GlyphId dropMarker = isBaseLayout ? GF_DROPPED : 0;
+
+ Glyphs::iterator gi = mvGlyphs.begin();
+ // TODO check whether we need to adjust positions here
+ // MultiSalLayout seems to move the glyphs itself, so it may not be needed.
+ long deltaX = 0;
+ while (gi != mvGlyphs.end())
+ {
+ if (gi->mnGlyphIndex == dropMarker)
+ {
+ deltaX += gi->mnNewWidth;
+ gi->mnNewWidth = 0;
+ }
+ else
+ {
+ deltaX = 0;
+ }
+ //mvCharDxs[mvGlyph2Char[gi->mnCharPos]] -= deltaX;
+ ++gi;
+ }
+#ifdef GRLAYOUT_DEBUG
+ fprintf(grLog(),"Simplify base%d dx=%ld newW=%ld\n", isBaseLayout, deltaX, mnWidth - deltaX);
+#endif
+ // discard width from trailing dropped glyphs, but not those in the middle
+ mnWidth -= deltaX;
+}
diff --git a/vcl/source/glyphs/graphite_serverfont.cxx b/vcl/source/glyphs/graphite_serverfont.cxx
new file mode 100644
index 000000000000..eda97f509f03
--- /dev/null
+++ b/vcl/source/glyphs/graphite_serverfont.cxx
@@ -0,0 +1,85 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// We need this to enable namespace support in libgrengine headers.
+#define GR_NAMESPACE
+
+// Header files
+//
+
+// Platform
+#include <vcl/sallayout.hxx>
+// Module
+#include "gcach_ftyp.hxx"
+#include <vcl/graphite_features.hxx>
+#include "graphite_textsrc.hxx"
+#include <vcl/graphite_serverfont.hxx>
+
+#ifndef WNT
+
+//
+// An implementation of the GraphiteLayout interface to enable Graphite enabled fonts to be used.
+//
+
+GraphiteServerFontLayout::GraphiteServerFontLayout(GraphiteFontAdaptor * pFont) throw()
+ : ServerFontLayout(pFont->font()), mpFont(pFont),
+ maImpl(*mpFont, mpFont->features(), pFont)
+{
+ // Nothing needed here
+}
+
+GraphiteServerFontLayout::~GraphiteServerFontLayout() throw()
+{
+ delete mpFont;
+ mpFont = NULL;
+}
+
+const sal_Unicode* GraphiteServerFontLayout::getTextPtr() const
+{
+ return maImpl.textSrc()->getLayoutArgs().mpStr +
+ maImpl.textSrc()->getLayoutArgs().mnMinCharPos;
+}
+
+sal_GlyphId GraphiteLayoutImpl::getKashidaGlyph(int & width)
+{
+ int nKashidaIndex = mpFont->font().GetGlyphIndex( 0x0640 );
+ if( nKashidaIndex != 0 )
+ {
+ const GlyphMetric& rGM = mpFont->font().GetGlyphMetric( nKashidaIndex );
+ width = rGM.GetCharWidth();
+ }
+ else
+ {
+ width = 0;
+ }
+ return nKashidaIndex;
+}
+
+#endif
diff --git a/vcl/source/glyphs/graphite_textsrc.cxx b/vcl/source/glyphs/graphite_textsrc.cxx
new file mode 100644
index 000000000000..5764ba9454c9
--- /dev/null
+++ b/vcl/source/glyphs/graphite_textsrc.cxx
@@ -0,0 +1,169 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// We need this to enable namespace support in libgrengine headers.
+#define GR_NAMESPACE
+
+// Header files
+//
+// Standard Library
+#include <string>
+#include <cassert>
+#include "graphite_textsrc.hxx"
+#include <vcl/graphite_features.hxx>
+
+// class TextSourceAdaptor implementation.
+//
+TextSourceAdaptor::~TextSourceAdaptor()
+{
+ delete mpFeatures;
+}
+
+gr::UtfType TextSourceAdaptor::utfEncodingForm() {
+ return gr::kutf16;
+}
+
+
+size_t TextSourceAdaptor::getLength()
+{
+ return maLayoutArgs.mnLength;
+}
+
+
+size_t TextSourceAdaptor::fetch(gr::toffset, size_t, gr::utf32 *)
+{
+ assert(false);
+ return 0;
+}
+
+
+size_t TextSourceAdaptor::fetch(gr::toffset offset, size_t char_count, gr::utf16 * char_buffer)
+{
+ assert(char_buffer);
+
+ size_t copy_count = std::min(size_t(maLayoutArgs.mnLength), char_count);
+ std::copy(maLayoutArgs.mpStr + offset, maLayoutArgs.mpStr + offset + copy_count, char_buffer);
+
+ return copy_count;
+}
+
+
+size_t TextSourceAdaptor::fetch(gr::toffset, size_t, gr::utf8 *)
+{
+ assert(false);
+ return 0;
+}
+
+
+inline void TextSourceAdaptor::getCharProperties(const int nCharIdx, int & min, int & lim, size_t & depth)
+{
+ maLayoutArgs.ResetPos();
+ bool rtl = maLayoutArgs.mnFlags & SAL_LAYOUT_BIDI_RTL;
+ for(depth = ((rtl)? 1:0); maLayoutArgs.maRuns.GetRun(&min, &lim, &rtl); maLayoutArgs.maRuns.NextRun())
+ {
+ if (min > nCharIdx)
+ break;
+ // Only increase the depth when a change of direction occurs.
+ depth += int(rtl ^ bool(depth & 0x1));
+ if (min <= nCharIdx && nCharIdx < lim)
+ break;
+ }
+ // If there is no run for this position increment the depth, but don't
+ // change if this is out of bounds context
+ if (lim > 0 && nCharIdx >= lim && nCharIdx < maLayoutArgs.mnEndCharPos)
+ depth++;
+}
+
+
+bool TextSourceAdaptor::getRightToLeft(gr::toffset nCharIdx)
+{
+ size_t depth;
+ int min, lim = 0;
+ getCharProperties(nCharIdx, min, lim, depth);
+ //printf("getRtl %d,%x=%d\n", nCharIdx, maLayoutArgs.mpStr[nCharIdx], depth & 0x1);
+ return depth & 0x1;
+}
+
+
+unsigned int TextSourceAdaptor::getDirectionDepth(gr::toffset nCharIdx)
+{
+ size_t depth;
+ int min, lim;
+ getCharProperties(nCharIdx, min, lim, depth);
+ //printf("getDirectionDepth %d,%x=%d\n", nCharIdx, maLayoutArgs.mpStr[nCharIdx], depth);
+ return depth;
+}
+
+
+float TextSourceAdaptor::getVerticalOffset(gr::toffset)
+{
+ return 0.0f; //TODO: Implement correctly
+}
+
+gr::isocode TextSourceAdaptor::getLanguage(gr::toffset)
+{
+ if (mpFeatures && mpFeatures->hasLanguage())
+ return mpFeatures->getLanguage();
+ gr::isocode unknown = {{0,0,0,0}};
+ return unknown;
+}
+
+ext_std::pair<gr::toffset, gr::toffset> TextSourceAdaptor::propertyRange(gr::toffset nCharIdx)
+{
+
+ if (nCharIdx < unsigned(maLayoutArgs.mnMinCharPos))
+ return ext_std::make_pair(0, maLayoutArgs.mnMinCharPos);
+
+ if (nCharIdx < mnEnd)
+ return ext_std::make_pair(maLayoutArgs.mnMinCharPos, mnEnd);
+
+ return ext_std::make_pair(mnEnd, maLayoutArgs.mnLength);
+}
+
+size_t TextSourceAdaptor::getFontFeatures(gr::toffset, gr::FeatureSetting * settings)
+{
+ if (mpFeatures) return mpFeatures->getFontFeatures(settings);
+ return 0;
+}
+
+
+bool TextSourceAdaptor::sameSegment(gr::toffset char_idx1, gr::toffset char_idx2)
+{
+ const ext_std::pair<gr::toffset, gr::toffset>
+ range1 = propertyRange(char_idx1),
+ range2 = propertyRange(char_idx2);
+
+ return range1 == range2;
+}
+
+void TextSourceAdaptor::setFeatures(const grutils::GrFeatureParser * pFeatures)
+{
+ mpFeatures = new grutils::GrFeatureParser(*pFeatures);
+}
diff --git a/vcl/source/glyphs/graphite_textsrc.hxx b/vcl/source/glyphs/graphite_textsrc.hxx
new file mode 100644
index 000000000000..3912977cc9be
--- /dev/null
+++ b/vcl/source/glyphs/graphite_textsrc.hxx
@@ -0,0 +1,131 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GRAPHITETEXTSRC_HXX
+#define _SV_GRAPHITETEXTSRC_HXX
+// Description: Implements the Graphite interfaces IGrTextSource and
+// IGrGraphics which provide Graphite with access to the
+// app's text storage system and the platform's font and
+// graphics systems.
+
+// We need this to enable namespace support in libgrengine headers.
+#define GR_NAMESPACE
+
+// Standard Library
+#include <stdexcept>
+// Platform
+
+#ifndef _SVWIN_H
+#include <tools/svwin.h>
+#endif
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+
+#ifndef _SV_SALGDI_HXX
+#include <vcl/salgdi.hxx>
+#endif
+
+#ifndef _SV_SALLAYOUT_HXX
+#include <vcl/sallayout.hxx>
+#endif
+
+// Module
+#include "vcl/dllapi.h"
+
+// Libraries
+#include <tools/preextstl.h>
+#include <graphite/GrClient.h>
+#include <graphite/Font.h>
+#include <graphite/ITextSource.h>
+#include <tools/postextstl.h>
+
+// Module type definitions and forward declarations.
+//
+namespace grutils
+{
+ class GrFeatureParser;
+}
+// Implements the Adaptor pattern to adapt the LayoutArgs and the ServerFont interfaces to the
+// gr::IGrTextSource interface.
+// @author tse
+//
+class TextSourceAdaptor : public gr::ITextSource
+{
+public:
+ TextSourceAdaptor(ImplLayoutArgs &layout_args, const int nContextLen) throw();
+ ~TextSourceAdaptor();
+ virtual gr::UtfType utfEncodingForm();
+ virtual size_t getLength();
+ virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer);
+ virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchwBuffer);
+ virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf8 * prgchsBuffer);
+ virtual bool getRightToLeft(gr::toffset ich);
+ virtual unsigned int getDirectionDepth(gr::toffset ich);
+ virtual float getVerticalOffset(gr::toffset ich);
+ virtual gr::isocode getLanguage(gr::toffset ich);
+
+ virtual ext_std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich);
+ virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset);
+ virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2);
+ virtual bool featureVariations() { return false; }
+
+ operator ImplLayoutArgs & () throw();
+ void setFeatures(const grutils::GrFeatureParser * pFeatures);
+ const ImplLayoutArgs & getLayoutArgs() const { return maLayoutArgs; }
+ size_t getContextLength() const { return mnEnd; };
+ inline void switchLayoutArgs(ImplLayoutArgs & newArgs);
+private:
+ // Prevent the generation of a default assignment operator.
+ TextSourceAdaptor & operator=(const TextSourceAdaptor &);
+
+ void getCharProperties(const int, int &, int &, size_t &);
+
+ ImplLayoutArgs maLayoutArgs;
+ size_t mnEnd;
+ const grutils::GrFeatureParser * mpFeatures;
+};
+
+inline TextSourceAdaptor::TextSourceAdaptor(ImplLayoutArgs &la, const int nContextLen) throw()
+ : maLayoutArgs(la),
+ mnEnd(std::min(la.mnLength, nContextLen)),
+ mpFeatures(NULL)
+{
+}
+
+inline TextSourceAdaptor::operator ImplLayoutArgs & () throw() {
+ return maLayoutArgs;
+}
+
+inline void TextSourceAdaptor::switchLayoutArgs(ImplLayoutArgs & aNewArgs)
+{
+ mnEnd += aNewArgs.mnMinCharPos - maLayoutArgs.mnMinCharPos;
+ maLayoutArgs = aNewArgs;
+}
+
+#endif
diff --git a/vcl/source/glyphs/makefile.mk b/vcl/source/glyphs/makefile.mk
new file mode 100644
index 000000000000..74811aba6204
--- /dev/null
+++ b/vcl/source/glyphs/makefile.mk
@@ -0,0 +1,80 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=glyphs
+
+ENABLE_EXCEPTIONS=true
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+CFLAGS+= $(FREETYPE_CFLAGS)
+
+# --- Files --------------------------------------------------------
+
+.IF "$(USE_BUILTIN_RASTERIZER)" != ""
+# GlyphCache + FreeType support (only on UNX platforms currently)
+SLOFILES=\
+ $(SLO)$/glyphcache.obj \
+ $(SLO)$/gcach_rbmp.obj \
+ $(SLO)$/gcach_layout.obj \
+ $(SLO)$/gcach_ftyp.obj
+
+.IF "$(ENABLE_GRAPHITE)" != ""
+# Graphite support using the glyphcache infrastructure
+CFLAGS+=-DENABLE_GRAPHITE
+SLOFILES+= $(SLO)$/graphite_adaptors.obj \
+ $(SLO)$/graphite_features.obj \
+ $(SLO)$/graphite_cache.obj \
+ $(SLO)$/graphite_textsrc.obj \
+ $(SLO)$/graphite_serverfont.obj \
+ $(SLO)$/graphite_layout.obj
+.ENDIF
+
+.ELSE
+
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+# Graphite support on non-UNX platforms
+# make use of stlport headerfiles
+EXT_USE_STLPORT=TRUE
+SLOFILES=\
+ $(SLO)$/graphite_textsrc.obj \
+ $(SLO)$/graphite_cache.obj \
+ $(SLO)$/graphite_features.obj \
+ $(SLO)$/graphite_layout.obj
+.ENDIF
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/source/helper/canvasbitmap.cxx b/vcl/source/helper/canvasbitmap.cxx
new file mode 100644
index 000000000000..2bc0ab94d272
--- /dev/null
+++ b/vcl/source/helper/canvasbitmap.cxx
@@ -0,0 +1,1467 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <com/sun/star/util/Endianness.hpp>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/rendering/RenderingIntent.hpp>
+
+#include <rtl/instance.hxx>
+#include <vos/mutex.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <vcl/canvasbitmap.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/svapp.hxx>
+
+#include <algorithm>
+
+
+using namespace ::vcl::unotools;
+using namespace ::com::sun::star;
+
+namespace
+{
+ // TODO(Q3): move to o3tl bithacks or somesuch. A similar method is in canvas/canvastools.hxx
+
+ // Good ole HAKMEM tradition. Calc number of 1 bits in 32bit word,
+ // unrolled loop. See e.g. Hackers Delight, p. 66
+ inline sal_Int32 bitcount( sal_uInt32 val )
+ {
+ val = val - ((val >> 1) & 0x55555555);
+ val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
+ val = (val + (val >> 4)) & 0x0F0F0F0F;
+ val = val + (val >> 8);
+ val = val + (val >> 16);
+ return sal_Int32(val & 0x0000003F);
+ }
+}
+
+void VclCanvasBitmap::setComponentInfo( ULONG redShift, ULONG greenShift, ULONG blueShift )
+{
+ // sort channels in increasing order of appearance in the pixel
+ // (starting with the least significant bits)
+ sal_Int8 redPos(0);
+ sal_Int8 greenPos(1);
+ sal_Int8 bluePos(2);
+
+ if( redShift > greenShift )
+ {
+ std::swap(redPos,greenPos);
+ if( redShift > blueShift )
+ {
+ std::swap(redPos,bluePos);
+ if( greenShift > blueShift )
+ std::swap(greenPos,bluePos);
+ }
+ }
+ else
+ {
+ if( greenShift > blueShift )
+ {
+ std::swap(greenPos,bluePos);
+ if( redShift > blueShift )
+ std::swap(redPos,bluePos);
+ }
+ }
+
+ m_aComponentTags.realloc(3);
+ sal_Int8* pTags = m_aComponentTags.getArray();
+ pTags[redPos] = rendering::ColorComponentTag::RGB_RED;
+ pTags[greenPos] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[bluePos] = rendering::ColorComponentTag::RGB_BLUE;
+
+ m_aComponentBitCounts.realloc(3);
+ sal_Int32* pCounts = m_aComponentBitCounts.getArray();
+ pCounts[redPos] = bitcount(sal::static_int_cast<sal_uInt32>(redShift));
+ pCounts[greenPos] = bitcount(sal::static_int_cast<sal_uInt32>(greenShift));
+ pCounts[bluePos] = bitcount(sal::static_int_cast<sal_uInt32>(blueShift));
+}
+
+VclCanvasBitmap::VclCanvasBitmap( const BitmapEx& rBitmap ) :
+ m_aBmpEx( rBitmap ),
+ m_aBitmap( rBitmap.GetBitmap() ),
+ m_aAlpha(),
+ m_pBmpAcc( m_aBitmap.AcquireReadAccess() ),
+ m_pAlphaAcc( NULL ),
+ m_aComponentTags(),
+ m_aComponentBitCounts(),
+ m_aLayout(),
+ m_nBitsPerInputPixel(0),
+ m_nBitsPerOutputPixel(0),
+ m_nRedIndex(-1),
+ m_nGreenIndex(-1),
+ m_nBlueIndex(-1),
+ m_nAlphaIndex(-1),
+ m_nIndexIndex(-1),
+ m_nEndianness(0),
+ m_bSwap(false),
+ m_bPalette(false)
+{
+ if( m_aBmpEx.IsTransparent() )
+ {
+ m_aAlpha = m_aBmpEx.IsAlpha() ? m_aBmpEx.GetAlpha().GetBitmap() : m_aBmpEx.GetMask();
+ m_pAlphaAcc = m_aAlpha.AcquireReadAccess();
+ }
+
+ m_aLayout.ScanLines = 0;
+ m_aLayout.ScanLineBytes = 0;
+ m_aLayout.ScanLineStride = 0;
+ m_aLayout.PlaneStride = 0;
+ m_aLayout.ColorSpace.clear();
+ m_aLayout.Palette.clear();
+ m_aLayout.IsMsbFirst = sal_False;
+
+ if( m_pBmpAcc )
+ {
+ m_aLayout.ScanLines = m_pBmpAcc->Height();
+ m_aLayout.ScanLineBytes = (m_pBmpAcc->GetBitCount()*m_pBmpAcc->Width() + 7) / 8;
+ m_aLayout.ScanLineStride = m_pBmpAcc->GetScanlineSize();
+ m_aLayout.PlaneStride = 0;
+
+ switch( m_pBmpAcc->GetScanlineFormat() )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ m_bPalette = true;
+ m_nBitsPerInputPixel = 1;
+ m_nEndianness = util::Endianness::LITTLE; // doesn't matter
+ m_aLayout.IsMsbFirst = sal_True;
+ break;
+
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ m_bPalette = true;
+ m_nBitsPerInputPixel = 1;
+ m_nEndianness = util::Endianness::LITTLE; // doesn't matter
+ m_aLayout.IsMsbFirst = sal_False;
+ break;
+
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ m_bPalette = true;
+ m_nBitsPerInputPixel = 4;
+ m_nEndianness = util::Endianness::LITTLE; // doesn't matter
+ m_aLayout.IsMsbFirst = sal_True;
+ break;
+
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ m_bPalette = true;
+ m_nBitsPerInputPixel = 4;
+ m_nEndianness = util::Endianness::LITTLE; // doesn't matter
+ m_aLayout.IsMsbFirst = sal_False;
+ break;
+
+ case BMP_FORMAT_8BIT_PAL:
+ m_bPalette = true;
+ m_nBitsPerInputPixel = 8;
+ m_nEndianness = util::Endianness::LITTLE; // doesn't matter
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ break;
+
+ case BMP_FORMAT_8BIT_TC_MASK:
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 8;
+ m_nEndianness = util::Endianness::LITTLE; // doesn't matter
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
+ m_pBmpAcc->GetColorMask().GetGreenMask(),
+ m_pBmpAcc->GetColorMask().GetBlueMask() );
+ break;
+
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 16;
+ m_nEndianness = util::Endianness::BIG;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
+ m_pBmpAcc->GetColorMask().GetGreenMask(),
+ m_pBmpAcc->GetColorMask().GetBlueMask() );
+ break;
+
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 16;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
+ m_pBmpAcc->GetColorMask().GetGreenMask(),
+ m_pBmpAcc->GetColorMask().GetBlueMask() );
+ break;
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 24;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ setComponentInfo( 0xff0000LL,
+ 0x00ff00LL,
+ 0x0000ffLL );
+ break;
+
+ case BMP_FORMAT_24BIT_TC_RGB:
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 24;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ setComponentInfo( 0x0000ffLL,
+ 0x00ff00LL,
+ 0xff0000LL );
+ break;
+
+ case BMP_FORMAT_24BIT_TC_MASK:
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 24;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
+ m_pBmpAcc->GetColorMask().GetGreenMask(),
+ m_pBmpAcc->GetColorMask().GetBlueMask() );
+ break;
+
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ {
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 32;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+
+ m_aComponentTags.realloc(4);
+ sal_Int8* pTags = m_aComponentTags.getArray();
+ pTags[0] = rendering::ColorComponentTag::ALPHA;
+ pTags[1] = rendering::ColorComponentTag::RGB_BLUE;
+ pTags[2] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[3] = rendering::ColorComponentTag::RGB_RED;
+
+ m_aComponentBitCounts.realloc(4);
+ sal_Int32* pCounts = m_aComponentBitCounts.getArray();
+ pCounts[0] = 8;
+ pCounts[1] = 8;
+ pCounts[2] = 8;
+ pCounts[3] = 8;
+
+ m_nRedIndex = 3;
+ m_nGreenIndex = 2;
+ m_nBlueIndex = 1;
+ m_nAlphaIndex = 0;
+ }
+ break;
+
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ {
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 32;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+
+ m_aComponentTags.realloc(4);
+ sal_Int8* pTags = m_aComponentTags.getArray();
+ pTags[0] = rendering::ColorComponentTag::ALPHA;
+ pTags[1] = rendering::ColorComponentTag::RGB_RED;
+ pTags[2] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[3] = rendering::ColorComponentTag::RGB_BLUE;
+
+ m_aComponentBitCounts.realloc(4);
+ sal_Int32* pCounts = m_aComponentBitCounts.getArray();
+ pCounts[0] = 8;
+ pCounts[1] = 8;
+ pCounts[2] = 8;
+ pCounts[3] = 8;
+
+ m_nRedIndex = 1;
+ m_nGreenIndex = 2;
+ m_nBlueIndex = 3;
+ m_nAlphaIndex = 0;
+ }
+ break;
+
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ {
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 32;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+
+ m_aComponentTags.realloc(4);
+ sal_Int8* pTags = m_aComponentTags.getArray();
+ pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
+ pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[2] = rendering::ColorComponentTag::RGB_RED;
+ pTags[3] = rendering::ColorComponentTag::ALPHA;
+
+ m_aComponentBitCounts.realloc(4);
+ sal_Int32* pCounts = m_aComponentBitCounts.getArray();
+ pCounts[0] = 8;
+ pCounts[1] = 8;
+ pCounts[2] = 8;
+ pCounts[3] = 8;
+
+ m_nRedIndex = 2;
+ m_nGreenIndex = 1;
+ m_nBlueIndex = 0;
+ m_nAlphaIndex = 3;
+ }
+ break;
+
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ {
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 32;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+
+ m_aComponentTags.realloc(4);
+ sal_Int8* pTags = m_aComponentTags.getArray();
+ pTags[0] = rendering::ColorComponentTag::RGB_RED;
+ pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
+ pTags[3] = rendering::ColorComponentTag::ALPHA;
+
+ m_aComponentBitCounts.realloc(4);
+ sal_Int32* pCounts = m_aComponentBitCounts.getArray();
+ pCounts[0] = 8;
+ pCounts[1] = 8;
+ pCounts[2] = 8;
+ pCounts[3] = 8;
+
+ m_nRedIndex = 0;
+ m_nGreenIndex = 1;
+ m_nBlueIndex = 2;
+ m_nAlphaIndex = 3;
+ }
+ break;
+
+ case BMP_FORMAT_32BIT_TC_MASK:
+ m_bPalette = false;
+ m_nBitsPerInputPixel = 32;
+ m_nEndianness = util::Endianness::LITTLE;
+ m_aLayout.IsMsbFirst = sal_False; // doesn't matter
+ setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(),
+ m_pBmpAcc->GetColorMask().GetGreenMask(),
+ m_pBmpAcc->GetColorMask().GetBlueMask() );
+ break;
+
+ default:
+ DBG_ERROR( "unsupported bitmap format" );
+ break;
+ }
+
+ if( m_bPalette )
+ {
+ m_aComponentTags.realloc(1);
+ m_aComponentTags[0] = rendering::ColorComponentTag::INDEX;
+
+ m_aComponentBitCounts.realloc(1);
+ m_aComponentBitCounts[0] = m_nBitsPerInputPixel;
+
+ m_nIndexIndex = 0;
+ }
+
+ m_nBitsPerOutputPixel = m_nBitsPerInputPixel;
+ if( m_aBmpEx.IsTransparent() )
+ {
+ // TODO(P1): need to interleave alpha with bitmap data -
+ // won't fuss with less-than-8 bit for now
+ m_nBitsPerOutputPixel = std::max(sal_Int32(8),m_nBitsPerInputPixel);
+
+ // check whether alpha goes in front or behind the
+ // bitcount sequence. If pixel format is little endian,
+ // put it behind all the other channels. If it's big
+ // endian, put it in front (because later, the actual data
+ // always gets written after the pixel data)
+
+ // TODO(Q1): slight catch - in the case of the
+ // BMP_FORMAT_32BIT_XX_ARGB formats, duplicate alpha
+ // channels might happen!
+ m_aComponentTags.realloc(m_aComponentTags.getLength()+1);
+ m_aComponentTags[m_aComponentTags.getLength()-1] = rendering::ColorComponentTag::ALPHA;
+
+ m_aComponentBitCounts.realloc(m_aComponentBitCounts.getLength()+1);
+ m_aComponentBitCounts[m_aComponentBitCounts.getLength()-1] = m_aBmpEx.IsAlpha() ? 8 : 1;
+
+ if( m_nEndianness == util::Endianness::BIG )
+ {
+ // put alpha in front of all the color channels
+ sal_Int8* pTags =m_aComponentTags.getArray();
+ sal_Int32* pCounts=m_aComponentBitCounts.getArray();
+ std::rotate(pTags,
+ pTags+m_aComponentTags.getLength()-1,
+ pTags+m_aComponentTags.getLength());
+ std::rotate(pCounts,
+ pCounts+m_aComponentBitCounts.getLength()-1,
+ pCounts+m_aComponentBitCounts.getLength());
+ ++m_nRedIndex;
+ ++m_nGreenIndex;
+ ++m_nBlueIndex;
+ ++m_nIndexIndex;
+ m_nAlphaIndex=0;
+ }
+
+ // always add a full byte to the pixel size, otherwise
+ // pixel packing hell breaks loose.
+ m_nBitsPerOutputPixel += 8;
+
+ // adapt scanline parameters
+ const Size aSize = m_aBitmap.GetSizePixel();
+ m_aLayout.ScanLineBytes =
+ m_aLayout.ScanLineStride = (aSize.Width()*m_nBitsPerOutputPixel + 7)/8;
+ }
+ }
+}
+
+VclCanvasBitmap::~VclCanvasBitmap()
+{
+ if( m_pAlphaAcc )
+ m_aAlpha.ReleaseAccess(m_pAlphaAcc);
+ if( m_pBmpAcc )
+ m_aBitmap.ReleaseAccess(m_pBmpAcc);
+}
+
+// XBitmap
+geometry::IntegerSize2D SAL_CALL VclCanvasBitmap::getSize() throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ return integerSize2DFromSize( m_aBitmap.GetSizePixel() );
+}
+
+::sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha() throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ return m_aBmpEx.IsTransparent();
+}
+
+uno::Reference< rendering::XBitmap > SAL_CALL VclCanvasBitmap::getScaledBitmap( const geometry::RealSize2D& newSize,
+ sal_Bool beFast ) throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ BitmapEx aNewBmp( m_aBitmap );
+ aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BMP_SCALE_FAST : BMP_SCALE_INTERPOLATE );
+ return uno::Reference<rendering::XBitmap>( new VclCanvasBitmap( aNewBmp ) );
+}
+
+// XIntegerReadOnlyBitmap
+uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getData( rendering::IntegerBitmapLayout& bitmapLayout,
+ const geometry::IntegerRectangle2D& rect ) throw( lang::IndexOutOfBoundsException,
+ rendering::VolatileContentDestroyedException,
+ uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ bitmapLayout = getMemoryLayout();
+
+ const ::Rectangle aRequestedArea( vcl::unotools::rectangleFromIntegerRectangle2D(rect) );
+ if( aRequestedArea.IsEmpty() )
+ return uno::Sequence< sal_Int8 >();
+
+ // Invalid/empty bitmap: no data available
+ if( !m_pBmpAcc )
+ throw lang::IndexOutOfBoundsException();
+ if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc )
+ throw lang::IndexOutOfBoundsException();
+
+ if( aRequestedArea.Left() < 0 || aRequestedArea.Top() < 0 ||
+ aRequestedArea.Right() > m_pBmpAcc->Width() ||
+ aRequestedArea.Bottom() > m_pBmpAcc->Height() )
+ {
+ throw lang::IndexOutOfBoundsException();
+ }
+
+ uno::Sequence< sal_Int8 > aRet;
+ Rectangle aRequestedBytes( aRequestedArea );
+
+ // adapt to byte boundaries
+ aRequestedBytes.Left() = aRequestedArea.Left()*m_nBitsPerOutputPixel/8;
+ aRequestedBytes.Right() = (aRequestedArea.Right()*m_nBitsPerOutputPixel + 7)/8;
+
+ // copy stuff to output sequence
+ aRet.realloc(aRequestedBytes.getWidth()*aRequestedBytes.getHeight());
+ sal_Int8* pOutBuf = aRet.getArray();
+
+ bitmapLayout.ScanLines = aRequestedBytes.getHeight();
+ bitmapLayout.ScanLineBytes =
+ bitmapLayout.ScanLineStride= aRequestedBytes.getWidth();
+
+ sal_Int32 nScanlineStride=bitmapLayout.ScanLineStride;
+ if( !(m_pBmpAcc->GetScanlineFormat() & BMP_FORMAT_TOP_DOWN) )
+ {
+ pOutBuf += bitmapLayout.ScanLineStride*(aRequestedBytes.getHeight()-1);
+ nScanlineStride *= -1;
+ }
+
+ if( !m_aBmpEx.IsTransparent() )
+ {
+ OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
+
+ // can return bitmap data as-is
+ for( long y=aRequestedBytes.Top(); y<aRequestedBytes.Bottom(); ++y )
+ {
+ Scanline pScan = m_pBmpAcc->GetScanline(y);
+ rtl_copyMemory(pOutBuf, pScan+aRequestedBytes.Left(), aRequestedBytes.getWidth());
+ pOutBuf += nScanlineStride;
+ }
+ }
+ else
+ {
+ OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
+ OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access");
+
+ // interleave alpha with bitmap data - note, bitcount is
+ // always integer multiple of 8
+ OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0,
+ "Transparent bitmap bitcount not integer multiple of 8" );
+
+ for( long y=aRequestedArea.Top(); y<aRequestedArea.Bottom(); ++y )
+ {
+ sal_Int8* pOutScan = pOutBuf;
+
+ if( m_nBitsPerInputPixel < 8 )
+ {
+ // input less than a byte - copy via GetPixel()
+ for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
+ {
+ *pOutScan++ = m_pBmpAcc->GetPixel(y,x);
+ *pOutScan++ = m_pAlphaAcc->GetPixel(y,x);
+ }
+ }
+ else
+ {
+ const long nNonAlphaBytes( m_nBitsPerInputPixel/8 );
+ const long nScanlineOffsetLeft(aRequestedArea.Left()*nNonAlphaBytes);
+ Scanline pScan = m_pBmpAcc->GetScanline(y) + nScanlineOffsetLeft;
+
+ // input integer multiple of byte - copy directly
+ for( long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
+ {
+ for( long i=0; i<nNonAlphaBytes; ++i )
+ *pOutScan++ = *pScan++;
+ *pOutScan++ = m_pAlphaAcc->GetPixel(y,x);
+ }
+ }
+
+ pOutBuf += nScanlineStride;
+ }
+ }
+
+ return aRet;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::IntegerBitmapLayout& bitmapLayout,
+ const geometry::IntegerPoint2D& pos ) throw (lang::IndexOutOfBoundsException,
+ rendering::VolatileContentDestroyedException,
+ uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ bitmapLayout = getMemoryLayout();
+
+ // Invalid/empty bitmap: no data available
+ if( !m_pBmpAcc )
+ throw lang::IndexOutOfBoundsException();
+ if( m_aBmpEx.IsTransparent() && !m_pAlphaAcc )
+ throw lang::IndexOutOfBoundsException();
+
+ if( pos.X < 0 || pos.Y < 0 ||
+ pos.X > m_pBmpAcc->Width() || pos.Y > m_pBmpAcc->Height() )
+ {
+ throw lang::IndexOutOfBoundsException();
+ }
+
+ uno::Sequence< sal_Int8 > aRet((m_nBitsPerOutputPixel + 7)/8);
+ sal_Int8* pOutBuf = aRet.getArray();
+
+ // copy stuff to output sequence
+ bitmapLayout.ScanLines = 1;
+ bitmapLayout.ScanLineBytes =
+ bitmapLayout.ScanLineStride= aRet.getLength();
+
+ const long nScanlineLeftOffset( pos.X*m_nBitsPerInputPixel/8 );
+ if( !m_aBmpEx.IsTransparent() )
+ {
+ OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
+
+ // can return bitmap data as-is
+ Scanline pScan = m_pBmpAcc->GetScanline(pos.Y);
+ rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, aRet.getLength() );
+ }
+ else
+ {
+ OSL_ENSURE(m_pBmpAcc,"Invalid bmp read access");
+ OSL_ENSURE(m_pAlphaAcc,"Invalid alpha read access");
+
+ // interleave alpha with bitmap data - note, bitcount is
+ // always integer multiple of 8
+ OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0,
+ "Transparent bitmap bitcount not integer multiple of 8" );
+
+ if( m_nBitsPerInputPixel < 8 )
+ {
+ // input less than a byte - copy via GetPixel()
+ *pOutBuf++ = m_pBmpAcc->GetPixel(pos.Y,pos.X);
+ *pOutBuf = m_pAlphaAcc->GetPixel(pos.Y,pos.X);
+ }
+ else
+ {
+ const long nNonAlphaBytes( m_nBitsPerInputPixel/8 );
+ Scanline pScan = m_pBmpAcc->GetScanline(pos.Y);
+
+ // input integer multiple of byte - copy directly
+ rtl_copyMemory(pOutBuf, pScan+nScanlineLeftOffset, nNonAlphaBytes );
+ pOutBuf += nNonAlphaBytes;
+ *pOutBuf++ = m_pAlphaAcc->GetPixel(pos.Y,pos.X);
+ }
+ }
+
+ return aRet;
+}
+
+uno::Reference< rendering::XBitmapPalette > SAL_CALL VclCanvasBitmap::getPalette() throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ uno::Reference< XBitmapPalette > aRet;
+ if( m_bPalette )
+ aRet.set(this);
+
+ return aRet;
+}
+
+rendering::IntegerBitmapLayout SAL_CALL VclCanvasBitmap::getMemoryLayout() throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ rendering::IntegerBitmapLayout aLayout( m_aLayout );
+
+ // only set references to self on separate copy of
+ // IntegerBitmapLayout - if we'd set that on m_aLayout, we'd have
+ // a circular reference!
+ if( m_bPalette )
+ aLayout.Palette.set( this );
+
+ aLayout.ColorSpace.set( this );
+
+ return aLayout;
+}
+
+sal_Int32 SAL_CALL VclCanvasBitmap::getNumberOfEntries() throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ if( !m_pBmpAcc )
+ return 0;
+
+ return m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ;
+}
+
+sal_Bool SAL_CALL VclCanvasBitmap::getIndex( uno::Sequence< double >& o_entry, sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const USHORT nCount( m_pBmpAcc ?
+ (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
+ OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
+ if( nIndex < 0 || nIndex >= nCount )
+ throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"),
+ static_cast<rendering::XBitmapPalette*>(this));
+
+ const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(sal::static_int_cast<USHORT>(nIndex));
+ o_entry.realloc(3);
+ double* pColor=o_entry.getArray();
+ pColor[0] = aCol.GetRed();
+ pColor[1] = aCol.GetGreen();
+ pColor[2] = aCol.GetBlue();
+
+ return sal_True; // no palette transparency here.
+}
+
+sal_Bool SAL_CALL VclCanvasBitmap::setIndex( const uno::Sequence< double >&, sal_Bool, sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const USHORT nCount( m_pBmpAcc ?
+ (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 );
+
+ OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range");
+ if( nIndex < 0 || nIndex >= nCount )
+ throw lang::IndexOutOfBoundsException(::rtl::OUString::createFromAscii("Palette index out of range"),
+ static_cast<rendering::XBitmapPalette*>(this));
+
+ return sal_False; // read-only implementation
+}
+
+namespace
+{
+ struct PaletteColorSpaceHolder: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>,
+ PaletteColorSpaceHolder>
+ {
+ uno::Reference<rendering::XColorSpace> operator()()
+ {
+ return vcl::unotools::createStandardColorSpace();
+ }
+ };
+}
+
+uno::Reference< rendering::XColorSpace > SAL_CALL VclCanvasBitmap::getColorSpace( ) throw (uno::RuntimeException)
+{
+ // this is the method from XBitmapPalette. Return palette color
+ // space here
+ return PaletteColorSpaceHolder::get();
+}
+
+sal_Int8 SAL_CALL VclCanvasBitmap::getType( ) throw (uno::RuntimeException)
+{
+ return rendering::ColorSpaceType::RGB;
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::getComponentTags( ) throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ return m_aComponentTags;
+}
+
+sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent( ) throw (uno::RuntimeException)
+{
+ return rendering::RenderingIntent::PERCEPTUAL;
+}
+
+uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties( ) throw (uno::RuntimeException)
+{
+ return uno::Sequence< ::beans::PropertyValue >();
+}
+
+uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertColorSpace( const uno::Sequence< double >& deviceColor,
+ const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) throw (uno::RuntimeException)
+{
+ // TODO(P3): if we know anything about target
+ // colorspace, this can be greatly sped up
+ uno::Sequence<rendering::ARGBColor> aIntermediate(
+ convertToARGB(deviceColor));
+ return targetColorSpace->convertFromARGB(aIntermediate);
+}
+
+uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
+ ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
+ "number of channels no multiple of pixel element count",
+ static_cast<rendering::XBitmapPalette*>(this), 01);
+
+ uno::Sequence< rendering::RGBColor > aRes(nLen/nComponentsPerPixel);
+ rendering::RGBColor* pOut( aRes.getArray() );
+
+ if( m_bPalette )
+ {
+ OSL_ENSURE(m_nIndexIndex != -1,
+ "Invalid color channel indices");
+ ENSURE_OR_THROW(m_pBmpAcc,
+ "Unable to get BitmapAccess");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
+ sal::static_int_cast<USHORT>(deviceColor[i+m_nIndexIndex]));
+
+ // TODO(F3): Convert result to sRGB color space
+ *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
+ toDoubleColor(aCol.GetGreen()),
+ toDoubleColor(aCol.GetBlue()));
+ }
+ }
+ else
+ {
+ OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
+ "Invalid color channel indices");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ // TODO(F3): Convert result to sRGB color space
+ *pOut++ = rendering::RGBColor(
+ deviceColor[i+m_nRedIndex],
+ deviceColor[i+m_nGreenIndex],
+ deviceColor[i+m_nBlueIndex]);
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
+ ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
+ "number of channels no multiple of pixel element count",
+ static_cast<rendering::XBitmapPalette*>(this), 01);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+
+ if( m_bPalette )
+ {
+ OSL_ENSURE(m_nIndexIndex != -1,
+ "Invalid color channel indices");
+ ENSURE_OR_THROW(m_pBmpAcc,
+ "Unable to get BitmapAccess");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
+ sal::static_int_cast<USHORT>(deviceColor[i+m_nIndexIndex]));
+
+ // TODO(F3): Convert result to sRGB color space
+ const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
+ *pOut++ = rendering::ARGBColor(nAlpha,
+ toDoubleColor(aCol.GetRed()),
+ toDoubleColor(aCol.GetGreen()),
+ toDoubleColor(aCol.GetBlue()));
+ }
+ }
+ else
+ {
+ OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
+ "Invalid color channel indices");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ // TODO(F3): Convert result to sRGB color space
+ const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
+ *pOut++ = rendering::ARGBColor(
+ nAlpha,
+ deviceColor[i+m_nRedIndex],
+ deviceColor[i+m_nGreenIndex],
+ deviceColor[i+m_nBlueIndex]);
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
+ ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
+ "number of channels no multiple of pixel element count",
+ static_cast<rendering::XBitmapPalette*>(this), 01);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+
+ if( m_bPalette )
+ {
+ OSL_ENSURE(m_nIndexIndex != -1,
+ "Invalid color channel indices");
+ ENSURE_OR_THROW(m_pBmpAcc,
+ "Unable to get BitmapAccess");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
+ sal::static_int_cast<USHORT>(deviceColor[i+m_nIndexIndex]));
+
+ // TODO(F3): Convert result to sRGB color space
+ const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
+ *pOut++ = rendering::ARGBColor(nAlpha,
+ nAlpha*toDoubleColor(aCol.GetRed()),
+ nAlpha*toDoubleColor(aCol.GetGreen()),
+ nAlpha*toDoubleColor(aCol.GetBlue()));
+ }
+ }
+ else
+ {
+ OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
+ "Invalid color channel indices");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ // TODO(F3): Convert result to sRGB color space
+ const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
+ *pOut++ = rendering::ARGBColor(
+ nAlpha,
+ nAlpha*deviceColor[i+m_nRedIndex],
+ nAlpha*deviceColor[i+m_nGreenIndex],
+ nAlpha*deviceColor[i+m_nBlueIndex]);
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( rgbColor.getLength() );
+ const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
+
+ uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
+ double* pColors=aRes.getArray();
+
+ if( m_bPalette )
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
+ BitmapColor(toByteColor(rgbColor[i].Red),
+ toByteColor(rgbColor[i].Green),
+ toByteColor(rgbColor[i].Blue)));
+ if( m_nAlphaIndex != -1 )
+ pColors[m_nAlphaIndex] = 1.0;
+
+ pColors += nComponentsPerPixel;
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ pColors[m_nRedIndex] = rgbColor[i].Red;
+ pColors[m_nGreenIndex] = rgbColor[i].Green;
+ pColors[m_nBlueIndex] = rgbColor[i].Blue;
+ if( m_nAlphaIndex != -1 )
+ pColors[m_nAlphaIndex] = 1.0;
+
+ pColors += nComponentsPerPixel;
+ }
+ }
+ return aRes;
+}
+
+uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( rgbColor.getLength() );
+ const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
+
+ uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
+ double* pColors=aRes.getArray();
+
+ if( m_bPalette )
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
+ BitmapColor(toByteColor(rgbColor[i].Red),
+ toByteColor(rgbColor[i].Green),
+ toByteColor(rgbColor[i].Blue)));
+ if( m_nAlphaIndex != -1 )
+ pColors[m_nAlphaIndex] = rgbColor[i].Alpha;
+
+ pColors += nComponentsPerPixel;
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ pColors[m_nRedIndex] = rgbColor[i].Red;
+ pColors[m_nGreenIndex] = rgbColor[i].Green;
+ pColors[m_nBlueIndex] = rgbColor[i].Blue;
+ if( m_nAlphaIndex != -1 )
+ pColors[m_nAlphaIndex] = rgbColor[i].Alpha;
+
+ pColors += nComponentsPerPixel;
+ }
+ }
+ return aRes;
+}
+
+uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( rgbColor.getLength() );
+ const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
+
+ uno::Sequence< double > aRes(nLen*nComponentsPerPixel);
+ double* pColors=aRes.getArray();
+
+ if( m_bPalette )
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const double nAlpha( rgbColor[i].Alpha );
+ pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex(
+ BitmapColor(toByteColor(rgbColor[i].Red / nAlpha),
+ toByteColor(rgbColor[i].Green / nAlpha),
+ toByteColor(rgbColor[i].Blue / nAlpha)));
+ if( m_nAlphaIndex != -1 )
+ pColors[m_nAlphaIndex] = nAlpha;
+
+ pColors += nComponentsPerPixel;
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const double nAlpha( rgbColor[i].Alpha );
+ pColors[m_nRedIndex] = rgbColor[i].Red / nAlpha;
+ pColors[m_nGreenIndex] = rgbColor[i].Green / nAlpha;
+ pColors[m_nBlueIndex] = rgbColor[i].Blue / nAlpha;
+ if( m_nAlphaIndex != -1 )
+ pColors[m_nAlphaIndex] = nAlpha;
+
+ pColors += nComponentsPerPixel;
+ }
+ }
+ return aRes;
+}
+
+sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel( ) throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ return m_nBitsPerOutputPixel;
+}
+
+uno::Sequence< ::sal_Int32 > SAL_CALL VclCanvasBitmap::getComponentBitCounts( ) throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ return m_aComponentBitCounts;
+}
+
+sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness( ) throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+ return m_nEndianness;
+}
+
+uno::Sequence<double> SAL_CALL VclCanvasBitmap::convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
+ const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
+ {
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength());
+ ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0,
+ "number of channels no multiple of pixel element count",
+ static_cast<rendering::XBitmapPalette*>(this), 01);
+
+ uno::Sequence<double> aRes(nLen);
+ double* pOut( aRes.getArray() );
+
+ if( m_bPalette )
+ {
+ OSL_ENSURE(m_nIndexIndex != -1,
+ "Invalid color channel indices");
+ ENSURE_OR_THROW(m_pBmpAcc,
+ "Unable to get BitmapAccess");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(
+ sal::static_int_cast<USHORT>(deviceColor[i+m_nIndexIndex]));
+
+ // TODO(F3): Convert result to sRGB color space
+ const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
+ *pOut++ = toDoubleColor(aCol.GetRed());
+ *pOut++ = toDoubleColor(aCol.GetGreen());
+ *pOut++ = toDoubleColor(aCol.GetBlue());
+ *pOut++ = nAlpha;
+ }
+ }
+ else
+ {
+ OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1,
+ "Invalid color channel indices");
+
+ for( sal_Size i=0; i<nLen; i+=nComponentsPerPixel )
+ {
+ // TODO(F3): Convert result to sRGB color space
+ const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 );
+ *pOut++ = deviceColor[i+m_nRedIndex];
+ *pOut++ = deviceColor[i+m_nGreenIndex];
+ *pOut++ = deviceColor[i+m_nBlueIndex];
+ *pOut++ = nAlpha;
+ }
+ }
+
+ return aRes;
+ }
+ else
+ {
+ // TODO(P3): if we know anything about target
+ // colorspace, this can be greatly sped up
+ uno::Sequence<rendering::ARGBColor> aIntermediate(
+ convertIntegerToARGB(deviceColor));
+ return targetColorSpace->convertFromARGB(aIntermediate);
+ }
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
+ const uno::Reference< ::rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) )
+ {
+ // it's us, so simply pass-through the data
+ return deviceColor;
+ }
+ else
+ {
+ // TODO(P3): if we know anything about target
+ // colorspace, this can be greatly sped up
+ uno::Sequence<rendering::ARGBColor> aIntermediate(
+ convertIntegerToARGB(deviceColor));
+ return targetColorSpace->convertIntegerFromARGB(aIntermediate);
+ }
+}
+
+uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const BYTE* pIn( reinterpret_cast<const BYTE*>(deviceColor.getConstArray()) );
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
+
+ uno::Sequence< rendering::RGBColor > aRes(nNumColors);
+ rendering::RGBColor* pOut( aRes.getArray() );
+
+ ENSURE_OR_THROW(m_pBmpAcc,
+ "Unable to get BitmapAccess");
+
+ if( m_aBmpEx.IsTransparent() )
+ {
+ const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
+ for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
+ {
+ // if palette, index is guaranteed to be 8 bit
+ const BitmapColor aCol =
+ m_bPalette ?
+ m_pBmpAcc->GetPaletteColor(*pIn) :
+ m_pBmpAcc->GetPixelFromData(pIn,0);
+
+ // TODO(F3): Convert result to sRGB color space
+ *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
+ toDoubleColor(aCol.GetGreen()),
+ toDoubleColor(aCol.GetBlue()));
+ // skips alpha
+ pIn += nBytesPerPixel;
+ }
+ }
+ else
+ {
+ for( sal_Int32 i=0; i<nNumColors; ++i )
+ {
+ const BitmapColor aCol =
+ m_bPalette ?
+ m_pBmpAcc->GetPaletteColor(
+ sal::static_int_cast<USHORT>(
+ m_pBmpAcc->GetPixelFromData(
+ pIn, i ))) :
+ m_pBmpAcc->GetPixelFromData(pIn, i);
+
+ // TODO(F3): Convert result to sRGB color space
+ *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()),
+ toDoubleColor(aCol.GetGreen()),
+ toDoubleColor(aCol.GetBlue()));
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const BYTE* pIn( reinterpret_cast<const BYTE*>(deviceColor.getConstArray()) );
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+
+ ENSURE_OR_THROW(m_pBmpAcc,
+ "Unable to get BitmapAccess");
+
+ if( m_aBmpEx.IsTransparent() )
+ {
+ const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
+ const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
+ const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
+ for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
+ {
+ // if palette, index is guaranteed to be 8 bit
+ const BitmapColor aCol =
+ m_bPalette ?
+ m_pBmpAcc->GetPaletteColor(*pIn) :
+ m_pBmpAcc->GetPixelFromData(pIn,0);
+
+ // TODO(F3): Convert result to sRGB color space
+ *pOut++ = rendering::ARGBColor(1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]),
+ toDoubleColor(aCol.GetRed()),
+ toDoubleColor(aCol.GetGreen()),
+ toDoubleColor(aCol.GetBlue()));
+ pIn += nBytesPerPixel;
+ }
+ }
+ else
+ {
+ for( sal_Int32 i=0; i<nNumColors; ++i )
+ {
+ const BitmapColor aCol =
+ m_bPalette ?
+ m_pBmpAcc->GetPaletteColor(
+ sal::static_int_cast<USHORT>(
+ m_pBmpAcc->GetPixelFromData(
+ pIn, i ))) :
+ m_pBmpAcc->GetPixelFromData(pIn, i);
+
+ // TODO(F3): Convert result to sRGB color space
+ *pOut++ = rendering::ARGBColor(1.0,
+ toDoubleColor(aCol.GetRed()),
+ toDoubleColor(aCol.GetGreen()),
+ toDoubleColor(aCol.GetBlue()));
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const BYTE* pIn( reinterpret_cast<const BYTE*>(deviceColor.getConstArray()) );
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nNumColors);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+
+ ENSURE_OR_THROW(m_pBmpAcc,
+ "Unable to get BitmapAccess");
+
+ if( m_aBmpEx.IsTransparent() )
+ {
+ const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
+ const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8);
+ const sal_uInt8 nAlphaFactor( m_aBmpEx.IsAlpha() ? 1 : 255 );
+ for( sal_Size i=0; i<nLen; i+=nBytesPerPixel )
+ {
+ // if palette, index is guaranteed to be 8 bit
+ const BitmapColor aCol =
+ m_bPalette ?
+ m_pBmpAcc->GetPaletteColor(*pIn) :
+ m_pBmpAcc->GetPixelFromData(pIn,0);
+
+ // TODO(F3): Convert result to sRGB color space
+ const double nAlpha( 1.0 - toDoubleColor(nAlphaFactor*pIn[nNonAlphaBytes]) );
+ *pOut++ = rendering::ARGBColor(nAlpha,
+ nAlpha*toDoubleColor(aCol.GetRed()),
+ nAlpha*toDoubleColor(aCol.GetGreen()),
+ nAlpha*toDoubleColor(aCol.GetBlue()));
+ pIn += nBytesPerPixel;
+ }
+ }
+ else
+ {
+ for( sal_Int32 i=0; i<nNumColors; ++i )
+ {
+ const BitmapColor aCol =
+ m_bPalette ?
+ m_pBmpAcc->GetPaletteColor(
+ sal::static_int_cast<USHORT>(
+ m_pBmpAcc->GetPixelFromData(
+ pIn, i ))) :
+ m_pBmpAcc->GetPixelFromData(pIn, i);
+
+ // TODO(F3): Convert result to sRGB color space
+ *pOut++ = rendering::ARGBColor(1.0,
+ toDoubleColor(aCol.GetRed()),
+ toDoubleColor(aCol.GetGreen()),
+ toDoubleColor(aCol.GetBlue()));
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( rgbColor.getLength() );
+ const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
+
+ uno::Sequence< sal_Int8 > aRes(nNumBytes);
+ BYTE* pColors=reinterpret_cast<BYTE*>(aRes.getArray());
+
+ if( m_aBmpEx.IsTransparent() )
+ {
+ const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const BitmapColor aCol(toByteColor(rgbColor[i].Red),
+ toByteColor(rgbColor[i].Green),
+ toByteColor(rgbColor[i].Blue));
+ const BitmapColor aCol2 =
+ m_bPalette ?
+ BitmapColor(
+ sal::static_int_cast<BYTE>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
+ aCol;
+
+ m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
+ pColors += nNonAlphaBytes;
+ *pColors++ = BYTE(255);
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const BitmapColor aCol(toByteColor(rgbColor[i].Red),
+ toByteColor(rgbColor[i].Green),
+ toByteColor(rgbColor[i].Blue));
+ const BitmapColor aCol2 =
+ m_bPalette ?
+ BitmapColor(
+ sal::static_int_cast<BYTE>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
+ aCol;
+
+ m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( rgbColor.getLength() );
+ const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
+
+ uno::Sequence< sal_Int8 > aRes(nNumBytes);
+ BYTE* pColors=reinterpret_cast<BYTE*>(aRes.getArray());
+
+ if( m_aBmpEx.IsTransparent() )
+ {
+ const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const BitmapColor aCol(toByteColor(rgbColor[i].Red),
+ toByteColor(rgbColor[i].Green),
+ toByteColor(rgbColor[i].Blue));
+ const BitmapColor aCol2 =
+ m_bPalette ?
+ BitmapColor(
+ sal::static_int_cast<BYTE>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
+ aCol;
+
+ m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
+ pColors += nNonAlphaBytes;
+ *pColors++ = 255 - toByteColor(rgbColor[i].Alpha);
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const BitmapColor aCol(toByteColor(rgbColor[i].Red),
+ toByteColor(rgbColor[i].Green),
+ toByteColor(rgbColor[i].Blue));
+ const BitmapColor aCol2 =
+ m_bPalette ?
+ BitmapColor(
+ sal::static_int_cast<BYTE>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
+ aCol;
+
+ m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
+ }
+ }
+
+ return aRes;
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) throw (lang::IllegalArgumentException,uno::RuntimeException)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ const sal_Size nLen( rgbColor.getLength() );
+ const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8);
+
+ uno::Sequence< sal_Int8 > aRes(nNumBytes);
+ BYTE* pColors=reinterpret_cast<BYTE*>(aRes.getArray());
+
+ if( m_aBmpEx.IsTransparent() )
+ {
+ const long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 );
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const double nAlpha( rgbColor[i].Alpha );
+ const BitmapColor aCol(toByteColor(rgbColor[i].Red / nAlpha),
+ toByteColor(rgbColor[i].Green / nAlpha),
+ toByteColor(rgbColor[i].Blue / nAlpha));
+ const BitmapColor aCol2 =
+ m_bPalette ?
+ BitmapColor(
+ sal::static_int_cast<BYTE>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
+ aCol;
+
+ m_pBmpAcc->SetPixelOnData(pColors,0,aCol2);
+ pColors += nNonAlphaBytes;
+ *pColors++ = 255 - toByteColor(nAlpha);
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ const BitmapColor aCol(toByteColor(rgbColor[i].Red),
+ toByteColor(rgbColor[i].Green),
+ toByteColor(rgbColor[i].Blue));
+ const BitmapColor aCol2 =
+ m_bPalette ?
+ BitmapColor(
+ sal::static_int_cast<BYTE>(m_pBmpAcc->GetBestPaletteIndex( aCol ))) :
+ aCol;
+
+ m_pBmpAcc->SetPixelOnData(pColors,i,aCol2);
+ }
+ }
+
+ return aRes;
+}
+
+BitmapEx VclCanvasBitmap::getBitmapEx() const
+{
+ return m_aBmpEx;
+}
diff --git a/vcl/source/helper/canvastools.cxx b/vcl/source/helper/canvastools.cxx
new file mode 100644
index 000000000000..71c306ff9bbb
--- /dev/null
+++ b/vcl/source/helper/canvastools.cxx
@@ -0,0 +1,837 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <rtl/logfile.hxx>
+#include <cppuhelper/compbase1.hxx>
+
+#include <com/sun/star/geometry/RealSize2D.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/geometry/RealRectangle2D.hpp>
+#include <com/sun/star/geometry/IntegerSize2D.hpp>
+#include <com/sun/star/geometry/IntegerPoint2D.hpp>
+#include <com/sun/star/geometry/IntegerRectangle2D.hpp>
+#include <com/sun/star/geometry/RealBezierSegment2D.hpp>
+
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/rendering/RenderingIntent.hpp>
+#include <com/sun/star/rendering/XGraphicDevice.hpp>
+#include <com/sun/star/rendering/XBitmap.hpp>
+#include <com/sun/star/rendering/XPolyPolygon2D.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/vector/b2isize.hxx>
+#include <basegfx/point/b2ipoint.hxx>
+#include <basegfx/range/b2irectangle.hxx>
+
+// #i79917#
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+#include <tools/poly.hxx>
+#include <tools/diagnose_ex.h>
+#include <rtl/uuid.h>
+
+#include <vcl/salbtype.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/bitmapex.hxx>
+
+#include <vcl/canvasbitmap.hxx>
+#include <vcl/canvastools.hxx>
+#include <hash_map>
+
+
+using namespace ::com::sun::star;
+
+namespace vcl
+{
+ namespace unotools
+ {
+ // #i79917# removed helpers bezierSequenceFromPolygon and
+ // pointSequenceFromPolygon here
+ // Also all helpers using tools Polygon and PolyPolygon will get mapped to the
+ // B2DPolygon helpers for these cases, see comments with the same TaskID below.
+ // TODO: Remove those wrapped methods
+
+ //---------------------------------------------------------------------------------------
+
+ uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice,
+ const ::Polygon& inputPolygon )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xPolyPolygonFromPolygon()" );
+
+ // #i79917# map to basegfx
+ const basegfx::B2DPolygon aB2DPolygon(inputPolygon.getB2DPolygon());
+ return basegfx::unotools::xPolyPolygonFromB2DPolygon(xGraphicDevice, aB2DPolygon);
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice,
+ const ::PolyPolygon& inputPolyPolygon )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xPolyPolygonFromPolyPolygon()" );
+
+ // #i79917# map to basegfx
+ const basegfx::B2DPolyPolygon aB2DPolyPolygon(inputPolyPolygon.getB2DPolyPolygon());
+ return basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(xGraphicDevice, aB2DPolyPolygon);
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ ::Polygon polygonFromPoint2DSequence( const uno::Sequence< geometry::RealPoint2D >& points )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::polygonFromPoint2DSequence()" );
+
+ const USHORT nCurrSize( sal::static_int_cast<USHORT>(points.getLength()) );
+
+ ::Polygon aPoly( nCurrSize );
+
+ USHORT nCurrPoint;
+ for( nCurrPoint=0; nCurrPoint<nCurrSize; ++nCurrPoint )
+ aPoly[nCurrPoint] = pointFromRealPoint2D( points[nCurrPoint] );
+
+ return aPoly;
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ ::PolyPolygon polyPolygonFromPoint2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::polyPolygonFromPoint2DSequenceSequence()" );
+
+ ::PolyPolygon aRes;
+
+ int nCurrPoly;
+ for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly )
+ {
+ aRes.Insert( polygonFromPoint2DSequence( points[nCurrPoly] ) );
+ }
+
+ return aRes;
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ ::Polygon polygonFromBezier2DSequence( const uno::Sequence< geometry::RealBezierSegment2D >& curves )
+ {
+ // #i79917# map to basegfx
+ const basegfx::B2DPolygon aB2DPolygon(basegfx::unotools::polygonFromBezier2DSequence(curves));
+ return ::Polygon(aB2DPolygon);
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ ::PolyPolygon polyPolygonFromBezier2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& curves )
+ {
+ // #i79917# map to basegfx
+ const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::unotools::polyPolygonFromBezier2DSequenceSequence(curves));
+ return ::PolyPolygon(aB2DPolyPolygon);
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ uno::Reference< rendering::XBitmap > xBitmapFromBitmap( const uno::Reference< rendering::XGraphicDevice >& /*xGraphicDevice*/,
+ const ::Bitmap& inputBitmap )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xBitmapFromBitmap()" );
+
+ return new vcl::unotools::VclCanvasBitmap( BitmapEx( inputBitmap ) );
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ uno::Reference< rendering::XBitmap > xBitmapFromBitmapEx( const uno::Reference< rendering::XGraphicDevice >& /*xGraphicDevice*/,
+ const ::BitmapEx& inputBitmap )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xBitmapFromBitmapEx()" );
+
+ return new vcl::unotools::VclCanvasBitmap( inputBitmap );
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ const uno::Sequence< sal_Int8 > getTunnelIdentifier( TunnelIdentifierType eType )
+ {
+ static std::hash_map< int, uno::Sequence< sal_Int8 > > aIds;
+ std::hash_map< int, uno::Sequence< sal_Int8 > >::iterator it =
+ aIds.find( eType );
+ if( it == aIds.end() )
+ {
+ uno::Sequence< sal_Int8 > aNewId( 16 );
+ rtl_createUuid( (sal_uInt8*)aNewId.getArray(), NULL, sal_True );
+ aIds[ eType ] = aNewId;
+ it = aIds.find( eType );
+ }
+ return it->second;
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ namespace
+ {
+ inline bool operator==( const rendering::IntegerBitmapLayout& rLHS,
+ const rendering::IntegerBitmapLayout& rRHS )
+ {
+ return
+ rLHS.ScanLineBytes == rRHS.ScanLineBytes &&
+ rLHS.ScanLineStride == rRHS.ScanLineStride &&
+ rLHS.PlaneStride == rRHS.PlaneStride &&
+ rLHS.ColorSpace == rRHS.ColorSpace &&
+ rLHS.Palette == rRHS.Palette &&
+ rLHS.IsMsbFirst == rRHS.IsMsbFirst;
+ }
+
+ bool readBmp( sal_Int32 nWidth,
+ sal_Int32 nHeight,
+ const rendering::IntegerBitmapLayout& rLayout,
+ const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap,
+ ScopedBitmapWriteAccess& rWriteAcc,
+ ScopedBitmapWriteAccess& rAlphaAcc )
+ {
+ rendering::IntegerBitmapLayout aCurrLayout;
+ geometry::IntegerRectangle2D aRect;
+ uno::Sequence<sal_Int8> aPixelData;
+ uno::Sequence<rendering::RGBColor> aRGBColors;
+ uno::Sequence<rendering::ARGBColor> aARGBColors;
+
+ for( aRect.Y1=0; aRect.Y1<nHeight; ++aRect.Y1 )
+ {
+ aRect.X1 = 0; aRect.X2 = nWidth; aRect.Y2 = aRect.Y1+1;
+ try
+ {
+ aPixelData = xInputBitmap->getData(aCurrLayout,aRect);
+ }
+ catch( rendering::VolatileContentDestroyedException& )
+ {
+ // re-read bmp from the start
+ return false;
+ }
+ if( !(aCurrLayout == rLayout) )
+ return false; // re-read bmp from the start
+
+ if( rAlphaAcc.get() )
+ {
+ // read ARGB color
+ aARGBColors = rLayout.ColorSpace->convertIntegerToARGB(aPixelData);
+
+ if( rWriteAcc->HasPalette() )
+ {
+ for( sal_Int32 x=0; x<nWidth; ++x )
+ {
+ const rendering::ARGBColor& rColor=aARGBColors[x];
+ rWriteAcc->SetPixel( aRect.Y1, x,
+ (BYTE)rWriteAcc->GetBestPaletteIndex(
+ BitmapColor( toByteColor(rColor.Red),
+ toByteColor(rColor.Green),
+ toByteColor(rColor.Blue))) );
+ rAlphaAcc->SetPixel( aRect.Y1, x,
+ BitmapColor( 255 - toByteColor(rColor.Alpha) ));
+ }
+ }
+ else
+ {
+ for( sal_Int32 x=0; x<nWidth; ++x )
+ {
+ const rendering::ARGBColor& rColor=aARGBColors[x];
+ rWriteAcc->SetPixel( aRect.Y1, x,
+ BitmapColor( toByteColor(rColor.Red),
+ toByteColor(rColor.Green),
+ toByteColor(rColor.Blue) ));
+ rAlphaAcc->SetPixel( aRect.Y1, x,
+ BitmapColor( 255 - toByteColor(rColor.Alpha) ));
+ }
+ }
+ }
+ else
+ {
+ // read RGB color
+ aRGBColors = rLayout.ColorSpace->convertIntegerToRGB(aPixelData);
+ if( rWriteAcc->HasPalette() )
+ {
+ for( sal_Int32 x=0; x<nWidth; ++x )
+ {
+ const rendering::RGBColor& rColor=aRGBColors[x];
+ rWriteAcc->SetPixel( aRect.Y1, x,
+ (BYTE)rWriteAcc->GetBestPaletteIndex(
+ BitmapColor( toByteColor(rColor.Red),
+ toByteColor(rColor.Green),
+ toByteColor(rColor.Blue))) );
+ }
+ }
+ else
+ {
+ for( sal_Int32 x=0; x<nWidth; ++x )
+ {
+ const rendering::RGBColor& rColor=aRGBColors[x];
+ rWriteAcc->SetPixel( aRect.Y1, x,
+ BitmapColor( toByteColor(rColor.Red),
+ toByteColor(rColor.Green),
+ toByteColor(rColor.Blue) ));
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+
+ ::BitmapEx VCL_DLLPUBLIC bitmapExFromXBitmap( const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::bitmapExFromXBitmap()" );
+
+ if( !xInputBitmap.is() )
+ return ::BitmapEx();
+
+ // tunnel directly for known implementation
+ // ----------------------------------------------------------------
+ VclCanvasBitmap* pImplBitmap = dynamic_cast<VclCanvasBitmap*>(xInputBitmap.get());
+ if( pImplBitmap )
+ return pImplBitmap->getBitmapEx();
+
+ // retrieve data via UNO interface
+ // ----------------------------------------------------------------
+
+ // volatile bitmaps are a bit more complicated to read
+ // from..
+ uno::Reference<rendering::XVolatileBitmap> xVolatileBitmap(
+ xInputBitmap, uno::UNO_QUERY);
+
+ // loop a few times, until successfully read (for XVolatileBitmap)
+ for( int i=0; i<10; ++i )
+ {
+ sal_Int32 nDepth=0;
+ sal_Int32 nAlphaDepth=0;
+ const rendering::IntegerBitmapLayout aLayout(
+ xInputBitmap->getMemoryLayout());
+
+ OSL_ENSURE(aLayout.ColorSpace.is(),
+ "Cannot convert image without color space!");
+ if( !aLayout.ColorSpace.is() )
+ return ::BitmapEx();
+
+ nDepth = aLayout.ColorSpace->getBitsPerPixel();
+
+ if( xInputBitmap->hasAlpha() )
+ {
+ // determine alpha channel depth
+ const uno::Sequence<sal_Int8> aTags(
+ aLayout.ColorSpace->getComponentTags() );
+ const uno::Sequence<sal_Int32> aDepths(
+ aLayout.ColorSpace->getComponentBitCounts() );
+ const sal_Int8* pStart(aTags.getConstArray());
+ const sal_Size nLen(aTags.getLength());
+ const sal_Int8* pEnd(pStart+nLen);
+
+ const std::ptrdiff_t nAlphaIndex =
+ std::find(pStart,pEnd,
+ rendering::ColorComponentTag::ALPHA) - pStart;
+
+ if( nAlphaIndex < sal::static_int_cast<std::ptrdiff_t>(nLen) )
+ {
+ nAlphaDepth = aLayout.ColorSpace->getComponentBitCounts()[nAlphaIndex] > 1 ? 8 : 1;
+ nDepth -= nAlphaDepth;
+ }
+ }
+
+ BitmapPalette aPalette;
+ if( aLayout.Palette.is() )
+ {
+ uno::Reference< rendering::XColorSpace > xPaletteColorSpace(
+ aLayout.Palette->getColorSpace());
+ ENSURE_OR_THROW(xPaletteColorSpace.is(),
+ "Palette without color space");
+
+ const sal_Int32 nEntryCount( aLayout.Palette->getNumberOfEntries() );
+ if( nEntryCount <= 256 )
+ {
+ if( nEntryCount <= 2 )
+ nDepth = 1;
+ else
+ nDepth = 8;
+
+ const USHORT nPaletteEntries(
+ sal::static_int_cast<USHORT>(
+ std::min(sal_Int32(255), nEntryCount)));
+
+ // copy palette entries
+ aPalette.SetEntryCount(nPaletteEntries);
+ uno::Reference<rendering::XBitmapPalette> xPalette( aLayout.Palette );
+ uno::Reference<rendering::XColorSpace> xPalColorSpace( xPalette->getColorSpace() );
+
+ uno::Sequence<double> aPaletteEntry;
+ for( USHORT j=0; j<nPaletteEntries; ++j )
+ {
+ if( !xPalette->getIndex(aPaletteEntry,j) &&
+ nAlphaDepth == 0 )
+ {
+ nAlphaDepth = 1;
+ }
+ uno::Sequence<rendering::RGBColor> aColors=xPalColorSpace->convertToRGB(aPaletteEntry);
+ ENSURE_OR_THROW(aColors.getLength() == 1,
+ "Palette returned more or less than one entry");
+ const rendering::RGBColor& rColor=aColors[0];
+ aPalette[j] = BitmapColor(toByteColor(rColor.Red),
+ toByteColor(rColor.Green),
+ toByteColor(rColor.Blue));
+ }
+ }
+ }
+
+ const ::Size aPixelSize(
+ sizeFromIntegerSize2D(xInputBitmap->getSize()));
+
+ // normalize bitcount
+ nDepth =
+ ( nDepth <= 1 ) ? 1 :
+ ( nDepth <= 4 ) ? 4 :
+ ( nDepth <= 8 ) ? 8 : 24;
+
+ ::Bitmap aBitmap( aPixelSize,
+ sal::static_int_cast<USHORT>(nDepth),
+ aLayout.Palette.is() ? &aPalette : NULL );
+ ::Bitmap aAlpha;
+ if( nAlphaDepth )
+ aAlpha = ::Bitmap( aPixelSize,
+ sal::static_int_cast<USHORT>(nAlphaDepth),
+ &::Bitmap::GetGreyPalette(
+ sal::static_int_cast<USHORT>(1L << nAlphaDepth)) );
+
+ { // limit scoped access
+ ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(),
+ aBitmap );
+ ScopedBitmapWriteAccess pAlphaWriteAccess( nAlphaDepth ? aAlpha.AcquireWriteAccess() : NULL,
+ aAlpha );
+
+ ENSURE_OR_THROW(pWriteAccess.get() != NULL,
+ "Cannot get write access to bitmap");
+
+ const sal_Int32 nWidth(aPixelSize.Width());
+ const sal_Int32 nHeight(aPixelSize.Height());
+
+ if( !readBmp(nWidth,nHeight,aLayout,xInputBitmap,
+ pWriteAccess,pAlphaWriteAccess) )
+ continue;
+ } // limit scoped access
+
+ if( nAlphaDepth )
+ return ::BitmapEx( aBitmap,
+ AlphaMask( aAlpha ) );
+ else
+ return ::BitmapEx( aBitmap );
+ }
+
+ // failed to read data 10 times - bail out
+ return ::BitmapEx();
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ geometry::RealSize2D size2DFromSize( const Size& rSize )
+ {
+ return geometry::RealSize2D( rSize.Width(),
+ rSize.Height() );
+ }
+
+ geometry::RealPoint2D point2DFromPoint( const Point& rPoint )
+ {
+ return geometry::RealPoint2D( rPoint.X(),
+ rPoint.Y() );
+ }
+
+ geometry::RealRectangle2D rectangle2DFromRectangle( const Rectangle& rRect )
+ {
+ return geometry::RealRectangle2D( rRect.Left(), rRect.Top(),
+ rRect.Right(), rRect.Bottom() );
+ }
+
+ Size sizeFromRealSize2D( const geometry::RealSize2D& rSize )
+ {
+ return Size( static_cast<long>(rSize.Width + .5),
+ static_cast<long>(rSize.Height + .5) );
+ }
+
+ Point pointFromRealPoint2D( const geometry::RealPoint2D& rPoint )
+ {
+ return Point( static_cast<long>(rPoint.X + .5),
+ static_cast<long>(rPoint.Y + .5) );
+ }
+
+ Rectangle rectangleFromRealRectangle2D( const geometry::RealRectangle2D& rRect )
+ {
+ return Rectangle( static_cast<long>(rRect.X1 + .5),
+ static_cast<long>(rRect.Y1 + .5),
+ static_cast<long>(rRect.X2 + .5),
+ static_cast<long>(rRect.Y2 + .5) );
+ }
+
+ ::Size sizeFromB2DSize( const ::basegfx::B2DVector& rVec )
+ {
+ return ::Size( FRound( rVec.getX() ),
+ FRound( rVec.getY() ) );
+ }
+
+ ::Point pointFromB2DPoint( const ::basegfx::B2DPoint& rPoint )
+ {
+ return ::Point( FRound( rPoint.getX() ),
+ FRound( rPoint.getY() ) );
+ }
+
+ ::Rectangle rectangleFromB2DRectangle( const ::basegfx::B2DRange& rRect )
+ {
+ return ::Rectangle( FRound( rRect.getMinX() ),
+ FRound( rRect.getMinY() ),
+ FRound( rRect.getMaxX() ),
+ FRound( rRect.getMaxY() ) );
+ }
+
+ Size sizeFromB2ISize( const ::basegfx::B2IVector& rVec )
+ {
+ return ::Size( rVec.getX(),
+ rVec.getY() );
+ }
+
+ Point pointFromB2IPoint( const ::basegfx::B2IPoint& rPoint )
+ {
+ return ::Point( rPoint.getX(),
+ rPoint.getY() );
+ }
+
+ Rectangle rectangleFromB2IRectangle( const ::basegfx::B2IRange& rRect )
+ {
+ return ::Rectangle( rRect.getMinX(),
+ rRect.getMinY(),
+ rRect.getMaxX(),
+ rRect.getMaxY() );
+ }
+
+ ::basegfx::B2DVector b2DSizeFromSize( const ::Size& rSize )
+ {
+ return ::basegfx::B2DVector( rSize.Width(),
+ rSize.Height() );
+ }
+
+ ::basegfx::B2DPoint b2DPointFromPoint( const ::Point& rPoint )
+ {
+ return ::basegfx::B2DPoint( rPoint.X(),
+ rPoint.Y() );
+ }
+
+ ::basegfx::B2DRange b2DRectangleFromRectangle( const ::Rectangle& rRect )
+ {
+ return ::basegfx::B2DRange( rRect.Left(),
+ rRect.Top(),
+ rRect.Right(),
+ rRect.Bottom() );
+ }
+
+ basegfx::B2IVector b2ISizeFromSize( const Size& rSize )
+ {
+ return ::basegfx::B2IVector( rSize.Width(),
+ rSize.Height() );
+ }
+
+ basegfx::B2IPoint b2IPointFromPoint( const Point& rPoint )
+ {
+ return ::basegfx::B2IPoint( rPoint.X(),
+ rPoint.Y() );
+ }
+
+ basegfx::B2IRange b2IRectangleFromRectangle( const Rectangle& rRect )
+ {
+ return ::basegfx::B2IRange( rRect.Left(),
+ rRect.Top(),
+ rRect.Right(),
+ rRect.Bottom() );
+ }
+
+ geometry::IntegerSize2D integerSize2DFromSize( const Size& rSize )
+ {
+ return geometry::IntegerSize2D( rSize.Width(),
+ rSize.Height() );
+ }
+
+ geometry::IntegerPoint2D integerPoint2DFromPoint( const Point& rPoint )
+ {
+ return geometry::IntegerPoint2D( rPoint.X(),
+ rPoint.Y() );
+ }
+
+ geometry::IntegerRectangle2D integerRectangle2DFromRectangle( const Rectangle& rRectangle )
+ {
+ return geometry::IntegerRectangle2D( rRectangle.Left(), rRectangle.Top(),
+ rRectangle.Right(), rRectangle.Bottom() );
+ }
+
+ Size sizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize )
+ {
+ return Size( rSize.Width,
+ rSize.Height );
+ }
+
+ Point pointFromIntegerPoint2D( const geometry::IntegerPoint2D& rPoint )
+ {
+ return Point( rPoint.X,
+ rPoint.Y );
+ }
+
+ Rectangle rectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle )
+ {
+ return Rectangle( rRectangle.X1, rRectangle.Y1,
+ rRectangle.X2, rRectangle.Y2 );
+ }
+
+ namespace
+ {
+ class StandardColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XColorSpace >
+ {
+ private:
+ uno::Sequence< sal_Int8 > m_aComponentTags;
+
+ virtual ::sal_Int8 SAL_CALL getType( ) throw (uno::RuntimeException)
+ {
+ return rendering::ColorSpaceType::RGB;
+ }
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) throw (uno::RuntimeException)
+ {
+ return m_aComponentTags;
+ }
+ virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException)
+ {
+ return rendering::RenderingIntent::PERCEPTUAL;
+ }
+ virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException)
+ {
+ return uno::Sequence< beans::PropertyValue >();
+ }
+ virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
+ const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ // TODO(P3): if we know anything about target
+ // colorspace, this can be greatly sped up
+ uno::Sequence<rendering::ARGBColor> aIntermediate(
+ convertToARGB(deviceColor));
+ return targetColorSpace->convertFromARGB(aIntermediate);
+ }
+ virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const double* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::RGBColor > aRes(nLen/4);
+ rendering::RGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
+ pIn += 4;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const double* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
+ pIn += 4;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const double* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
+ pIn += 4;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::RGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< double > aRes(nLen*4);
+ double* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = pIn->Red;
+ *pColors++ = pIn->Green;
+ *pColors++ = pIn->Blue;
+ *pColors++ = 1.0;
+ ++pIn;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< double > aRes(nLen*4);
+ double* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = pIn->Red;
+ *pColors++ = pIn->Green;
+ *pColors++ = pIn->Blue;
+ *pColors++ = pIn->Alpha;
+ ++pIn;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< double > aRes(nLen*4);
+ double* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = pIn->Red/pIn->Alpha;
+ *pColors++ = pIn->Green/pIn->Alpha;
+ *pColors++ = pIn->Blue/pIn->Alpha;
+ *pColors++ = pIn->Alpha;
+ ++pIn;
+ }
+ return aRes;
+ }
+
+ public:
+ StandardColorSpace() : m_aComponentTags(4)
+ {
+ sal_Int8* pTags = m_aComponentTags.getArray();
+ pTags[0] = rendering::ColorComponentTag::RGB_RED;
+ pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
+ pTags[3] = rendering::ColorComponentTag::ALPHA;
+ }
+ };
+ }
+
+ uno::Reference<rendering::XColorSpace> VCL_DLLPUBLIC createStandardColorSpace()
+ {
+ return new StandardColorSpace();
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ uno::Sequence< double > colorToStdColorSpaceSequence( const Color& rColor )
+ {
+ uno::Sequence< double > aRet(4);
+ double* pRet = aRet.getArray();
+
+ pRet[0] = toDoubleColor(rColor.GetRed());
+ pRet[1] = toDoubleColor(rColor.GetGreen());
+ pRet[2] = toDoubleColor(rColor.GetBlue());
+
+ // VCL's notion of alpha is different from the rest of the world's
+ pRet[3] = 1.0 - toDoubleColor(rColor.GetTransparency());
+
+ return aRet;
+ }
+
+ Color stdColorSpaceSequenceToColor( const uno::Sequence< double >& rColor )
+ {
+ ENSURE_ARG_OR_THROW( rColor.getLength() == 4,
+ "color must have 4 channels" );
+
+ Color aColor;
+
+ aColor.SetRed ( toByteColor(rColor[0]) );
+ aColor.SetGreen( toByteColor(rColor[1]) );
+ aColor.SetBlue ( toByteColor(rColor[2]) );
+ // VCL's notion of alpha is different from the rest of the world's
+ aColor.SetTransparency( 255 - toByteColor(rColor[3]) );
+
+ return aColor;
+ }
+
+ uno::Sequence< double > VCL_DLLPUBLIC colorToDoubleSequence(
+ const Color& rColor,
+ const uno::Reference< rendering::XColorSpace >& xColorSpace )
+ {
+ uno::Sequence<rendering::ARGBColor> aSeq(1);
+ aSeq[0] = rendering::ARGBColor(
+ 1.0-toDoubleColor(rColor.GetTransparency()),
+ toDoubleColor(rColor.GetRed()),
+ toDoubleColor(rColor.GetGreen()),
+ toDoubleColor(rColor.GetBlue()) );
+
+ return xColorSpace->convertFromARGB(aSeq);
+ }
+
+ Color VCL_DLLPUBLIC doubleSequenceToColor(
+ const uno::Sequence< double > rColor,
+ const uno::Reference< rendering::XColorSpace >& xColorSpace )
+ {
+ const rendering::ARGBColor& rARGBColor(
+ xColorSpace->convertToARGB(rColor)[0]);
+
+ return Color( 255-toByteColor(rARGBColor.Alpha),
+ toByteColor(rARGBColor.Red),
+ toByteColor(rARGBColor.Green),
+ toByteColor(rARGBColor.Blue) );
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ } // namespace vcltools
+
+} // namespace canvas
+
+// eof
diff --git a/vcl/source/helper/evntpost.cxx b/vcl/source/helper/evntpost.cxx
new file mode 100644
index 000000000000..9e200a3136c3
--- /dev/null
+++ b/vcl/source/helper/evntpost.cxx
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+
+
+#include <vcl/evntpost.hxx>
+#include <vcl/svapp.hxx>
+
+namespace vcl
+{
+
+EventPoster::EventPoster( const Link& rLink )
+ : m_aLink(rLink)
+{
+ m_nId = 0;
+}
+
+EventPoster::~EventPoster()
+{
+ if ( m_nId )
+ GetpApp()->RemoveUserEvent( m_nId );
+}
+
+void EventPoster::Post( UserEvent* pEvent )
+
+{
+ m_nId = GetpApp()->PostUserEvent( ( LINK( this, EventPoster, DoEvent_Impl ) ), pEvent );
+}
+
+IMPL_LINK_INLINE_START( EventPoster, DoEvent_Impl, UserEvent*, pEvent )
+{
+ m_nId = 0;
+ m_aLink.Call( pEvent );
+ return 0;
+}
+IMPL_LINK_INLINE_END( EventPoster, DoEvent_Impl, UserEvent*, pEvent )
+
+}
diff --git a/vcl/source/helper/lazydelete.cxx b/vcl/source/helper/lazydelete.cxx
new file mode 100644
index 000000000000..7b244781c3c7
--- /dev/null
+++ b/vcl/source/helper/lazydelete.cxx
@@ -0,0 +1,125 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef LAZYDELETE_CXX
+#define LAZYDELETE_CXX
+
+#include "vcl/window.hxx"
+#include "vcl/menu.hxx"
+#include "vcl/lazydelete.hxx"
+#include "vcl/svdata.hxx"
+
+namespace vcl {
+
+LazyDeletorBase::LazyDeletorBase()
+{
+}
+
+LazyDeletorBase::~LazyDeletorBase()
+{
+}
+
+// instantiate instance pointers for LazyDeletor<Window,Menu>
+template<> LazyDeletor<Window>* LazyDeletor<Window>::s_pOneInstance = NULL;
+template<> LazyDeletor<Menu>* LazyDeletor<Menu>::s_pOneInstance = NULL;
+
+// a list for all LazyeDeletor<T> singletons
+static std::vector< LazyDeletorBase* > lcl_aDeletors;
+
+void LazyDelete::addDeletor( LazyDeletorBase* i_pDel )
+{
+ lcl_aDeletors.push_back( i_pDel );
+}
+
+void LazyDelete::flush()
+{
+ unsigned int nCount = lcl_aDeletors.size();
+ for( unsigned int i = 0; i < nCount; i++ )
+ delete lcl_aDeletors[i];
+ lcl_aDeletors.clear();
+}
+
+// specialized is_less function for Window
+template<> bool LazyDeletor<Window>::is_less( Window* left, Window* right )
+{
+ return (left != right && right->IsChild( left, TRUE )) ? true : false;
+}
+
+// specialized is_less function for Menu
+template<> bool LazyDeletor<Menu>::is_less( Menu* left, Menu* right )
+{
+ while( left && left != right )
+ left = left->ImplGetStartedFrom();
+ return left != NULL;
+}
+
+DeleteOnDeinitBase::~DeleteOnDeinitBase()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData && pSVData->mpDeinitDeleteList != NULL )
+ pSVData->mpDeinitDeleteList->remove( this );
+}
+
+void DeleteOnDeinitBase::addDeinitContainer( DeleteOnDeinitBase* i_pContainer )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData )
+ {
+ ImplInitSVData();
+ pSVData = ImplGetSVData();
+ }
+
+ DBG_ASSERT( ! pSVData->mbDeInit, "DeleteOnDeinit added after DeiInitVCL !" );
+ if( pSVData->mbDeInit )
+ return;
+
+ if( pSVData->mpDeinitDeleteList == NULL )
+ pSVData->mpDeinitDeleteList = new std::list< DeleteOnDeinitBase* >();
+ pSVData->mpDeinitDeleteList->push_back( i_pContainer );
+}
+
+void DeleteOnDeinitBase::ImplDeleteOnDeInit()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpDeinitDeleteList )
+ {
+ for( std::list< vcl::DeleteOnDeinitBase* >::iterator it = pSVData->mpDeinitDeleteList->begin();
+ it != pSVData->mpDeinitDeleteList->end(); ++it )
+ {
+ (*it)->doCleanup();
+ }
+ delete pSVData->mpDeinitDeleteList;
+ pSVData->mpDeinitDeleteList = NULL;
+ }
+}
+
+} // namespace vcl
+
+#endif
+
diff --git a/vcl/source/helper/makefile.mk b/vcl/source/helper/makefile.mk
new file mode 100644
index 000000000000..e708bdec9eaa
--- /dev/null
+++ b/vcl/source/helper/makefile.mk
@@ -0,0 +1,56 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+ENABLE_EXCEPTIONS=TRUE
+PRJNAME=vcl
+TARGET=helper
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES=\
+ $(SLO)$/strhelper.obj \
+ $(SLO)$/evntpost.obj \
+ $(SLO)$/canvasbitmap.obj \
+ $(SLO)$/canvastools.obj \
+ $(SLO)$/xconnection.obj \
+ $(SLO)$/threadex.obj \
+ $(SLO)$/smartid.obj \
+ $(SLO)$/lazydelete.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/source/helper/smartid.cxx b/vcl/source/helper/smartid.cxx
new file mode 100755
index 000000000000..c367aeb2bce5
--- /dev/null
+++ b/vcl/source/helper/smartid.cxx
@@ -0,0 +1,264 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/smartid.hxx>
+
+struct ImplSmartIdData
+{
+ String aUId;
+ ULONG nUId;
+ BOOL bHasStringId;
+ BOOL bHasNumericId;
+};
+
+
+ImplSmartIdData* SmartId::GetSmartIdData()
+{
+ if ( !mpData )
+ {
+ mpData = new ImplSmartIdData;
+// mpData->aUId = "";
+ mpData->nUId = 0;
+ mpData->bHasStringId = FALSE;
+ mpData->bHasNumericId = FALSE;
+ }
+ return mpData;
+}
+
+
+SmartId::SmartId( const String& rId )
+: mpData( NULL )
+{
+ GetSmartIdData()->aUId = rId;
+ GetSmartIdData()->bHasStringId = TRUE;
+}
+
+SmartId::SmartId( ULONG nId )
+: mpData( NULL )
+{
+ GetSmartIdData()->nUId = nId;
+ GetSmartIdData()->bHasNumericId = TRUE;
+}
+
+SmartId::SmartId( const String& rId, ULONG nId )
+: mpData( NULL )
+{
+ GetSmartIdData()->aUId = rId;
+ GetSmartIdData()->bHasStringId = TRUE;
+ GetSmartIdData()->nUId = nId;
+ GetSmartIdData()->bHasNumericId = TRUE;
+}
+
+SmartId::SmartId()
+: mpData( NULL )
+{}
+
+SmartId::SmartId( const SmartId& rId )
+: mpData( NULL )
+{
+ if ( rId.mpData )
+ {
+ GetSmartIdData();
+ mpData->aUId = rId.mpData->aUId;
+ mpData->bHasStringId = rId.mpData->bHasStringId;
+ mpData->nUId = rId.mpData->nUId;
+ mpData->bHasNumericId = rId.mpData->bHasNumericId;
+ }
+}
+
+SmartId& SmartId::operator = ( const SmartId& rId )
+{
+ if ( rId.mpData )
+ GetSmartIdData();
+ else
+ {
+ delete mpData;
+ mpData = NULL;
+ }
+ if ( mpData && rId.mpData )
+ {
+ mpData->aUId = rId.mpData->aUId;
+ mpData->bHasStringId = rId.mpData->bHasStringId;
+ mpData->nUId = rId.mpData->nUId;
+ mpData->bHasNumericId = rId.mpData->bHasNumericId;
+ }
+ return *this;
+}
+
+SmartId::~SmartId()
+{
+ if ( mpData )
+ delete mpData;
+#ifdef DBG_UTIL
+ if ( mpData )
+ mpData = (ImplSmartIdData*)0xDeadBeef;
+#endif
+}
+
+void SmartId::UpdateId( const SmartId& rId, SmartIdUpdateMode aMode )
+{
+ // Check if ImplData is needed
+ if ( aMode != SMART_SET_SMART || ( rId.HasString() || rId.HasNumeric() ) )
+ GetSmartIdData();
+
+ if ( aMode == SMART_SET_STR || aMode == SMART_SET_ALL || ( aMode == SMART_SET_SMART && rId.HasString() ) )
+ {
+ GetSmartIdData()->aUId = rId.GetStr();
+ GetSmartIdData()->bHasStringId = rId.HasString();
+ }
+ if ( aMode == SMART_SET_NUM || aMode == SMART_SET_ALL || ( aMode == SMART_SET_SMART && rId.HasNumeric() ) )
+ {
+ GetSmartIdData()->nUId = rId.GetNum();
+ GetSmartIdData()->bHasNumericId = rId.HasNumeric();
+ }
+
+ // remove ImplData when no IDs are set. This is Important because Implementation of Equals() Matches and HasAny relies on it
+ if ( mpData && !mpData->bHasStringId && !mpData->bHasNumericId )
+ {
+ delete mpData;
+ mpData = NULL;
+ }
+}
+
+BOOL SmartId::HasNumeric() const
+{
+ if ( !mpData )
+ return FALSE;
+ else
+ return mpData->bHasNumericId;
+}
+
+BOOL SmartId::HasString() const
+{
+ if ( !mpData )
+ return FALSE;
+ else
+ return mpData->bHasStringId;
+}
+
+BOOL SmartId::HasAny() const
+{
+ return mpData != NULL;
+}
+
+ULONG SmartId::GetNum() const
+{
+ if ( !mpData )
+ return 0;
+ else
+ return mpData->nUId;
+}
+
+String SmartId::GetStr() const
+{
+ if ( !mpData )
+ return String();
+ else
+ return mpData->aUId;
+}
+
+
+String SmartId::GetText() const // return String for UI usage
+{
+ String aRes;
+ if ( HasNumeric() )
+ aRes = String::CreateFromInt64( GetNum() );
+ if ( HasString() )
+ {
+ if ( HasNumeric() )
+ aRes.AppendAscii( "/" );
+ aRes.Append( GetStr() );
+ }
+ return aRes;
+}
+
+BOOL SmartId::Matches( const String &rId )const
+{
+ if ( HasString() )
+ return GetStr().EqualsIgnoreCaseAscii( rId );
+ else
+ return FALSE;
+}
+
+BOOL SmartId::Matches( const ULONG nId ) const
+{
+ if ( HasNumeric() )
+ return GetNum() == nId;
+ else
+ return FALSE;
+}
+
+/******************************************************************************
+If Both Ids have nither Strings nor Numbers they don't match
+If both Ids have Strings the result of Matching these is returned.
+Numbers are then Ignored.
+Else Matching Numbers is attempted.
+******************************************************************************/
+BOOL SmartId::Matches( const SmartId &rId ) const
+{
+ if ( !mpData || !rId.mpData )
+ return FALSE;
+ else if ( HasString() && rId.HasString() )
+ return Matches( rId.GetStr() );
+ else
+ return rId.HasNumeric() && Matches( rId.GetNum() );
+}
+
+BOOL SmartId::Equals( const SmartId &rId ) const
+{
+ if ( mpData && rId.mpData )
+ return mpData->aUId.EqualsIgnoreCaseAscii( rId.mpData->aUId )
+ && mpData->bHasStringId == rId.mpData->bHasStringId
+ && mpData->nUId == rId.mpData->nUId
+ && mpData->bHasNumericId == rId.mpData->bHasNumericId;
+ else if ( !mpData && !rId.mpData )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+BOOL SmartId::operator == ( const SmartId& rRight ) const
+{
+ return Equals( rRight );
+}
+
+BOOL SmartId::operator < ( const SmartId& rRight ) const
+{
+ if ( HasString() && rRight.HasString() && GetStr() != rRight.GetStr() )
+ return GetStr() < rRight.GetStr();
+ else if ( HasNumeric() && rRight.HasNumeric() && GetNum() != rRight.GetNum() )
+ return GetNum() < rRight.GetNum();
+ else
+ { // Sort Strings to Front
+ if ( HasString() )
+ return rRight.HasString() && rRight.HasNumeric();
+ else
+ return rRight.HasString() || (!HasNumeric() && rRight.HasNumeric());
+ }
+}
diff --git a/vcl/source/helper/strhelper.cxx b/vcl/source/helper/strhelper.cxx
new file mode 100644
index 000000000000..db622073cea9
--- /dev/null
+++ b/vcl/source/helper/strhelper.cxx
@@ -0,0 +1,442 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/strhelper.hxx"
+#include "sal/alloca.h"
+
+namespace psp {
+
+inline int isSpace( char cChar )
+{
+ return
+ cChar == ' ' || cChar == '\t' ||
+ cChar == '\r' || cChar == '\n' ||
+ cChar == 0x0c || cChar == 0x0b;
+}
+
+inline int isSpace( sal_Unicode cChar )
+{
+ return
+ cChar == ' ' || cChar == '\t' ||
+ cChar == '\r' || cChar == '\n' ||
+ cChar == 0x0c || cChar == 0x0b;
+}
+
+inline int isProtect( char cChar )
+{
+ return cChar == '`' || cChar == '\'' || cChar == '"';
+}
+
+inline int isProtect( sal_Unicode cChar )
+{
+ return cChar == '`' || cChar == '\'' || cChar == '"';
+}
+
+inline void CopyUntil( char*& pTo, const char*& pFrom, char cUntil, int bIncludeUntil = 0 )
+{
+ do
+ {
+ if( *pFrom == '\\' )
+ {
+ pFrom++;
+ if( *pFrom )
+ {
+ *pTo = *pFrom;
+ pTo++;
+ }
+ }
+ else if( bIncludeUntil || ! isProtect( *pFrom ) )
+ {
+ *pTo = *pFrom;
+ pTo++;
+ }
+ pFrom++;
+ } while( *pFrom && *pFrom != cUntil );
+ // copy the terminating character unless zero or protector
+ if( ! isProtect( *pFrom ) || bIncludeUntil )
+ {
+ *pTo = *pFrom;
+ if( *pTo )
+ pTo++;
+ }
+ if( *pFrom )
+ pFrom++;
+}
+
+inline void CopyUntil( sal_Unicode*& pTo, const sal_Unicode*& pFrom, sal_Unicode cUntil, int bIncludeUntil = 0 )
+{
+ do
+ {
+ if( *pFrom == '\\' )
+ {
+ pFrom++;
+ if( *pFrom )
+ {
+ *pTo = *pFrom;
+ pTo++;
+ }
+ }
+ else if( bIncludeUntil || ! isProtect( *pFrom ) )
+ {
+ *pTo = *pFrom;
+ pTo++;
+ }
+ pFrom++;
+ } while( *pFrom && *pFrom != cUntil );
+ // copy the terminating character unless zero or protector
+ if( ! isProtect( *pFrom ) || bIncludeUntil )
+ {
+ *pTo = *pFrom;
+ if( *pTo )
+ pTo++;
+ }
+ if( *pFrom )
+ pFrom++;
+}
+
+String GetCommandLineToken( int nToken, const String& rLine )
+{
+ int nLen = rLine.Len();
+ if( ! nLen )
+ return String();
+
+ int nActualToken = 0;
+ sal_Unicode* pBuffer = (sal_Unicode*)alloca( sizeof(sal_Unicode)*( nLen + 1 ) );
+ const sal_Unicode* pRun = rLine.GetBuffer();
+ sal_Unicode* pLeap = NULL;
+
+ while( *pRun && nActualToken <= nToken )
+ {
+ while( *pRun && isSpace( *pRun ) )
+ pRun++;
+ pLeap = pBuffer;
+ while( *pRun && ! isSpace( *pRun ) )
+ {
+ if( *pRun == '\\' )
+ {
+ // escapement
+ pRun++;
+ *pLeap = *pRun;
+ pLeap++;
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '`' )
+ CopyUntil( pLeap, pRun, '`' );
+ else if( *pRun == '\'' )
+ CopyUntil( pLeap, pRun, '\'' );
+ else if( *pRun == '"' )
+ CopyUntil( pLeap, pRun, '"' );
+ else
+ {
+ *pLeap = *pRun;
+ pLeap++;
+ pRun++;
+ }
+ }
+ if( nActualToken != nToken )
+ pBuffer[0] = 0;
+ nActualToken++;
+ }
+
+ *pLeap = 0;
+
+ String aRet( pBuffer );
+ return aRet;
+}
+
+ByteString GetCommandLineToken( int nToken, const ByteString& rLine )
+{
+ int nLen = rLine.Len();
+ if( ! nLen )
+ return ByteString();
+
+ int nActualToken = 0;
+ char* pBuffer = (char*)alloca( nLen + 1 );
+ const char* pRun = rLine.GetBuffer();
+ char* pLeap = NULL;
+
+ while( *pRun && nActualToken <= nToken )
+ {
+ while( *pRun && isSpace( *pRun ) )
+ pRun++;
+ pLeap = pBuffer;
+ while( *pRun && ! isSpace( *pRun ) )
+ {
+ if( *pRun == '\\' )
+ {
+ // escapement
+ pRun++;
+ *pLeap = *pRun;
+ pLeap++;
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '`' )
+ CopyUntil( pLeap, pRun, '`' );
+ else if( *pRun == '\'' )
+ CopyUntil( pLeap, pRun, '\'' );
+ else if( *pRun == '"' )
+ CopyUntil( pLeap, pRun, '"' );
+ else
+ {
+ *pLeap = *pRun;
+ pLeap++;
+ pRun++;
+ }
+ }
+ if( nActualToken != nToken )
+ pBuffer[0] = 0;
+ nActualToken++;
+ }
+
+ *pLeap = 0;
+
+ ByteString aRet( pBuffer );
+ return aRet;
+}
+
+int GetCommandLineTokenCount( const String& rLine )
+{
+ if( ! rLine.Len() )
+ return 0;
+
+ int nTokenCount = 0;
+ const sal_Unicode *pRun = rLine.GetBuffer();
+
+
+ while( *pRun )
+ {
+ while( *pRun && isSpace( *pRun ) )
+ pRun++;
+ if( ! *pRun )
+ break;
+ while( *pRun && ! isSpace( *pRun ) )
+ {
+ if( *pRun == '\\' )
+ {
+ // escapement
+ pRun++;
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '`' )
+ {
+ do pRun++; while( *pRun && *pRun != '`' );
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '\'' )
+ {
+ do pRun++; while( *pRun && *pRun != '\'' );
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '"' )
+ {
+ do pRun++; while( *pRun && *pRun != '"' );
+ if( *pRun )
+ pRun++;
+ }
+ else
+ pRun++;
+ }
+ nTokenCount++;
+ }
+
+ return nTokenCount;
+}
+
+int GetCommandLineTokenCount( const ByteString& rLine )
+{
+ if( ! rLine.Len() )
+ return 0;
+
+ int nTokenCount = 0;
+ const char *pRun = rLine.GetBuffer();
+
+
+ while( *pRun )
+ {
+ while( *pRun && isSpace( *pRun ) )
+ pRun++;
+ if( ! *pRun )
+ break;
+ while( *pRun && ! isSpace( *pRun ) )
+ {
+ if( *pRun == '\\' )
+ {
+ // escapement
+ pRun++;
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '`' )
+ {
+ do pRun++; while( *pRun && *pRun != '`' );
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '\'' )
+ {
+ do pRun++; while( *pRun && *pRun != '\'' );
+ if( *pRun )
+ pRun++;
+ }
+ else if( *pRun == '"' )
+ {
+ do pRun++; while( *pRun && *pRun != '"' );
+ if( *pRun )
+ pRun++;
+ }
+ else
+ pRun++;
+ }
+ nTokenCount++;
+ }
+
+ return nTokenCount;
+}
+
+String WhitespaceToSpace( const String& rLine, BOOL bProtect )
+{
+ int nLen = rLine.Len();
+ if( ! nLen )
+ return String();
+
+ sal_Unicode *pBuffer = (sal_Unicode*)alloca( sizeof(sal_Unicode)*(nLen + 1) );
+ const sal_Unicode *pRun = rLine.GetBuffer();
+ sal_Unicode *pLeap = pBuffer;
+
+ while( *pRun )
+ {
+ if( *pRun && isSpace( *pRun ) )
+ {
+ *pLeap = ' ';
+ pLeap++;
+ pRun++;
+ }
+ while( *pRun && isSpace( *pRun ) )
+ pRun++;
+ while( *pRun && ! isSpace( *pRun ) )
+ {
+ if( *pRun == '\\' )
+ {
+ // escapement
+ pRun++;
+ *pLeap = *pRun;
+ pLeap++;
+ if( *pRun )
+ pRun++;
+ }
+ else if( bProtect && *pRun == '`' )
+ CopyUntil( pLeap, pRun, '`', TRUE );
+ else if( bProtect && *pRun == '\'' )
+ CopyUntil( pLeap, pRun, '\'', TRUE );
+ else if( bProtect && *pRun == '"' )
+ CopyUntil( pLeap, pRun, '"', TRUE );
+ else
+ {
+ *pLeap = *pRun;
+ *pLeap++;
+ *pRun++;
+ }
+ }
+ }
+
+ *pLeap = 0;
+
+ // there might be a space at beginning or end
+ pLeap--;
+ if( *pLeap == ' ' )
+ *pLeap = 0;
+
+ String aRet( *pBuffer == ' ' ? pBuffer+1 : pBuffer );
+ return aRet;
+}
+
+ByteString WhitespaceToSpace( const ByteString& rLine, BOOL bProtect )
+{
+ int nLen = rLine.Len();
+ if( ! nLen )
+ return ByteString();
+
+ char *pBuffer = (char*)alloca( nLen + 1 );
+ const char *pRun = rLine.GetBuffer();
+ char *pLeap = pBuffer;
+
+ while( *pRun )
+ {
+ if( *pRun && isSpace( *pRun ) )
+ {
+ *pLeap = ' ';
+ pLeap++;
+ pRun++;
+ }
+ while( *pRun && isSpace( *pRun ) )
+ pRun++;
+ while( *pRun && ! isSpace( *pRun ) )
+ {
+ if( *pRun == '\\' )
+ {
+ // escapement
+ pRun++;
+ *pLeap = *pRun;
+ pLeap++;
+ if( *pRun )
+ pRun++;
+ }
+ else if( bProtect && *pRun == '`' )
+ CopyUntil( pLeap, pRun, '`', TRUE );
+ else if( bProtect && *pRun == '\'' )
+ CopyUntil( pLeap, pRun, '\'', TRUE );
+ else if( bProtect && *pRun == '"' )
+ CopyUntil( pLeap, pRun, '"', TRUE );
+ else
+ {
+ *pLeap = *pRun;
+ *pLeap++;
+ *pRun++;
+ }
+ }
+ }
+
+ *pLeap = 0;
+
+ // there might be a space at beginning or end
+ pLeap--;
+ if( *pLeap == ' ' )
+ *pLeap = 0;
+
+ ByteString aRet( *pBuffer == ' ' ? pBuffer+1 : pBuffer );
+ return aRet;
+}
+
+} // namespace
diff --git a/vcl/source/helper/threadex.cxx b/vcl/source/helper/threadex.cxx
new file mode 100644
index 000000000000..133b19aa0538
--- /dev/null
+++ b/vcl/source/helper/threadex.cxx
@@ -0,0 +1,127 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define THREADEX_IMPLEMENTATION
+#include <vcl/threadex.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace vcl;
+
+ThreadExecutor::ThreadExecutor()
+{
+ m_aFinish = osl_createCondition();
+ m_aThread = NULL;
+}
+
+ThreadExecutor::~ThreadExecutor()
+{
+ osl_destroyCondition( m_aFinish );
+ if( m_aThread )
+ osl_destroyThread( m_aThread );
+}
+
+extern "C"
+{
+ static void call_worker( void* pInstance )
+ {
+ ThreadExecutor::worker( pInstance );
+ }
+}
+
+void ThreadExecutor::worker( void* pInstance )
+{
+ ThreadExecutor* pThis = ((ThreadExecutor*)pInstance);
+ pThis->m_nReturn = pThis->doIt();
+ osl_setCondition( pThis->m_aFinish );
+}
+
+long ThreadExecutor::execute()
+{
+ osl_resetCondition( m_aFinish );
+ if( m_aThread )
+ osl_destroyThread( m_aThread ), m_aThread = NULL;
+ m_aThread = osl_createThread( call_worker, this );
+ while( ! osl_checkCondition( m_aFinish ) )
+ Application::Reschedule();
+ return m_nReturn;
+}
+
+
+SolarThreadExecutor::SolarThreadExecutor()
+ :m_nReturn( 0 )
+ ,m_bTimeout( false )
+{
+ m_aStart = osl_createCondition();
+ m_aFinish = osl_createCondition();
+}
+
+SolarThreadExecutor::~SolarThreadExecutor()
+{
+ osl_destroyCondition( m_aStart );
+ osl_destroyCondition( m_aFinish );
+}
+
+IMPL_LINK( SolarThreadExecutor, worker, void*, EMPTYARG )
+{
+ if ( !m_bTimeout )
+ {
+ osl_setCondition( m_aStart );
+ m_nReturn = doIt();
+ osl_setCondition( m_aFinish );
+ }
+ return m_nReturn;
+}
+
+long SolarThreadExecutor::impl_execute( const TimeValue* _pTimeout )
+{
+ if( ::vos::OThread::getCurrentIdentifier() == Application::GetMainThreadIdentifier() )
+ {
+ osl_setCondition( m_aStart );
+ m_nReturn = doIt();
+ osl_setCondition( m_aFinish );
+ }
+ else
+ {
+ osl_resetCondition( m_aStart );
+ osl_resetCondition( m_aFinish );
+ ULONG nSolarMutexCount = Application::ReleaseSolarMutex();
+ ULONG nEvent = Application::PostUserEvent( LINK( this, SolarThreadExecutor, worker ) );
+ if ( osl_cond_result_timeout == osl_waitCondition( m_aStart, _pTimeout ) )
+ {
+ m_bTimeout = true;
+ Application::RemoveUserEvent( nEvent );
+ }
+ else
+ osl_waitCondition( m_aFinish, NULL );
+ if( nSolarMutexCount )
+ Application::AcquireSolarMutex( nSolarMutexCount );
+ }
+ return m_nReturn;
+}
diff --git a/vcl/source/helper/xconnection.cxx b/vcl/source/helper/xconnection.cxx
new file mode 100644
index 000000000000..caf7ee237d67
--- /dev/null
+++ b/vcl/source/helper/xconnection.cxx
@@ -0,0 +1,178 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "svsys.h"
+#include "vcl/xconnection.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/salinst.hxx"
+#include "vcl/svapp.hxx"
+
+namespace vcl
+{
+ class SolarMutexReleaser
+ {
+ ULONG mnReleased;
+ public:
+ SolarMutexReleaser()
+ {
+ mnReleased = Application::ReleaseSolarMutex();
+ }
+
+ ~SolarMutexReleaser()
+ {
+ if( mnReleased )
+ Application::AcquireSolarMutex( mnReleased );
+ }
+ };
+}
+
+using namespace rtl;
+using namespace osl;
+using namespace vcl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt;
+
+
+DisplayConnection::DisplayConnection()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpDefInst->SetEventCallback( this, dispatchEvent );
+ pSVData->mpDefInst->SetErrorEventCallback( this, dispatchErrorEvent );
+
+ SalInstance::ConnectionIdentifierType eType;
+ int nBytes;
+ void* pBytes = pSVData->mpDefInst->GetConnectionIdentifier( eType, nBytes );
+ switch( eType )
+ {
+ case SalInstance::AsciiCString:
+ m_aAny <<= OUString::createFromAscii( (sal_Char*)pBytes );
+ break;
+ case SalInstance::Blob:
+ m_aAny <<= Sequence< sal_Int8 >( (sal_Int8*)pBytes, nBytes );
+ break;
+ }
+}
+
+DisplayConnection::~DisplayConnection()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if( pSVData )
+ {
+ pSVData->mpDefInst->SetEventCallback( NULL, NULL );
+ pSVData->mpDefInst->SetErrorEventCallback( NULL, NULL );
+ }
+}
+
+
+void SAL_CALL DisplayConnection::addEventHandler( const Any& /*window*/, const Reference< XEventHandler >& handler, sal_Int32 /*eventMask*/ ) throw()
+{
+ MutexGuard aGuard( m_aMutex );
+
+ m_aHandlers.push_back( handler );
+}
+
+void SAL_CALL DisplayConnection::removeEventHandler( const Any& /*window*/, const Reference< XEventHandler >& handler ) throw()
+{
+ MutexGuard aGuard( m_aMutex );
+
+ m_aHandlers.remove( handler );
+}
+
+void SAL_CALL DisplayConnection::addErrorHandler( const Reference< XEventHandler >& handler ) throw()
+{
+ MutexGuard aGuard( m_aMutex );
+
+ m_aErrorHandlers.push_back( handler );
+}
+
+void SAL_CALL DisplayConnection::removeErrorHandler( const Reference< XEventHandler >& handler ) throw()
+{
+ MutexGuard aGuard( m_aMutex );
+
+ m_aErrorHandlers.remove( handler );
+}
+
+Any SAL_CALL DisplayConnection::getIdentifier() throw()
+{
+ return m_aAny;
+}
+
+void DisplayConnection::dispatchDowningEvent()
+{
+ SolarMutexReleaser aRel;
+
+ MutexGuard aGuard( m_aMutex );
+ Any aEvent;
+ std::list< Reference< XEventHandler > > aLocalList( m_aHandlers );
+ for( ::std::list< Reference< XEventHandler > >::const_iterator it = aLocalList.begin(); it != aLocalList.end(); ++it )
+ (*it)->handleEvent( aEvent );
+}
+
+bool DisplayConnection::dispatchEvent( void* pThis, void* pData, int nBytes )
+{
+ SolarMutexReleaser aRel;
+
+ DisplayConnection* This = (DisplayConnection*)pThis;
+
+ Sequence< sal_Int8 > aSeq( (sal_Int8*)pData, nBytes );
+ Any aEvent;
+ aEvent <<= aSeq;
+ ::std::list< Reference< XEventHandler > > handlers;
+ {
+ MutexGuard aGuard( This->m_aMutex );
+ handlers = This->m_aHandlers;
+ }
+ for( ::std::list< Reference< XEventHandler > >::const_iterator it = handlers.begin(); it != handlers.end(); ++it )
+ if( (*it)->handleEvent( aEvent ) )
+ return true;
+ return false;
+}
+
+bool DisplayConnection::dispatchErrorEvent( void* pThis, void* pData, int nBytes )
+{
+ SolarMutexReleaser aRel;
+
+ DisplayConnection* This = (DisplayConnection*)pThis;
+
+ Sequence< sal_Int8 > aSeq( (sal_Int8*)pData, nBytes );
+ Any aEvent;
+ aEvent <<= aSeq;
+ ::std::list< Reference< XEventHandler > > handlers;
+ {
+ MutexGuard aGuard( This->m_aMutex );
+ handlers = This->m_aErrorHandlers;
+ }
+ for( ::std::list< Reference< XEventHandler > >::const_iterator it = handlers.begin(); it != handlers.end(); ++it )
+ if( (*it)->handleEvent( aEvent ) )
+ return true;
+
+ return false;
+}
diff --git a/vcl/source/salmain/makefile.mk b/vcl/source/salmain/makefile.mk
new file mode 100644
index 000000000000..de085b482c4d
--- /dev/null
+++ b/vcl/source/salmain/makefile.mk
@@ -0,0 +1,38 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ = ..$/..
+PRJNAME = vcl
+TARGET = salmain
+LIBTARGET = NO
+ENABLE_EXCEPTIONS = TRUE
+
+.INCLUDE: settings.mk
+
+OBJFILES = $(OBJ)$/salmain.obj
+
+.INCLUDE: target.mk
diff --git a/vcl/source/salmain/salmain.cxx b/vcl/source/salmain/salmain.cxx
new file mode 100644
index 000000000000..c2e3af01635a
--- /dev/null
+++ b/vcl/source/salmain/salmain.cxx
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_vcl.hxx"
+#include "sal/config.h"
+
+#include <cstdlib>
+
+#include "sal/main.h"
+#include "tools/extendapplicationenvironment.hxx"
+#include "vcl/salinst.hxx"
+
+SAL_IMPLEMENT_MAIN() {
+ tools::extendApplicationEnvironment();
+ return SVMain() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/vcl/source/src/btntext.src b/vcl/source/src/btntext.src
new file mode 100644
index 000000000000..6d2360dae6cb
--- /dev/null
+++ b/vcl/source/src/btntext.src
@@ -0,0 +1,147 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define _SV_BTNTEXT_SRC
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+
+String SV_BUTTONTEXT_OK
+{
+ Text [ en-US ] = "OK";
+};
+
+String SV_BUTTONTEXT_CANCEL
+{
+ Text [ en-US ] = "Cancel";
+};
+
+String SV_BUTTONTEXT_YES
+{
+ Text [ en-US ] = "~Yes";
+};
+
+String SV_BUTTONTEXT_NO
+{
+ Text [ en-US ] = "~No";
+};
+
+String SV_BUTTONTEXT_RETRY
+{
+ Text [ en-US ] = "~Retry";
+};
+
+String SV_BUTTONTEXT_HELP
+{
+ Text [ en-US ] = "~Help";
+};
+
+String SV_BUTTONTEXT_MORE
+{
+ Text [ en-US ] = "~More";
+};
+
+String SV_BUTTONTEXT_LESS
+{
+ Text [ en-US ] = "~More";
+};
+
+String SV_BUTTONTEXT_IGNORE
+{
+ Text [ en-US ] = "~Ignore";
+};
+
+String SV_BUTTONTEXT_ABORT
+{
+ Text [ en-US ] = "~Abort";
+};
+
+/* HelpTexte, die wir derzeit nicht mehr verwenden:
+SV_BUTTONHELPTEXT_OK
+{
+ Text = "Schließt dieses Dialogfeld und speichert alle vorgenommenen Änderungen." ;
+};
+
+SV_BUTTONHELPTEXT_CANCEL
+{
+ Text = "Schließt dieses Dialogfeld, ohne Ihre Änderungen zu speichern." ;
+};
+
+SV_BUTTONHELPTEXT_HELP
+{
+ Text = "Zeigt Hilfe zu diesem Fenster an." ;
+};
+
+SV_BUTTONHELPTEXT_MORE
+{
+ Text = "Zeigt weitere EinstellmÖglichkeiten an oder versteckt diese wieder." ;
+};
+
+Finnische-Texte:
+OK OK
+CANCEL Peruuta
+HELP ~Ohje
+MORE ~Enemmän
+YES ~Kyllä
+NO ~Ei
+RETRY ~Yritäuudelleen
+*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vcl/source/src/helptext.src b/vcl/source/src/helptext.src
new file mode 100644
index 000000000000..a42a9531d9ee
--- /dev/null
+++ b/vcl/source/src/helptext.src
@@ -0,0 +1,163 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define _SV_HELPTEXT_SRC
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+
+String SV_HELPTEXT_CLOSE
+{
+ Text [ en-US ] = "Close";
+};
+String SV_HELPTEXT_CLOSEDOCUMENT
+{
+ Text [ en-US ] = "Close Document";
+};
+String SV_HELPTEXT_MINIMIZE
+{
+ Text [ en-US ] = "Minimize";
+};
+
+String SV_HELPTEXT_MAXIMIZE
+{
+ Text [ en-US ] = "Maximize";
+};
+
+String SV_HELPTEXT_RESTORE
+{
+ Text [ en-US ] = "Restore";
+};
+
+String SV_HELPTEXT_ROLLDOWN
+{
+ Text [ en-US ] = "Drop down";
+};
+
+String SV_HELPTEXT_ROLLUP
+{
+ Text [ en-US ] = "Roll up";
+};
+
+String SV_HELPTEXT_HELP
+{
+ Text [ en-US ] = "Help";
+};
+
+String SV_HELPTEXT_ALWAYSVISIBLE
+{
+ Text [ en-US ] = "Always visible";
+};
+
+String SV_HELPTEXT_FADEIN
+{
+ Text [ en-US ] = "Show";
+};
+
+String SV_HELPTEXT_FADEOUT
+{
+ Text [ en-US ] = "Hide";
+};
+
+String SV_HELPTEXT_SPLITFLOATING
+{
+ Text [ en-US ] = "Floating";
+};
+
+String SV_HELPTEXT_SPLITFIXED
+{
+ Text [ en-US ] = "Stick";
+};
+
+String SV_SHORTCUT_HELP
+{
+ Text [ en-US ] = "Help" ;
+};
+
+String SV_SHORTCUT_CONTEXTHELP
+{
+ Text [ en-US ] = "Context Help";
+};
+
+String SV_SHORTCUT_ACTIVEHELP
+{
+ Text [ en-US ] = "Extended Tips";
+};
+
+String SV_SHORTCUT_DOCKUNDOCK
+{
+ Text [ en-US ] = "Dock/Undock Windows";
+};
+
+String SV_SHORTCUT_NEXTSUBWINDOW
+{
+ Text [ en-US ] = "To Next Toolbar/Window";
+};
+
+String SV_SHORTCUT_PREVSUBWINDOW
+{
+ Text [ en-US ] = "To Previous Toolbar/Window";
+};
+
+String SV_SHORTCUT_TODOCUMENT
+{
+ Text [ en-US ] = "To Document";
+};
+
+String SV_SHORTCUT_MENUBAR
+{
+ Text [ en-US ] = "To Menu Bar";
+};
+
+String SV_SHORTCUT_SPLITTER
+{
+ Text [ en-US ] = "Split window separator" ;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vcl/source/src/images.src b/vcl/source/src/images.src
new file mode 100644
index 000000000000..fdb1e755c86a
--- /dev/null
+++ b/vcl/source/src/images.src
@@ -0,0 +1,852 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define _SV_IMAGES_SRC
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+
+// =======================================================================
+
+Bitmap (SV_RESID_BITMAP_CHECK + SV_RESID_STDOFFSET)
+{
+ File = "check.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_CHECK + SV_RESID_WINOFFSET)
+{
+ File = "checkwin.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_CHECK + SV_RESID_OS2OFFSET)
+{
+ File = "checkos2.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_CHECK + SV_RESID_MACOFFSET)
+{
+ File = "checkmac.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_CHECK + SV_RESID_UNIXOFFSET)
+{
+ File = "checkunx.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_CHECK + SV_RESID_MONOOFFSET)
+{
+ File = "checkmono.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_SCROLLBMP)
+{
+ File = "scrbmp.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_SCROLLMSK)
+{
+ File = "scrmsk.bmp";
+};
+
+// -----------------------------------------------------------------------
+
+Bitmap (SV_RESID_BITMAP_RADIO + SV_RESID_STDOFFSET)
+{
+ File = "radio.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_RADIO + SV_RESID_WINOFFSET)
+{
+ File = "radiowin.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_RADIO + SV_RESID_OS2OFFSET)
+{
+ File = "radioos2.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_RADIO + SV_RESID_MACOFFSET)
+{
+ File = "radiomac.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_RADIO + SV_RESID_UNIXOFFSET)
+{
+ File = "radiounx.bmp";
+};
+
+Bitmap (SV_RESID_BITMAP_RADIO + SV_RESID_MONOOFFSET)
+{
+ File = "radiomono.bmp";
+};
+
+// -----------------------------------------------------------------------
+
+Bitmap SV_RESID_BITMAP_MSGBOX
+{
+ File = "msgbox.png";
+};
+
+// -----------------------------------------------------------------------
+
+Bitmap SV_RESID_BITMAP_MSGBOX_HC
+{
+ File = "msgbox_hc.png";
+};
+
+// -----------------------------------------------------------------------
+
+Bitmap SV_RESID_BITMAP_PIN
+{
+ File = "pin.bmp";
+};
+
+// -----------------------------------------------------------------------
+
+Bitmap SV_RESID_BITMAP_CLOSEDOC
+{
+ File = "closedoc.bmp";
+};
+
+Bitmap SV_RESID_BITMAP_CLOSEDOCHC
+{
+ File = "closedochc.bmp";
+};
+
+// -----------------------------------------------------------------------
+
+Bitmap SV_RESID_BITMAP_SPLITHPIN
+{
+ File = "splhpin.bmp";
+};
+
+Bitmap SV_RESID_BITMAP_SPLITVPIN
+{
+ File = "splvpin.bmp";
+};
+
+Bitmap SV_RESID_BITMAP_SPLITHARW
+{
+ File = "splharw.bmp";
+};
+
+Bitmap SV_RESID_BITMAP_SPLITVARW
+{
+ File = "splvarw.bmp";
+};
+
+// -----------------------------------------------------------------------
+
+Bitmap (SV_ICON_SIZE48_START)
+{
+ File = "mainapp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START)
+{
+ File = "mainapp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START)
+{
+ File = "mainapp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_OFFICE)
+{
+ File = "mainapp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_OFFICE)
+{
+ File = "mainapp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_OFFICE)
+{
+ File = "mainapp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_TEXT)
+{
+ File = "odt_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_TEXT)
+{
+ File = "odt_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_TEXT)
+{
+ File = "odt_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_TEXT_TEMPLATE)
+{
+ File = "ott_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_TEXT_TEMPLATE)
+{
+ File = "ott_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_TEXT_TEMPLATE)
+{
+ File = "ott_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_SPREADSHEET)
+{
+ File = "ods_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_SPREADSHEET)
+{
+ File = "ods_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_SPREADSHEET)
+{
+ File = "ods_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_SPREADSHEET_TEMPLATE)
+{
+ File = "ots_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_SPREADSHEET_TEMPLATE)
+{
+ File = "ots_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_SPREADSHEET_TEMPLATE)
+{
+ File = "ots_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_DRAWING)
+{
+ File = "odg_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_DRAWING)
+{
+ File = "odg_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_DRAWING)
+{
+ File = "odg_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_DRAWING_TEMPLATE)
+{
+ File = "otg_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_DRAWING_TEMPLATE)
+{
+ File = "otg_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_DRAWING_TEMPLATE)
+{
+ File = "otg_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_PRESENTATION)
+{
+ File = "odp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_PRESENTATION)
+{
+ File = "odp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_PRESENTATION)
+{
+ File = "odp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_PRESENTATION_TEMPLATE)
+{
+ File = "otp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_PRESENTATION_TEMPLATE)
+{
+ File = "otp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_PRESENTATION_TEMPLATE)
+{
+ File = "otp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_PRESENTATION_COMPRESSED)
+{
+ File = "odp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_PRESENTATION_COMPRESSED)
+{
+ File = "odp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_PRESENTATION_COMPRESSED)
+{
+ File = "odp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_MASTER_DOCUMENT)
+{
+ File = "odm_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_MASTER_DOCUMENT)
+{
+ File = "odm_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_MASTER_DOCUMENT)
+{
+ File = "odm_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_HTML_DOCUMENT)
+{
+ File = "oth_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_HTML_DOCUMENT)
+{
+ File = "oth_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_HTML_DOCUMENT)
+{
+ File = "oth_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_CHART)
+{
+ File = "mainapp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_CHART)
+{
+ File = "mainapp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_CHART)
+{
+ File = "mainapp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_DATABASE)
+{
+ File = "odb_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_DATABASE)
+{
+ File = "odb_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_DATABASE)
+{
+ File = "odb_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_FORMULA)
+{
+ File = "odf_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_FORMULA)
+{
+ File = "odf_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_FORMULA)
+{
+ File = "odf_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_TEMPLATE)
+{
+ File = "mainapp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_TEMPLATE)
+{
+ File = "mainapp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_TEMPLATE)
+{
+ File = "mainapp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_MACRO)
+{
+ File = "mainapp_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_MACRO)
+{
+ File = "mainapp_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_MACRO)
+{
+ File = "mainapp_16_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE48_START + SV_ICON_ID_PRINTERADMIN)
+{
+ File = "printeradmin_48_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE32_START + SV_ICON_ID_PRINTERADMIN)
+{
+ File = "printeradmin_32_8.png" ;
+};
+
+Bitmap (SV_ICON_SIZE16_START + SV_ICON_ID_PRINTERADMIN)
+{
+ File = "printeradmin_16_8.png" ;
+};
+
+// -----------------------------------------------------------------------
+
+
+Bitmap (SV_ICON_LARGE_START)
+{
+ File = "mainapp_32.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START)
+{
+ File = "mainapp_16.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START)
+{
+ File = "mainapp_32_h.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START)
+{
+ File = "mainapp_16_h.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_OFFICE)
+{
+ File = "mainapp_32.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_OFFICE)
+{
+ File = "mainapp_16.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_OFFICE)
+{
+ File = "mainapp_32_h.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_OFFICE)
+{
+ File = "mainapp_16_h" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_TEXT)
+{
+ File = "lx03251.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_TEXT)
+{
+ File = "sx03251.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_TEXT)
+{
+ File = "lxh03251.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_TEXT)
+{
+ File = "sxh03251.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_TEXT_TEMPLATE)
+{
+ File = "lx03255.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_TEXT_TEMPLATE)
+{
+ File = "sx03255.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_TEXT_TEMPLATE)
+{
+ File = "lxh03255.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_TEXT_TEMPLATE)
+{
+ File = "sxh03255.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_SPREADSHEET)
+{
+ File = "lx03250.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_SPREADSHEET)
+{
+ File = "sx03250.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_SPREADSHEET)
+{
+ File = "lxh03250.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_SPREADSHEET)
+{
+ File = "sxh03250.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_SPREADSHEET_TEMPLATE)
+{
+ File = "lx03254.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_SPREADSHEET_TEMPLATE)
+{
+ File = "sx03254.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_SPREADSHEET_TEMPLATE)
+{
+ File = "lxh03254.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_SPREADSHEET_TEMPLATE)
+{
+ File = "sxh03254.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_DRAWING)
+{
+ File = "lx03246.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_DRAWING)
+{
+ File = "sx03246.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_DRAWING)
+{
+ File = "lxh03246.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_DRAWING)
+{
+ File = "sxh03246.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_DRAWING_TEMPLATE)
+{
+ File = "lx03252.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_DRAWING_TEMPLATE)
+{
+ File = "sx03252.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_DRAWING_TEMPLATE)
+{
+ File = "lxh03252.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_DRAWING_TEMPLATE)
+{
+ File = "sxh03252.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_PRESENTATION)
+{
+ File = "lx03249.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_PRESENTATION)
+{
+ File = "sx03249.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_PRESENTATION)
+{
+ File = "lxh03249.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_PRESENTATION)
+{
+ File = "sxh03249.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_PRESENTATION_TEMPLATE)
+{
+ File = "lx03253.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_PRESENTATION_TEMPLATE)
+{
+ File = "sx03253.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_PRESENTATION_TEMPLATE)
+{
+ File = "lxh03253.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_PRESENTATION_TEMPLATE)
+{
+ File = "sxh03253.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_PRESENTATION_COMPRESSED)
+{
+ File = "lx03241.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_PRESENTATION_COMPRESSED)
+{
+ File = "sx03241.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_PRESENTATION_COMPRESSED)
+{
+ File = "lxh03241.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_PRESENTATION_COMPRESSED)
+{
+ File = "sxh03241.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_MASTER_DOCUMENT)
+{
+ File = "lx03248.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_MASTER_DOCUMENT)
+{
+ File = "sx03248.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_MASTER_DOCUMENT)
+{
+ File = "lxh03248.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_MASTER_DOCUMENT)
+{
+ File = "sxh03248.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_HTML_DOCUMENT)
+{
+ File = "lx03139.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_HTML_DOCUMENT)
+{
+ File = "sx03139.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_HTML_DOCUMENT)
+{
+ File = "lxh03139.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_HTML_DOCUMENT)
+{
+ File = "sxh03139.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_CHART)
+{
+ File = "lx03128.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_CHART)
+{
+ File = "sx03128.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_CHART)
+{
+ File = "lxh03128.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_CHART)
+{
+ File = "sxh03128.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_DATABASE)
+{
+ File = "lx03245.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_DATABASE)
+{
+ File = "sx03245.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_DATABASE)
+{
+ File = "lxh03245.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_DATABASE)
+{
+ File = "sxh03245.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_FORMULA)
+{
+ File = "lx03247.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_FORMULA)
+{
+ File = "sx03247.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_FORMULA)
+{
+ File = "lxh03247.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_FORMULA)
+{
+ File = "sxh03247.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_TEMPLATE)
+{
+ File = "lx03242.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_TEMPLATE)
+{
+ File = "sx03242.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_TEMPLATE)
+{
+ File = "lxh03242.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_TEMPLATE)
+{
+ File = "sxh03242.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_MACRO)
+{
+ File = "lx03216.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_MACRO)
+{
+ File = "sx03216.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_MACRO)
+{
+ File = "lxh03216.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_MACRO)
+{
+ File = "sxh03216.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_START + SV_ICON_ID_PRINTERADMIN)
+{
+ File = "printeradmin_32.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_START + SV_ICON_ID_PRINTERADMIN)
+{
+ File = "printeradmin_16.png" ;
+};
+
+Bitmap (SV_ICON_LARGE_HC_START + SV_ICON_ID_PRINTERADMIN)
+{
+ File = "printeradmin_32_h.png" ;
+};
+
+Bitmap (SV_ICON_SMALL_HC_START + SV_ICON_ID_PRINTERADMIN)
+{
+ File = "printeradmin_16_h.png" ;
+};
+
+Bitmap SV_DISCLOSURE_PLUS
+{
+ File = "plus.png";
+};
+
+Bitmap SV_DISCLOSURE_PLUS_HC
+{
+ File = "plus_sch.png";
+};
+
+Bitmap SV_DISCLOSURE_MINUS
+{
+ File = "minus.png";
+};
+
+Bitmap SV_DISCLOSURE_MINUS_HC
+{
+ File = "minus_sch.png";
+};
+
diff --git a/vcl/source/src/makefile.mk b/vcl/source/src/makefile.mk
new file mode 100644
index 000000000000..40b7d4e75dfe
--- /dev/null
+++ b/vcl/source/src/makefile.mk
@@ -0,0 +1,56 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=svsrc
+RESTARGET=vcl
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+SRS1NAME=$(TARGET)
+SRC1FILES= images.src \
+ menu.src \
+ stdtext.src \
+ helptext.src \
+ units.src \
+ btntext.src \
+ print.src
+
+RESLIB1NAME= $(RESTARGET)
+RESLIB1IMAGES= $(PRJ)$/source/src
+RESLIB1SRSFILES= $(SRS)$/svsrc.srs
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/source/src/menu.src b/vcl/source/src/menu.src
new file mode 100644
index 000000000000..1833093adfac
--- /dev/null
+++ b/vcl/source/src/menu.src
@@ -0,0 +1,107 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define _SV_MENU_SRC
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+
+String SV_RESID_STRING_NOSELECTIONPOSSIBLE
+{
+ Text [ en-US ] = "<No selection possible>";
+};
+
+Menu SV_RESID_MENU_EDIT
+{
+ ItemList =
+ {
+ MenuItem
+ {
+ Identifier = SV_MENU_EDIT_UNDO ;
+ Text [ en-US ] = "~Undo" ;
+ };
+ MenuItem { Separator = TRUE ; };
+ MenuItem
+ {
+ Identifier = SV_MENU_EDIT_CUT ;
+ Text [ en-US ] = "Cu~t" ;
+ };
+ MenuItem
+ {
+ Identifier = SV_MENU_EDIT_COPY ;
+ Text [ en-US ] = "~Copy" ;
+ };
+ MenuItem
+ {
+ Identifier = SV_MENU_EDIT_PASTE ;
+ Text [ en-US ] = "~Paste" ;
+ };
+ MenuItem
+ {
+ Identifier = SV_MENU_EDIT_DELETE ;
+ Text [ en-US ] = "~Delete" ;
+ };
+ MenuItem { Separator = TRUE ; };
+ MenuItem
+ {
+ Identifier = SV_MENU_EDIT_SELECTALL ;
+ Text [ en-US ] = "Select ~All" ;
+ };
+ MenuItem { Separator = TRUE ; };
+ MenuItem
+ {
+ Identifier = SV_MENU_EDIT_INSERTSYMBOL;
+ Text [ en-US ] = "~Special Character...";
+
+ };
+ };
+};
+
+String SV_MENU_MAC_SERVICES
+{
+ Text [ en-US ] = "Services";
+};
+
+String SV_MENU_MAC_HIDEAPP
+{
+ Text [ en-US ] = "Hide %PRODUCTNAME";
+};
+
+String SV_MENU_MAC_HIDEALL
+{
+ Text [ en-US ] = "Hide Others";
+};
+
+String SV_MENU_MAC_SHOWALL
+{
+ Text [ en-US ] = "Show All";
+};
+
+String SV_MENU_MAC_QUITAPP
+{
+ Text [ en-US ] = "Quit %PRODUCTNAME";
+};
+
diff --git a/vcl/source/src/print.src b/vcl/source/src/print.src
new file mode 100644
index 000000000000..58f0a477c848
--- /dev/null
+++ b/vcl/source/src/print.src
@@ -0,0 +1,492 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "vcl/svids.hrc"
+
+ModalDialog SV_DLG_PRINT
+{
+ Text [en-US] = "Print";
+ Closeable = TRUE;
+ Sizeable = TRUE;
+ Moveable = TRUE;
+ Maxable = TRUE;
+ SVLook = TRUE;
+
+ Size = MAP_APPFONT( 350, 215 );
+
+ OKButton SV_PRINT_OK
+ {
+ DefButton = TRUE;
+ Pos = MAP_APPFONT( 240, 195 );
+ Size = MAP_APPFONT( 50, 15 );
+ Text [en-US] = "~Print";
+ };
+ CancelButton SV_PRINT_CANCEL
+ {
+ Pos = MAP_APPFONT( 295, 195 );
+ Size = MAP_APPFONT( 50, 15 );
+ };
+ HelpButton SV_PRINT_HELP
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 50, 15 );
+ };
+
+ Window SV_PRINT_PAGE_PREVIEW
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 130, 130 );
+ Border = FALSE;
+ };
+ NumericField SV_PRINT_PAGE_EDIT
+ {
+ Pos = MAP_APPFONT( 5, 140 );
+ Size = MAP_APPFONT( 30, 12 );
+ SVLook = TRUE;
+ Spin = FALSE;
+ Border = TRUE;
+ HelpText [en-US] = "Select page to display in preview.";
+ };
+ FixedText SV_PRINT_PAGE_TXT
+ {
+ Pos = MAP_APPFONT( 40,142 );
+ Size = MAP_APPFONT( 30, 12 );
+ Text [ en-US ] = "/ %n";
+ VCenter = TRUE;
+ };
+ PushButton SV_PRINT_PAGE_FORWARD
+ {
+ Pos = MAP_APPFONT( 95, 140 );
+ Size = MAP_APPFONT( 15, 12 );
+ HelpText [en-US] = "Scroll one page forward.";
+ };
+ PushButton SV_PRINT_PAGE_BACKWARD
+ {
+ Pos = MAP_APPFONT( 80, 140 );
+ Size = MAP_APPFONT( 15, 12 );
+ HelpText [en-US] = "Scroll one page backward.";
+ };
+ TabControl SV_PRINT_TABCTRL
+ {
+ Pos = MAP_APPFONT( 140, 5 );
+ Size = MAP_APPFONT( 205, 175 );
+ };
+ FixedLine SV_PRINT_BUTTONLINE
+ {
+ Pos = MAP_APPFONT( 0, 185 );
+ Size = MAP_APPFONT( 350, 8 );
+ };
+ String SV_PRINT_NOPAGES
+ {
+ Text [en-US] = "No pages";
+ };
+
+ String SV_PRINT_TOFILE_TXT
+ {
+ Text [en-US] = "Print to File...";
+ };
+
+ String SV_PRINT_DEFPRT_TXT
+ {
+ Text [en-US] = "Default printer";
+ };
+
+
+ String SV_PRINT_PRINTPREVIEW_TXT
+ {
+ Text [en-US] = "Print preview";
+ };
+
+ TabPage SV_PRINT_TAB_NUP
+ {
+ Text [en-US] = "Page Layout";
+ Hide = TRUE;
+
+ FixedLine SV_PRINT_PRT_NUP_LAYOUT_FL
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 150, 10 );
+ Text [en-US] = "Layout";
+ };
+ RadioButton SV_PRINT_PRT_NUP_DEFAULT_BTN
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 10 );
+ Text [en-US] = "~Default";
+ HelpText [en-US] = "Print one page per sheet of paper.";
+ };
+ RadioButton SV_PRINT_PRT_NUP_BROCHURE_BTN
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 10 );
+ Text = "";
+ };
+ RadioButton SV_PRINT_PRT_NUP_PAGES_BTN
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 10 );
+ Text [en-US] = "Pa~ges per sheet";
+ HelpText [en-US] = "Print multiple pages per sheet of paper.";
+ };
+ ListBox SV_PRINT_PRT_NUP_PAGES_BOX
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 80 );
+ Border = TRUE;
+ DropDown = TRUE;
+ CurPos = 0;
+ HelpText [en-US] = "Select how many pages to print per sheet of paper.";
+ StringList [en-US] =
+ {
+ < "1"; 1; >;
+ < "2"; 2; >;
+ < "4"; 4; >;
+ < "6"; 6; >;
+ < "9"; 9; >;
+ < "16"; 16; >;
+ < "Custom"; 0xffff; >;
+ };
+ };
+ FixedText SV_PRINT_PRT_NUP_NUM_PAGES_TXT
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 10 );
+ Text [en-US] = "P~ages";
+ VCenter = TRUE;
+ };
+ NumericField SV_PRINT_PRT_NUP_COLS_EDT
+ {
+ Pos = MAP_APPFONT( 55, 20 );
+ Size = MAP_APPFONT( 40, 12 );
+ Border = TRUE;
+ Spin = TRUE;
+ Minimum = 1;
+ Maximum = 32;
+ Value = 1;
+ HelpText [en-US] = "Select number of columns.";
+ };
+ FixedText SV_PRINT_PRT_NUP_TIMES_TXT
+ {
+ Pos = MAP_APPFONT( 10, 35 );
+ Size = MAP_APPFONT( 40, 10 );
+ Text [en-US] = "b~y";
+ VCenter = TRUE;
+ };
+ NumericField SV_PRINT_PRT_NUP_ROWS_EDT
+ {
+ Pos = MAP_APPFONT( 55, 35 );
+ Size = MAP_APPFONT( 40, 12 );
+ Border = TRUE;
+ Spin = TRUE;
+ Minimum = 1;
+ Maximum = 32;
+ Value = 1;
+ HelpText [en-US] = "Select number of rows.";
+ };
+ FixedText SV_PRINT_PRT_NUP_MARGINS_PAGES_1_TXT
+ {
+ Pos = MAP_APPFONT( 10, 95 );
+ Size = MAP_APPFONT( 40, 10 );
+ Text [en-US] = "~Distance";
+ };
+ MetricField SV_PRINT_PRT_NUP_MARGINS_PAGES_EDT
+ {
+ Pos = MAP_APPFONT( 55, 95 );
+ Size = MAP_APPFONT( 40, 12 );
+ Spin = TRUE;
+ Border = TRUE;
+ Value = 0;
+ Unit = FUNIT_MM;
+ HelpText [en-US] = "Select margin between individual pages on each sheet of paper.";
+ };
+ FixedText SV_PRINT_PRT_NUP_MARGINS_PAGES_2_TXT
+ {
+ Pos = MAP_APPFONT( 10, 95 );
+ Size = MAP_APPFONT( 40, 10 );
+ Text [en-US] = "between pages";
+ };
+ FixedText SV_PRINT_PRT_NUP_MARGINS_SHEET_1_TXT
+ {
+ Pos = MAP_APPFONT( 110, 95 );
+ Size = MAP_APPFONT( 40, 10 );
+ Text [en-US] = "~Margin";
+ };
+ MetricField SV_PRINT_PRT_NUP_MARGINS_SHEET_EDT
+ {
+ Pos = MAP_APPFONT( 155, 95 );
+ Size = MAP_APPFONT( 40, 12 );
+ Spin = TRUE;
+ Border = TRUE;
+ Value = 0;
+ Unit = FUNIT_MM;
+ HelpText [en-US] = "Select margin between the printed pages and paper edge.";
+ };
+ FixedText SV_PRINT_PRT_NUP_MARGINS_SHEET_2_TXT
+ {
+ Pos = MAP_APPFONT( 110, 95 );
+ Size = MAP_APPFONT( 40, 10 );
+ Text [en-US] = "to sheet border";
+ };
+ FixedText SV_PRINT_PRT_NUP_ORIENTATION_TXT
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 10 );
+ Text [en-US] = "~Orientation";
+ };
+ ListBox SV_PRINT_PRT_NUP_ORIENTATION_BOX
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 40 );
+ Border = TRUE;
+ DropDown = TRUE;
+ CurPos = 0;
+ StringList [en-US] =
+ {
+ < "Automatic"; SV_PRINT_PRT_NUP_ORIENTATION_AUTOMATIC; >;
+ < "Portrait"; SV_PRINT_PRT_NUP_ORIENTATION_PORTRAIT; >;
+ < "Landscape"; SV_PRINT_PRT_NUP_ORIENTATION_LANDSCAPE; >;
+ };
+ HelpText [en-US] = "Select the orientation of the paper.";
+ };
+ FixedText SV_PRINT_PRT_NUP_ORDER_TXT
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 10 );
+ Text [en-US] = "Order";
+ };
+ ListBox SV_PRINT_PRT_NUP_ORDER_BOX
+ {
+ Pos = MAP_APPFONT( 0, 0 );
+ Size = MAP_APPFONT( 10, 20 );
+ DropDown = TRUE;
+ Border = TRUE;
+ CurPos = 0;
+ StringList [en-US] =
+ {
+ < "left to right, then down"; SV_PRINT_PRT_NUP_ORDER_LRTD; >;
+ < "top to bottom, then right"; SV_PRINT_PRT_NUP_ORDER_TDLR; >;
+ };
+ HelpText [en-US] = "Select order in which pages are to be printed.";
+ };
+ CheckBox SV_PRINT_PRT_NUP_BORDER_CB
+ {
+ Pos = MAP_APPFONT( 10, 65 );
+ Size = MAP_APPFONT( 150, 12 );
+ Text [en-US] = "Draw a border around each page";
+ HelpText [en-US] = "Check to draw a border around each page.";
+ };
+ };
+
+ TabPage SV_PRINT_TAB_JOB
+ {
+ Text [en-US] = "General";
+ Hide = TRUE;
+
+ FixedLine SV_PRINT_PRINTERS_FL
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 100, 10 );
+ Text [ en-US ] = "Prin~ter";
+ };
+ ListBox SV_PRINT_PRINTERS
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 100, 80 );
+ Border = TRUE;
+ Sort = TRUE;
+ HelpText [en-US] = "Select the printer to print on.";
+ };
+ CheckBox SV_PRINT_DETAILS_BTN
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 5, 5 );
+ Text [en-US] = "Details";
+ HelpText [en-US] = "Show/Hide detailed information of the selected printer.";
+ };
+ FixedText SV_PRINT_STATUS_TXT
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 100, 10 );
+ Text [en-US] = "Status:";
+ };
+ FixedText SV_PRINT_LOCATION_TXT
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 100, 10 );
+ Text [en-US] = "Location:";
+ };
+ FixedText SV_PRINT_COMMENT_TXT
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 100, 10 );
+ Text [en-US] = "Comment:";
+ };
+ PushButton SV_PRINT_PRT_SETUP
+ {
+ Pos = MAP_APPFONT( 115, 5 );
+ Size = MAP_APPFONT( 50, 15 );
+ Text [en-US] = "Properties...";
+ HelpText [en-US] = "Call the setup dialog of the selected printer.";
+ };
+ FixedLine SV_PRINT_COPIES
+ {
+ Pos = MAP_APPFONT( 5, 35 );
+ Size = MAP_APPFONT( 150, 10 );
+ Text [en-US] = "Range and copies";
+ };
+ FixedText SV_PRINT_COPYCOUNT
+ {
+ Pos = MAP_APPFONT( 10, 45 );
+ Size = MAP_APPFONT( 80, 10 );
+ Text [en-US] = "Number of copies";
+ };
+ NumericField SV_PRINT_COPYCOUNT_FIELD
+ {
+ Pos = MAP_APPFONT( 10, 56 );
+ Size = MAP_APPFONT( 40, 12 );
+ Border = TRUE;
+ Spin = TRUE;
+ Minimum = 1;
+ Maximum = 16384;
+ Value = 1;
+ HelpText [en-US] = "Select the number of copies to be produced.";
+ };
+ FixedImage SV_PRINT_COLLATE_IMAGE
+ {
+ Pos = MAP_APPFONT( 95, 60 );
+ Size = MAP_PIXEL( 80, 30 );
+ };
+ CheckBox SV_PRINT_COLLATE
+ {
+ Pos = MAP_APPFONT( 95, 45 );
+ Size = MAP_APPFONT( 70, 10 );
+ Text [en-US] = "Collate";
+ HelpText [en-US] = "Select whether copies should be collated or not.";
+ };
+
+ Image SV_PRINT_COLLATE_IMG
+ {
+ ImageBitmap = Bitmap { File = "collate.png" ; };
+ };
+
+ Image SV_PRINT_NOCOLLATE_IMG
+ {
+ ImageBitmap = Bitmap { File = "ncollate.png" ; };
+ };
+
+ Image SV_PRINT_COLLATE_HC_IMG
+ {
+ ImageBitmap = Bitmap { File = "collate_h.png" ; };
+ };
+
+ Image SV_PRINT_NOCOLLATE_HC_IMG
+ {
+ ImageBitmap = Bitmap { File = "ncollate_h.png" ; };
+ };
+ };
+
+ TabPage SV_PRINT_TAB_OPT
+ {
+ Text [en-US] = "Options";
+ Hide = TRUE;
+
+ FixedLine SV_PRINT_OPT_PRINT_FL
+ {
+ Pos = MAP_APPFONT( 5, 5 );
+ Size = MAP_APPFONT( 150, 10 );
+ Text [en-US] = "Options";
+ };
+ CheckBox SV_PRINT_OPT_TOFILE
+ {
+ Pos = MAP_APPFONT( 10, 20 );
+ Size = MAP_APPFONT( 200, 12 );
+ Text [en-US] = "Print to ~file";
+ HelpText [en-US] = "Check to send output to a file instead of the actual printer.";
+ };
+ CheckBox SV_PRINT_OPT_SINGLEJOBS
+ {
+ Pos = MAP_APPFONT( 10, 35 );
+ Size = MAP_APPFONT( 200, 12 );
+ Text [en-US] = "~Create single print jobs for collated output";
+ HelpText [en-US] = "Check to not rely on the printer to create collated copies but create a print job for each copy instead.";
+ };
+ CheckBox SV_PRINT_OPT_REVERSE
+ {
+ Pos = MAP_APPFONT( 10, 50 );
+ Size = MAP_APPFONT( 200, 12 );
+ Text [en-US] = "Print in ~reverse page order";
+ HelpText [en-US] = "Check to print pages in reverse order.";
+ };
+ };
+};
+
+ModelessDialog SV_DLG_PRINT_PROGRESS
+{
+ Text [en-US] = "Printing";
+ Closeable = FALSE;
+ Sizeable = FALSE;
+ Moveable = TRUE;
+ SVLook = TRUE;
+
+ Size = MAP_APPFONT( 120, 70 );
+
+ CancelButton SV_PRINT_PROGRESS_CANCEL
+ {
+ Pos = MAP_APPFONT( 35, 50 );
+ Size = MAP_APPFONT( 50, 15 );
+ };
+ FixedText SV_PRINT_PROGRESS_TEXT
+ {
+ Pos = MAP_APPFONT( 5,10 );
+ Size = MAP_APPFONT( 110, 10 );
+ Text [ en-US ] = "Page %p of %n";
+ Center = TRUE;
+ };
+};
+
+ErrorBox SV_PRINT_NOPRINTERWARNING
+{
+ Title = "%PRODUCTNAME";
+ Message [en-US] = "No default printer found.\nPlease choose a printer and try again.";
+};
+
+ErrorBox SV_PRINT_NOCONTENT
+{
+ Title = "%PRODUCTNAME";
+ Message [en-US] = "There are no pages to be printed. Please check your document for ranges relevant to printing.";
+};
+
+StringArray SV_PRINT_NATIVE_STRINGS
+{
+ ItemList [en-US] =
+ {
+ < "Preview"; >;
+ < "Page number"; >;
+ < "Number of pages"; >;
+ < "More"; >;
+ };
+};
diff --git a/vcl/source/src/stdtext.src b/vcl/source/src/stdtext.src
new file mode 100644
index 000000000000..2c6574220a5f
--- /dev/null
+++ b/vcl/source/src/stdtext.src
@@ -0,0 +1,127 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define _SV_STDTEXT_SRC
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+
+String SV_STDTEXT_SERVICENOTAVAILABLE
+{
+ Text [ en-US ] = "The component (%s) could not be loaded.\nPlease start setup with the repair option.";
+};
+
+String SV_STDTEXT_DONTHINTAGAIN
+{
+ Text [ en-US ] = "Do not show this information again.";
+};
+
+String SV_STDTEXT_DONTASKAGAIN
+{
+ Text [ en-US ] = "Do not show this question again.";
+};
+
+String SV_STDTEXT_DONTWARNAGAIN
+{
+ Text [ en-US ] = "Do not show warning again.";
+};
+
+String SV_ACCESSERROR_WRONG_VERSION
+{
+ Text [ en-US ] = "Wrong Version";
+};
+
+String SV_ACCESSERROR_BRIDGE_MSG
+{
+ Text [ en-US ] = "%PRODUCTNAME %PRODUCTVERSION requires a Java Access Bridge 1.0.3 or later version to support accessibility.";
+};
+
+String SV_ACCESSERROR_OK_CANCEL_MSG
+{
+ Text [ en-US ] = "Click '%OK' to start %PRODUCTNAME %PRODUCTVERSION without accessibility support, or click '%CANCEL' to exit %PRODUCTNAME %PRODUCTVERSION.";
+};
+
+String SV_ACCESSERROR_MISSING_BRIDGE
+{
+ Text [ en-US ] = "No Java Access Bridge";
+};
+
+String SV_ACCESSERROR_FAULTY_JAVA
+{
+ Text [ en-US ] = "Faulty Java Installation";
+};
+
+String SV_ACCESSERROR_JAVA_MSG
+{
+ Text [ en-US ] = "%PRODUCTNAME %PRODUCTVERSION requires Java 1.4.0_02 or later version to support accessibility.";
+};
+
+String SV_ACCESSERROR_MISSING_JAVA
+{
+ Text [ en-US ] = "No Java Installation";
+};
+
+String SV_ACCESSERROR_JAVA_NOT_CONFIGURED
+{
+ Text [ en-US ] = "Missing Java Configuration";
+};
+
+String SV_ACCESSERROR_JAVA_DISABLED
+{
+ Text [ en-US ] = "Java Disabled";
+};
+
+String SV_ACCESSERROR_TURNAROUND_MSG
+{
+ Text [ en-US ] = "The Java Access Bridge could not be started.";
+};
+
+String SV_STDTEXT_ABOUT
+{
+ Text [ en-US ] = "About %PRODUCTNAME";
+};
+
+String SV_STDTEXT_PREFERENCES
+{
+ Text [ en-US ] = "Preferences...";
+};
+
+WarningBox SV_EDIT_WARNING_BOX
+{
+ Message [en-US] = "The inserted text exceeded the maximum length of this text field. The text was truncated.";
+};
+
+String SV_MAC_SCREENNNAME
+{
+ Text [en-US] = "Screen %d";
+};
+
+String SV_STDTEXT_ALLFILETYPES
+{
+ Text [en-US] = "Any type";
+};
diff --git a/vcl/source/src/units.src b/vcl/source/src/units.src
new file mode 100644
index 000000000000..16b40b3f41a3
--- /dev/null
+++ b/vcl/source/src/units.src
@@ -0,0 +1,57 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define _SV_UNITS_SRC
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+
+StringArray SV_FUNIT_STRINGS
+{
+ ItemList [ en-US ] =
+ {
+ < "mm" ; FUNIT_MM ; > ;
+ < "cm" ; FUNIT_CM ; > ;
+ < "m" ; FUNIT_M ; > ;
+ < "km" ; FUNIT_KM ; > ;
+ < "twips" ; FUNIT_TWIP ; > ;
+ < "twip" ; FUNIT_TWIP ; > ;
+ < "pt" ; FUNIT_POINT ; > ;
+ < "pi" ; FUNIT_PICA ; > ;
+ < "\"" ; FUNIT_INCH ; > ;
+ < "in" ; FUNIT_INCH ; > ;
+ < "inch" ; FUNIT_INCH ; > ;
+ < "'" ; FUNIT_FOOT ; > ;
+ < "ft" ; FUNIT_FOOT ; > ;
+ < "foot" ; FUNIT_FOOT ; > ;
+ < "feet" ; FUNIT_FOOT ; > ;
+ < "miles" ; FUNIT_MILE ; > ;
+ < "mile" ; FUNIT_MILE ; > ;
+ < "%" ; FUNIT_PERCENT ; > ;
+ };
+};
+
diff --git a/vcl/source/window/abstdlg.cxx b/vcl/source/window/abstdlg.cxx
new file mode 100644
index 000000000000..7f00b73b0808
--- /dev/null
+++ b/vcl/source/window/abstdlg.cxx
@@ -0,0 +1,64 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/abstdlg.hxx>
+#include "cuilib.hxx"
+
+#include <osl/module.hxx>
+#include <tools/string.hxx>
+
+typedef VclAbstractDialogFactory* (__LOADONCALLAPI *FuncPtrCreateDialogFactory)();
+
+extern "C" { static void SAL_CALL thisModule() {} }
+
+VclAbstractDialogFactory* VclAbstractDialogFactory::Create()
+{
+ FuncPtrCreateDialogFactory fp = 0;
+ static ::osl::Module aDialogLibrary;
+ if ( aDialogLibrary.is() || aDialogLibrary.loadRelative( &thisModule, String( RTL_CONSTASCII_USTRINGPARAM( DLL_NAME ) ) ) )
+ fp = ( VclAbstractDialogFactory* (__LOADONCALLAPI*)() )
+ aDialogLibrary.getFunctionSymbol( ::rtl::OUString::createFromAscii("CreateDialogFactory") );
+ if ( fp )
+ return fp();
+ return 0;
+}
+
+VclAbstractDialog::~VclAbstractDialog()
+{
+}
+
+// virtual
+VclAbstractDialog2::~VclAbstractDialog2()
+{
+}
+
+VclAbstractDialogFactory::~VclAbstractDialogFactory()
+{
+}
diff --git a/vcl/source/window/accel.cxx b/vcl/source/window/accel.cxx
new file mode 100644
index 000000000000..3018236fff1a
--- /dev/null
+++ b/vcl/source/window/accel.cxx
@@ -0,0 +1,731 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/list.hxx>
+#ifndef _TABLE_HXX
+#include <tools/table.hxx>
+#endif
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/accel.h>
+#include <vcl/accel.hxx>
+#ifndef _RC_H
+#include <tools/rc.h>
+#endif
+
+
+
+// =======================================================================
+
+DECLARE_TABLE( ImplAccelTable, ImplAccelEntry* )
+DECLARE_LIST( ImplAccelList, ImplAccelEntry* )
+
+#define ACCELENTRY_NOTFOUND ((USHORT)0xFFFF)
+
+// =======================================================================
+
+class ImplAccelData
+{
+public:
+ ImplAccelTable maKeyTable; // Fuer KeyCodes, die mit einem Code erzeugt wurden
+ ImplAccelList maIdList; // Id-List
+};
+
+// =======================================================================
+
+DBG_NAME( Accelerator )
+
+// =======================================================================
+
+USHORT ImplAccelEntryGetIndex( ImplAccelList* pList, USHORT nId,
+ USHORT* pIndex = NULL )
+{
+ ULONG nLow;
+ ULONG nHigh;
+ ULONG nMid;
+ ULONG nCount = pList->Count();
+ USHORT nCompareId;
+
+ // Abpruefen, ob der erste Key groesser als der Vergleichskey ist
+ if ( !nCount || (nId < pList->GetObject( 0 )->mnId) )
+ {
+ if ( pIndex )
+ *pIndex = 0;
+ return ACCELENTRY_NOTFOUND;
+ }
+
+ // Binaeres Suchen
+ nLow = 0;
+ nHigh = nCount-1;
+ do
+ {
+ nMid = (nLow + nHigh) / 2;
+ nCompareId = pList->GetObject( nMid )->mnId;
+ if ( nId < nCompareId )
+ nHigh = nMid-1;
+ else
+ {
+ if ( nId > nCompareId )
+ nLow = nMid + 1;
+ else
+ return (USHORT)nMid;
+ }
+ }
+ while ( nLow <= nHigh );
+
+ if ( pIndex )
+ {
+ if ( nId > nCompareId )
+ *pIndex = (USHORT)(nMid+1);
+ else
+ *pIndex = (USHORT)nMid;
+ }
+
+ return ACCELENTRY_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplAccelEntryInsert( ImplAccelList* pList, ImplAccelEntry* pEntry )
+{
+ USHORT nInsIndex;
+ USHORT nIndex = ImplAccelEntryGetIndex( pList, pEntry->mnId, &nInsIndex );
+
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ {
+ do
+ {
+ nIndex++;
+ ImplAccelEntry* pTempEntry = pList->GetObject( nIndex );
+ if ( !pTempEntry || (pTempEntry->mnId != pEntry->mnId) )
+ break;
+ }
+ while ( nIndex < pList->Count() );
+
+ pList->Insert( pEntry, (ULONG)nIndex );
+ }
+ else
+ pList->Insert( pEntry, (ULONG)nInsIndex );
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplAccelEntryGetFirstPos( ImplAccelList* pList, USHORT nId )
+{
+ USHORT nIndex = ImplAccelEntryGetIndex( pList, nId );
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ {
+ while ( nIndex )
+ {
+ nIndex--;
+ if ( pList->GetObject( nIndex )->mnId != nId )
+ break;
+ }
+
+ if ( pList->GetObject( nIndex )->mnId != nId )
+ nIndex++;
+ }
+
+ return nIndex;
+}
+
+// =======================================================================
+
+void Accelerator::ImplInit()
+{
+ mnCurId = 0;
+ mnCurRepeat = 0;
+ mbIsCancel = FALSE;
+ mpDel = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplAccelEntry* Accelerator::ImplGetAccelData( const KeyCode& rKeyCode ) const
+{
+ return mpData->maKeyTable.Get( rKeyCode.GetFullKeyCode() );
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::ImplCopyData( ImplAccelData& rAccelData )
+{
+ // Tabellen kopieren
+ ImplAccelEntry* pEntry = rAccelData.maIdList.First();
+ while ( pEntry )
+ {
+ pEntry = new ImplAccelEntry( *pEntry );
+
+ // Folge-Accelerator, dann auch kopieren
+ if ( pEntry->mpAccel )
+ {
+ pEntry->mpAccel = new Accelerator( *(pEntry->mpAccel) );
+ pEntry->mpAutoAccel = pEntry->mpAccel;
+ }
+ else
+ pEntry->mpAutoAccel = NULL;
+
+ mpData->maKeyTable.Insert( (ULONG)pEntry->maKeyCode.GetFullKeyCode(), pEntry );
+ mpData->maIdList.Insert( pEntry, LIST_APPEND );
+
+ pEntry = rAccelData.maIdList.Next();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::ImplDeleteData()
+{
+ // Accelerator-Eintraege ueber die Id-Tabelle loeschen
+ ImplAccelEntry* pEntry = mpData->maIdList.First();
+ while ( pEntry )
+ {
+ // AutoResAccel zerstoeren
+ if ( pEntry->mpAutoAccel )
+ delete pEntry->mpAutoAccel;
+ delete pEntry;
+
+ pEntry = mpData->maIdList.Next();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::ImplInsertAccel( USHORT nItemId, const KeyCode& rKeyCode,
+ BOOL bEnable, Accelerator* pAutoAccel )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+ DBG_ASSERT( nItemId, "Accelerator::InsertItem(): ItemId == 0" );
+
+ if ( rKeyCode.IsFunction() )
+ {
+ USHORT nCode1;
+ USHORT nCode2;
+ USHORT nCode3;
+ USHORT nCode4;
+ ImplGetKeyCode( rKeyCode.GetFunction(), nCode1, nCode2, nCode3, nCode4 );
+ if ( nCode1 )
+ ImplInsertAccel( nItemId, KeyCode( nCode1, nCode1 ), bEnable, pAutoAccel );
+ if ( nCode2 )
+ {
+ if ( pAutoAccel )
+ pAutoAccel = new Accelerator( *pAutoAccel );
+ ImplInsertAccel( nItemId, KeyCode( nCode2, nCode2 ), bEnable, pAutoAccel );
+ if ( nCode3 )
+ {
+ if ( pAutoAccel )
+ pAutoAccel = new Accelerator( *pAutoAccel );
+ ImplInsertAccel( nItemId, KeyCode( nCode3, nCode3 ), bEnable, pAutoAccel );
+ }
+ }
+ return;
+ }
+
+ // Neuen Eintrag holen und fuellen
+ ImplAccelEntry* pEntry = new ImplAccelEntry;
+ pEntry->mnId = nItemId;
+ pEntry->maKeyCode = rKeyCode;
+ pEntry->mpAccel = pAutoAccel;
+ pEntry->mpAutoAccel = pAutoAccel;
+ pEntry->mbEnabled = bEnable;
+
+ // Ab in die Tabellen
+ ULONG nCode = rKeyCode.GetFullKeyCode();
+ if ( !nCode )
+ {
+ DBG_ERROR( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
+ delete pEntry;
+ }
+ else if ( !mpData->maKeyTable.Insert( nCode, pEntry ) )
+ {
+ DBG_ERROR1( "Accelerator::InsertItem(): KeyCode (Key: %lx) already exists", nCode );
+ delete pEntry;
+ }
+ else
+ ImplAccelEntryInsert( &(mpData->maIdList), pEntry );
+}
+
+// -----------------------------------------------------------------------
+
+Accelerator::Accelerator()
+{
+ DBG_CTOR( Accelerator, NULL );
+
+ ImplInit();
+ mpData = new ImplAccelData;
+}
+
+// -----------------------------------------------------------------------
+
+Accelerator::Accelerator( const Accelerator& rAccel ) :
+ Resource(),
+ maHelpStr( rAccel.maHelpStr ),
+ maCurKeyCode( rAccel.maCurKeyCode )
+{
+ DBG_CTOR( Accelerator, NULL );
+ DBG_CHKOBJ( &rAccel, Accelerator, NULL );
+
+ ImplInit();
+ mpData = new ImplAccelData;
+ ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
+}
+
+// -----------------------------------------------------------------------
+
+Accelerator::Accelerator( const ResId& rResId )
+{
+ DBG_CTOR( Accelerator, NULL );
+
+ ImplInit();
+ mpData = new ImplAccelData;
+ rResId.SetRT( RSC_ACCEL );
+ ImplLoadRes( rResId );
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::ImplLoadRes( const ResId& rResId )
+{
+ GetRes( rResId );
+
+ maHelpStr = ReadStringRes();
+ ULONG nObjFollows = ReadLongRes();
+
+ for( ULONG i = 0; i < nObjFollows; i++ )
+ {
+ InsertItem( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Accelerator::~Accelerator()
+{
+ DBG_DTOR( Accelerator, NULL );
+
+ // AccelManager benachrichtigen, das Accelrator geloescht wurde
+ if ( mpDel )
+ *mpDel = TRUE;
+
+ ImplDeleteData();
+ delete mpData;
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::Activate()
+{
+ maActivateHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::Deactivate()
+{
+ maDeactivateHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::Select()
+{
+ maSelectHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::InsertItem( USHORT nItemId, const KeyCode& rKeyCode )
+{
+ ImplInsertAccel( nItemId, rKeyCode, TRUE, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::InsertItem( const ResId& rResId )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ULONG nObjMask;
+ USHORT nAccelKeyId;
+ USHORT bDisable;
+ KeyCode aKeyCode;
+ Accelerator* pAutoAccel = NULL;
+
+ GetRes( rResId.SetRT( RSC_ACCELITEM ) );
+ nObjMask = ReadLongRes();
+ nAccelKeyId = sal::static_int_cast<USHORT>(ReadLongRes());
+ bDisable = ReadShortRes();
+
+ if ( nObjMask & ACCELITEM_KEY )
+ {
+ // es wird ein neuer Kontext aufgespannt
+ RSHEADER_TYPE * pKeyCodeRes = (RSHEADER_TYPE *)GetClassRes();
+ ResId aResId( pKeyCodeRes, *rResId.GetResMgr());
+ aKeyCode = KeyCode( aResId );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+
+ if ( nObjMask & ACCELITEM_ACCEL )
+ {
+ pAutoAccel = new Accelerator( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+
+ ImplInsertAccel( nAccelKeyId, aKeyCode, !bDisable, pAutoAccel );
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::RemoveItem( USHORT nItemId )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ // Aus der Id-Liste entfernen
+ USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ {
+ USHORT nItemCount = GetItemCount();
+ do
+ {
+ ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex );
+ if ( pEntry && pEntry->mnId == nItemId )
+ {
+ mpData->maKeyTable.Remove( pEntry->maKeyCode.GetFullKeyCode() );
+ mpData->maIdList.Remove( (ULONG)nIndex );
+
+ // AutoResAccel zerstoeren
+ if ( pEntry->mpAutoAccel )
+ delete pEntry->mpAutoAccel;
+
+ delete pEntry;
+ }
+ else
+ break;
+ }
+ while ( nIndex < nItemCount );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::RemoveItem( const KeyCode rKeyCode )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ {
+ // Aus der Id-Liste entfernen
+ USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), pEntry->mnId );
+ USHORT nItemCount = GetItemCount();
+ do
+ {
+ if ( mpData->maIdList.GetObject( (ULONG)nIndex ) == pEntry )
+ break;
+ nIndex++;
+ }
+ while ( nIndex < nItemCount );
+
+ mpData->maKeyTable.Remove( rKeyCode.GetFullKeyCode() );
+ mpData->maIdList.Remove( (ULONG)nIndex );
+
+ // AutoResAccel zerstoeren
+ if ( pEntry->mpAutoAccel )
+ delete pEntry->mpAutoAccel;
+
+ delete pEntry;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::Clear()
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplDeleteData();
+ mpData->maKeyTable.Clear();
+ mpData->maIdList.Clear();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Accelerator::GetItemCount() const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ return (USHORT)mpData->maIdList.Count();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Accelerator::GetItemId( USHORT nPos ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nPos );
+ if ( pEntry )
+ return pEntry->mnId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+KeyCode Accelerator::GetItemKeyCode( USHORT nPos ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nPos );
+ if ( pEntry )
+ return pEntry->maKeyCode;
+ else
+ return KeyCode();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Accelerator::GetItemId( const KeyCode& rKeyCode ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ return pEntry->mnId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+KeyCode Accelerator::GetKeyCode( USHORT nItemId ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ return mpData->maIdList.GetObject( (ULONG)nIndex )->maKeyCode;
+ else
+ return KeyCode();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Accelerator::IsIdValid( USHORT nItemId ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
+ return (nIndex != ACCELENTRY_NOTFOUND);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Accelerator::IsKeyCodeValid( const KeyCode rKeyCode ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ return (pEntry != NULL);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Accelerator::Call( const KeyCode& rKeyCode, USHORT nRepeat )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ {
+ if ( pEntry->mbEnabled )
+ {
+ BOOL bDel = FALSE;
+ mnCurId = pEntry->mnId;
+ maCurKeyCode = rKeyCode;
+ mnCurRepeat = nRepeat;
+ mpDel = &bDel;
+ Select();
+ if ( !bDel )
+ {
+ mnCurId = 0;
+ maCurKeyCode = KeyCode();
+ mnCurRepeat = 0;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::SetAccel( USHORT nItemId, Accelerator* pAccel )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ {
+ USHORT nItemCount = GetItemCount();
+ do
+ {
+ ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex );
+ if ( pEntry->mnId != nItemId )
+ break;
+
+ pEntry->mpAccel = pAccel;
+ nIndex++;
+ }
+ while ( nIndex < nItemCount );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Accelerator* Accelerator::GetAccel( USHORT nItemId ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ return mpData->maIdList.GetObject( (ULONG)nIndex )->mpAccel;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::SetAccel( const KeyCode rKeyCode, Accelerator* pAccel )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ pEntry->mpAccel = pAccel;
+}
+
+// -----------------------------------------------------------------------
+
+Accelerator* Accelerator::GetAccel( const KeyCode rKeyCode ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ return pEntry->mpAccel;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::EnableItem( USHORT nItemId, BOOL bEnable )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ {
+ USHORT nItemCount = GetItemCount();
+ do
+ {
+ ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex );
+ if ( pEntry->mnId != nItemId )
+ break;
+
+ pEntry->mbEnabled = bEnable;
+ nIndex++;
+ }
+ while ( nIndex < nItemCount );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Accelerator::IsItemEnabled( USHORT nItemId ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
+ if ( nIndex != ACCELENTRY_NOTFOUND )
+ return mpData->maIdList.GetObject( (ULONG)nIndex )->mbEnabled;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Accelerator::EnableItem( const KeyCode rKeyCode, BOOL bEnable )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ pEntry->mbEnabled = bEnable;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Accelerator::IsItemEnabled( const KeyCode rKeyCode ) const
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+
+ ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ return pEntry->mbEnabled;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Accelerator& Accelerator::operator=( const Accelerator& rAccel )
+{
+ DBG_CHKTHIS( Accelerator, NULL );
+ DBG_CHKOBJ( &rAccel, Accelerator, NULL );
+
+ // Neue Daten zuweisen
+ maHelpStr = rAccel.maHelpStr;
+ maCurKeyCode = KeyCode();
+ mnCurId = 0;
+ mnCurRepeat = 0;
+ mbIsCancel = FALSE;
+
+ // Tabellen loeschen und kopieren
+ ImplDeleteData();
+ mpData->maKeyTable.Clear();
+ mpData->maIdList.Clear();
+ ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
+
+ return *this;
+}
diff --git a/vcl/source/window/accmgr.cxx b/vcl/source/window/accmgr.cxx
new file mode 100644
index 000000000000..81699bcaabb0
--- /dev/null
+++ b/vcl/source/window/accmgr.cxx
@@ -0,0 +1,290 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/list.hxx>
+#include <tools/debug.hxx>
+#include <vcl/accel.h>
+#include <vcl/accel.hxx>
+#include <vcl/accmgr.hxx>
+
+
+
+// =======================================================================
+
+DECLARE_LIST( ImplAccelList, Accelerator* )
+
+// =======================================================================
+
+DBG_NAMEEX( Accelerator )
+
+// =======================================================================
+
+ImplAccelManager::~ImplAccelManager()
+{
+ if ( mpAccelList )
+ delete mpAccelList;
+ if ( mpSequenceList )
+ delete mpSequenceList;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplAccelManager::InsertAccel( Accelerator* pAccel )
+{
+ if ( !mpAccelList )
+ mpAccelList = new ImplAccelList;
+ else
+ {
+ // Gibts den schon ?
+ if ( mpAccelList->GetPos( pAccel ) != LIST_ENTRY_NOTFOUND )
+ return FALSE;
+ }
+
+ // Am Anfang der Liste einfuegen
+ mpAccelList->Insert( pAccel, (ULONG)0 );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplAccelManager::RemoveAccel( Accelerator* pAccel )
+{
+ // Haben wir ueberhaupt eine Liste ?
+ if ( !mpAccelList )
+ return;
+
+ //e.g. #i90599#. Someone starts typing a sequence in a dialog, but doesn't
+ //end it, and then closes the dialog, deleting the accelerators. So if
+ //we're removing an accelerator that a sub-accelerator which is in the
+ //sequence list, throw away the entire sequence
+ if ( mpSequenceList )
+ {
+ for (USHORT i = 0; i < pAccel->GetItemCount(); ++i)
+ {
+ Accelerator* pSubAccel = pAccel->GetAccel(pAccel->GetItemId(i));
+ if ( mpSequenceList->GetPos( pSubAccel ) != LIST_ENTRY_NOTFOUND )
+ {
+ EndSequence( true );
+ break;
+ }
+ }
+ }
+
+ // Raus damit
+ mpAccelList->Remove( pAccel );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplAccelManager::EndSequence( BOOL bCancel )
+{
+ // Sind wir ueberhaupt in einer Sequenz ?
+ if ( !mpSequenceList )
+ return;
+
+ // Alle Deactivate-Handler der Acceleratoren in der Sequenz rufen
+ Accelerator* pTempAccel = mpSequenceList->First();
+ while( pTempAccel )
+ {
+ BOOL bDel = FALSE;
+ pTempAccel->mbIsCancel = bCancel;
+ pTempAccel->mpDel = &bDel;
+ pTempAccel->Deactivate();
+ if ( !bDel )
+ {
+ pTempAccel->mbIsCancel = FALSE;
+ pTempAccel->mpDel = NULL;
+ }
+
+ pTempAccel = mpSequenceList->Next();
+ }
+
+ // Sequenz-Liste loeschen
+ delete mpSequenceList;
+ mpSequenceList = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplAccelManager::IsAccelKey( const KeyCode& rKeyCode, USHORT nRepeat )
+{
+ Accelerator* pAccel;
+
+ // Haben wir ueberhaupt Acceleratoren ??
+ if ( !mpAccelList )
+ return FALSE;
+ if ( !mpAccelList->Count() )
+ return FALSE;
+
+ // Sind wir in einer Sequenz ?
+ if ( mpSequenceList )
+ {
+ pAccel = mpSequenceList->GetObject( 0 );
+ DBG_CHKOBJ( pAccel, Accelerator, NULL );
+
+ // Nicht Gefunden ?
+ if ( !pAccel )
+ {
+ // Sequenz abbrechen
+ FlushAccel();
+ return FALSE;
+ }
+
+ // Ist der Eintrag da drin ?
+ ImplAccelEntry* pEntry = pAccel->ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ {
+ Accelerator* pNextAccel = pEntry->mpAccel;
+
+ // Ist da ein Accelerator hinter ?
+ if ( pNextAccel )
+ {
+ DBG_CHKOBJ( pNextAccel, Accelerator, NULL );
+
+ mpSequenceList->Insert( pNextAccel, (ULONG)0 );
+
+ // Activate-Handler vom Neuen rufen
+ pNextAccel->Activate();
+ return TRUE;
+ }
+ else
+ {
+ // Hat ihn schon !
+ if ( pEntry->mbEnabled )
+ {
+ // Sequence beenden (Deactivate-Handler vorher rufen)
+ EndSequence();
+
+ // Dem Accelerator das aktuelle Item setzen
+ // und Handler rufen
+ BOOL bDel = FALSE;
+ pAccel->maCurKeyCode = rKeyCode;
+ pAccel->mnCurId = pEntry->mnId;
+ pAccel->mnCurRepeat = nRepeat;
+ pAccel->mpDel = &bDel;
+ pAccel->Select();
+
+ // Hat Accel den Aufruf ueberlebt
+ if ( !bDel )
+ {
+ DBG_CHKOBJ( pAccel, Accelerator, NULL );
+ pAccel->maCurKeyCode = KeyCode();
+ pAccel->mnCurId = 0;
+ pAccel->mnCurRepeat = 0;
+ pAccel->mpDel = NULL;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ // Sequenz abbrechen, weil Acceleraor disabled
+ // Taste wird weitergeleitet (ans System)
+ FlushAccel();
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ // Sequenz abbrechen wegen falscher Taste
+ FlushAccel();
+ return FALSE;
+ }
+ }
+
+ // Durch die Liste der Acceleratoren wuehlen
+ pAccel = mpAccelList->First();
+ while ( pAccel )
+ {
+ DBG_CHKOBJ( pAccel, Accelerator, NULL );
+
+ // Ist der Eintrag da drin ?
+ ImplAccelEntry* pEntry = pAccel->ImplGetAccelData( rKeyCode );
+ if ( pEntry )
+ {
+ Accelerator* pNextAccel = pEntry->mpAccel;
+
+ // Ist da ein Accelerator hinter ?
+ if ( pNextAccel )
+ {
+ DBG_CHKOBJ( pNextAccel, Accelerator, NULL );
+
+ // Sequenz-Liste erzeugen
+ mpSequenceList = new ImplAccelList;
+ mpSequenceList->Insert( pAccel, (ULONG)0 );
+ mpSequenceList->Insert( pNextAccel, (ULONG)0 );
+
+ // Activate-Handler vom Neuen rufen
+ pNextAccel->Activate();
+
+ return TRUE;
+ }
+ else
+ {
+ // Hat ihn schon !
+ if ( pEntry->mbEnabled )
+ {
+ // Activate/Deactivate-Handler vorher rufen
+ pAccel->Activate();
+ pAccel->Deactivate();
+
+ // Dem Accelerator das aktuelle Item setzen
+ // und Handler rufen
+ BOOL bDel = FALSE;
+ pAccel->maCurKeyCode = rKeyCode;
+ pAccel->mnCurId = pEntry->mnId;
+ pAccel->mnCurRepeat = nRepeat;
+ pAccel->mpDel = &bDel;
+ pAccel->Select();
+
+ // Hat Accel den Aufruf ueberlebt
+ if ( !bDel )
+ {
+ DBG_CHKOBJ( pAccel, Accelerator, NULL );
+ pAccel->maCurKeyCode = KeyCode();
+ pAccel->mnCurId = 0;
+ pAccel->mnCurRepeat = 0;
+ pAccel->mpDel = NULL;
+ }
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ }
+
+ // Nicht gefunden, vielleicht im naechsten Accelerator
+ pAccel = mpAccelList->Next();
+ }
+
+ return FALSE;
+}
diff --git a/vcl/source/window/arrange.cxx b/vcl/source/window/arrange.cxx
new file mode 100644
index 000000000000..dad48235f8fb
--- /dev/null
+++ b/vcl/source/window/arrange.cxx
@@ -0,0 +1,903 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_vcl.hxx"
+
+#include "vcl/arrange.hxx"
+#include "vcl/edit.hxx"
+
+#include "osl/diagnose.h"
+
+using namespace vcl;
+
+// ----------------------------------------
+// vcl::WindowArranger
+//-----------------------------------------
+
+WindowArranger::~WindowArranger()
+{}
+
+void WindowArranger::setParent( WindowArranger* i_pParent )
+{
+ OSL_VERIFY( i_pParent->m_pParentWindow == m_pParentWindow || m_pParentWindow == NULL );
+
+ m_pParentArranger = i_pParent;
+ m_pParentWindow = i_pParent->m_pParentWindow;
+ setParentWindow( m_pParentWindow );
+}
+
+void WindowArranger::setParentWindow( Window* i_pNewParent )
+{
+ m_pParentWindow = i_pNewParent;
+
+ size_t nEle = countElements();
+ for( size_t i = 0; i < nEle; i++ )
+ {
+ Element* pEle = getElement( i );
+ if( pEle ) // sanity check
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ if( pEle->m_pElement )
+ {
+ OSL_VERIFY( pEle->m_pElement->GetParent() == i_pNewParent );
+ }
+ #endif
+ if( pEle->m_pChild )
+ pEle->m_pChild->setParentWindow( i_pNewParent );
+ }
+ }
+}
+
+void WindowArranger::show( bool i_bShow, bool i_bImmediateUpdate )
+{
+ size_t nEle = countElements();
+ for( size_t i = 0; i < nEle; i++ )
+ {
+ Element* pEle = getElement( i );
+ if( pEle ) // sanity check
+ {
+ pEle->m_bHidden = ! i_bShow;
+ if( pEle->m_pElement )
+ pEle->m_pElement->Show( i_bShow );
+ if( pEle->m_pChild.get() )
+ pEle->m_pChild->show( i_bShow, false );
+ }
+ }
+ if( m_pParentArranger )
+ {
+ nEle = m_pParentArranger->countElements();
+ for( size_t i = 0; i < nEle; i++ )
+ {
+ Element* pEle = m_pParentArranger->getElement( i );
+ if( pEle && pEle->m_pChild.get() == this )
+ {
+ pEle->m_bHidden = ! i_bShow;
+ break;
+ }
+ }
+ }
+ if( i_bImmediateUpdate )
+ {
+ // find the topmost parent
+ WindowArranger* pResize = this;
+ while( pResize->m_pParentArranger )
+ pResize = pResize->m_pParentArranger;
+ pResize->resize();
+ }
+}
+
+bool WindowArranger::isVisible() const
+{
+ size_t nEle = countElements();
+ for( size_t i = 0; i < nEle; i++ )
+ {
+ const Element* pEle = getConstElement( i );
+ if( pEle->isVisible() )
+ return true;
+ }
+ return false;
+}
+
+bool WindowArranger::Element::isVisible() const
+{
+ bool bVisible = false;
+ if( ! m_bHidden )
+ {
+ if( m_pElement )
+ bVisible = m_pElement->IsVisible();
+ else if( m_pChild )
+ bVisible = m_pChild->isVisible();
+ }
+ return bVisible;
+}
+
+sal_Int32 WindowArranger::Element::getExpandPriority() const
+{
+ sal_Int32 nPrio = m_nExpandPriority;
+ if( m_pChild && m_nExpandPriority >= 0 )
+ {
+ size_t nElements = m_pChild->countElements();
+ for( size_t i = 0; i < nElements; i++ )
+ {
+ sal_Int32 nCPrio = m_pChild->getExpandPriority( i );
+ if( nCPrio > nPrio )
+ nPrio = nCPrio;
+ }
+ }
+ return nPrio;
+}
+
+Size WindowArranger::Element::getOptimalSize( WindowSizeType i_eType ) const
+{
+ Size aResult;
+ if( ! m_bHidden )
+ {
+ if( m_pElement && m_pElement->IsVisible() )
+ aResult = m_pElement->GetOptimalSize( i_eType );
+ else if( m_pChild )
+ aResult = m_pChild->getOptimalSize( i_eType );
+ if( aResult.Width() < m_aMinSize.Width() )
+ aResult.Width() = m_aMinSize.Width();
+ if( aResult.Height() < m_aMinSize.Height() )
+ aResult.Height() = m_aMinSize.Height();
+ aResult.Width() += m_nLeftBorder + m_nRightBorder;
+ aResult.Height() += m_nTopBorder + m_nBottomBorder;
+ }
+
+ return aResult;
+}
+
+void WindowArranger::Element::setPosSize( const Point& i_rPos, const Size& i_rSize )
+{
+ Point aPoint( i_rPos );
+ Size aSize( i_rSize );
+ aPoint.X() += m_nLeftBorder;
+ aPoint.Y() += m_nTopBorder;
+ aSize.Width() -= m_nLeftBorder + m_nRightBorder;
+ aSize.Height() -= m_nTopBorder + m_nBottomBorder;
+ if( m_pElement )
+ m_pElement->SetPosSizePixel( aPoint, aSize );
+ else if( m_pChild )
+ m_pChild->setManagedArea( Rectangle( aPoint, aSize ) );
+}
+
+// ----------------------------------------
+// vcl::RowOrColumn
+//-----------------------------------------
+
+RowOrColumn::~RowOrColumn()
+{
+ for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ it->deleteChild();
+ }
+}
+
+Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const
+{
+ Size aRet( 0, 0 );
+ for( std::vector< WindowArranger::Element >::const_iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ if( it->isVisible() )
+ {
+ // get the size of type of the managed element
+ Size aElementSize( it->getOptimalSize( i_eType ) );
+ if( m_bColumn )
+ {
+ // add the distance between elements
+ aRet.Height() += m_nBorderWidth;
+ // check if the width needs adjustment
+ if( aRet.Width() < aElementSize.Width() )
+ aRet.Width() = aElementSize.Width();
+ aRet.Height() += aElementSize.Height();
+ }
+ else
+ {
+ // add the distance between elements
+ aRet.Width() += m_nBorderWidth;
+ // check if the height needs adjustment
+ if( aRet.Height() < aElementSize.Height() )
+ aRet.Height() = aElementSize.Height();
+ aRet.Width() += aElementSize.Width();
+ }
+ }
+ }
+
+ if( aRet.Width() != 0 || aRet.Height() != 0 )
+ {
+ // subtract the border for the first element
+ if( m_bColumn )
+ aRet.Height() -= m_nBorderWidth;
+ else
+ aRet.Width() -= m_nBorderWidth;
+
+ // add the outer border
+ aRet.Width() += 2*m_nOuterBorder;
+ aRet.Height() += 2*m_nOuterBorder;
+ }
+
+ return aRet;
+}
+
+void RowOrColumn::distributeRowWidth( std::vector<Size>& io_rSizes, long /*i_nUsedWidth*/, long i_nExtraWidth )
+{
+ if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() )
+ {
+ // find all elements with the highest expand priority
+ size_t nElements = m_aElements.size();
+ std::vector< size_t > aIndices;
+ sal_Int32 nHighPrio = 0;
+ for( size_t i = 0; i < nElements; i++ )
+ {
+ if( m_aElements[ i ].isVisible() )
+ {
+ sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority();
+ if( nCurPrio > nHighPrio )
+ {
+ aIndices.clear();
+ nHighPrio = nCurPrio;
+ }
+ if( nCurPrio == nHighPrio )
+ aIndices.push_back( i );
+ }
+ }
+
+ // distribute extra space evenly among collected elements
+ nElements = aIndices.size();
+ if( nElements > 0 )
+ {
+ long nDelta = i_nExtraWidth / nElements;
+ for( size_t i = 0; i < nElements; i++ )
+ {
+ io_rSizes[ aIndices[i] ].Width() += nDelta;
+ i_nExtraWidth -= nDelta;
+ }
+ // add the last pixels to the last row element
+ if( i_nExtraWidth > 0 && nElements > 0 )
+ io_rSizes[aIndices.back()].Width() += i_nExtraWidth;
+ }
+ }
+}
+
+void RowOrColumn::distributeColumnHeight( std::vector<Size>& io_rSizes, long /*i_nUsedHeight*/, long i_nExtraHeight )
+{
+ if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() )
+ {
+ // find all elements with the highest expand priority
+ size_t nElements = m_aElements.size();
+ std::vector< size_t > aIndices;
+ sal_Int32 nHighPrio = 3;
+ for( size_t i = 0; i < nElements; i++ )
+ {
+ if( m_aElements[ i ].isVisible() )
+ {
+ sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority();
+ if( nCurPrio > nHighPrio )
+ {
+ aIndices.clear();
+ nHighPrio = nCurPrio;
+ }
+ if( nCurPrio == nHighPrio )
+ aIndices.push_back( i );
+ }
+ }
+
+ // distribute extra space evenly among collected elements
+ nElements = aIndices.size();
+ if( nElements > 0 )
+ {
+ long nDelta = i_nExtraHeight / nElements;
+ for( size_t i = 0; i < nElements; i++ )
+ {
+ io_rSizes[ aIndices[i] ].Height() += nDelta;
+ i_nExtraHeight -= nDelta;
+ }
+ // add the last pixels to the last row element
+ if( i_nExtraHeight > 0 && nElements > 0 )
+ io_rSizes[aIndices.back()].Height() += i_nExtraHeight;
+ }
+ }
+}
+
+void RowOrColumn::resize()
+{
+ // check if we can get optimal size, else fallback to minimal size
+ Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED ) );
+ WindowSizeType eType = WINDOWSIZE_PREFERRED;
+ if( m_bColumn )
+ {
+ if( aOptSize.Height() > m_aManagedArea.GetHeight() )
+ eType = WINDOWSIZE_MINIMUM;
+ }
+ else
+ {
+ if( aOptSize.Width() > m_aManagedArea.GetWidth() )
+ eType = WINDOWSIZE_MINIMUM;
+ }
+
+ size_t nElements = m_aElements.size();
+ // get all element sizes for sizing
+ std::vector<Size> aElementSizes( nElements );
+ long nUsedWidth = 2*m_nOuterBorder - (nElements ? m_nBorderWidth : 0);
+ for( size_t i = 0; i < nElements; i++ )
+ {
+ if( m_aElements[i].isVisible() )
+ {
+ aElementSizes[i] = m_aElements[i].getOptimalSize( eType );
+ if( m_bColumn )
+ {
+ aElementSizes[i].Width() = m_aManagedArea.GetWidth() - 2* m_nOuterBorder;
+ nUsedWidth += aElementSizes[i].Height() + m_nBorderWidth;
+ }
+ else
+ {
+ aElementSizes[i].Height() = m_aManagedArea.GetHeight() - 2* m_nOuterBorder;
+ nUsedWidth += aElementSizes[i].Width() + m_nBorderWidth;
+ }
+ }
+ }
+
+ long nExtraWidth = (m_bColumn ? m_aManagedArea.GetHeight() : m_aManagedArea.GetWidth()) - nUsedWidth;
+ if( nExtraWidth > 0 )
+ {
+ if( m_bColumn )
+ distributeColumnHeight( aElementSizes, nUsedWidth, nExtraWidth );
+ else
+ distributeRowWidth( aElementSizes, nUsedWidth, nExtraWidth );
+ }
+
+ // get starting position
+ Point aElementPos( m_aManagedArea.TopLeft() );
+ // outer border
+ aElementPos.X() += m_nOuterBorder;
+ aElementPos.Y() += m_nOuterBorder;
+
+ // position managed windows
+ for( size_t i = 0; i < nElements; i++ )
+ {
+ // get the size of type of the managed element
+ if( m_aElements[i].isVisible() )
+ {
+ m_aElements[i].setPosSize( aElementPos, aElementSizes[i] );
+ if( m_bColumn )
+ aElementPos.Y() += m_nBorderWidth + aElementSizes[i].Height();
+ else
+ aElementPos.X() += m_nBorderWidth + aElementSizes[i].Width();
+ }
+ }
+}
+
+size_t RowOrColumn::addWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio, size_t i_nIndex )
+{
+ size_t nIndex = i_nIndex;
+ if( i_nIndex >= m_aElements.size() )
+ {
+ nIndex = m_aElements.size();
+ m_aElements.push_back( WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) );
+ }
+ else
+ {
+ std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
+ while( i_nIndex-- )
+ ++it;
+ m_aElements.insert( it, WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) );
+ }
+ return nIndex;
+}
+
+size_t RowOrColumn::addChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio, size_t i_nIndex )
+{
+ size_t nIndex = i_nIndex;
+ if( i_nIndex >= m_aElements.size() )
+ {
+ nIndex = m_aElements.size();
+ m_aElements.push_back( WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) );
+ }
+ else
+ {
+ std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
+ while( i_nIndex-- )
+ ++it;
+ m_aElements.insert( it, WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) );
+ }
+ return nIndex;
+}
+
+void RowOrColumn::remove( Window* i_pWindow )
+{
+ if( i_pWindow )
+ {
+ for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ if( it->m_pElement == i_pWindow )
+ {
+ m_aElements.erase( it );
+ return;
+ }
+ }
+ }
+}
+
+void RowOrColumn::remove( boost::shared_ptr<WindowArranger> const & i_pChild )
+{
+ if( i_pChild )
+ {
+ for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ if( it->m_pChild == i_pChild )
+ {
+ m_aElements.erase( it );
+ return;
+ }
+ }
+ }
+}
+
+// ----------------------------------------
+// vcl::LabeledElement
+//-----------------------------------------
+
+LabeledElement::~LabeledElement()
+{
+ m_aLabel.deleteChild();
+ m_aElement.deleteChild();
+}
+
+Size LabeledElement::getOptimalSize( WindowSizeType i_eType ) const
+{
+ Size aRet( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) );
+ if( aRet.Width() != 0 )
+ {
+ if( m_nLabelColumnWidth != 0 )
+ aRet.Width() = m_nLabelColumnWidth;
+ else
+ aRet.Width() += m_nDistance;
+ }
+ Size aElementSize( m_aElement.getOptimalSize( i_eType ) );
+ aRet.Width() += aElementSize.Width();
+ if( aElementSize.Height() > aRet.Height() )
+ aRet.Height() = aElementSize.Height();
+ if( aRet.Height() != 0 )
+ aRet.Height() += 2*m_nOuterBorder;
+
+ return aRet;
+}
+
+void LabeledElement::resize()
+{
+ Size aLabelSize( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) );
+ Size aElementSize( m_aElement.getOptimalSize( WINDOWSIZE_PREFERRED ) );
+ if( m_nDistance + aLabelSize.Width() + aElementSize.Width() > m_aManagedArea.GetWidth() )
+ aElementSize = m_aElement.getOptimalSize( WINDOWSIZE_MINIMUM );
+
+ // align label and element vertically in LabeledElement
+ long nYOff = (m_aManagedArea.GetHeight() - 2*m_nOuterBorder - aLabelSize.Height()) / 2;
+ Point aPos( m_aManagedArea.Left(),
+ m_aManagedArea.Top() + m_nOuterBorder + nYOff );
+ Size aSize( aLabelSize );
+ if( m_nLabelColumnWidth != 0 )
+ aSize.Width() = m_nLabelColumnWidth;
+ m_aLabel.setPosSize( aPos, aSize );
+
+ aPos.X() += aSize.Width() + m_nDistance;
+ nYOff = (m_aManagedArea.GetHeight() - 2*m_nOuterBorder - aElementSize.Height()) / 2;
+ aPos.Y() = m_aManagedArea.Top() + m_nOuterBorder + nYOff;
+ aSize.Width() = aElementSize.Width();
+ aSize.Height() = m_aManagedArea.GetHeight() - 2*m_nOuterBorder;
+
+ // label style
+ // 0: position left and right
+ // 1: keep the element close to label and grow it
+ // 2: keep the element close and don't grow it
+ if( m_nLabelStyle == 0)
+ {
+ if( aPos.X() + aSize.Width() < m_aManagedArea.Right() )
+ aPos.X() = m_aManagedArea.Right() - aSize.Width();
+ }
+ else if( m_nLabelStyle == 1 )
+ {
+ if( aPos.X() + aSize.Width() < m_aManagedArea.Right() )
+ aSize.Width() = m_aManagedArea.Right() - aPos.X();
+ }
+ m_aElement.setPosSize( aPos, aSize );
+}
+
+void LabeledElement::setLabel( Window* i_pLabel )
+{
+ m_aLabel.m_pElement = i_pLabel;
+ m_aLabel.m_pChild.reset();
+}
+
+void LabeledElement::setLabel( boost::shared_ptr<WindowArranger> const & i_pLabel )
+{
+ m_aLabel.m_pElement = NULL;
+ m_aLabel.m_pChild = i_pLabel;
+}
+
+void LabeledElement::setElement( Window* i_pElement )
+{
+ m_aElement.m_pElement = i_pElement;
+ m_aElement.m_pChild.reset();
+}
+
+void LabeledElement::setElement( boost::shared_ptr<WindowArranger> const & i_pElement )
+{
+ m_aElement.m_pElement = NULL;
+ m_aElement.m_pChild = i_pElement;
+}
+
+// ----------------------------------------
+// vcl::LabelColumn
+//-----------------------------------------
+LabelColumn::~LabelColumn()
+{
+}
+
+long LabelColumn::getLabelWidth() const
+{
+ long nWidth = 0;
+
+ size_t nEle = countElements();
+ for( size_t i = 0; i < nEle; i++ )
+ {
+ const Element* pEle = getConstElement( i );
+ if( pEle && pEle->m_pChild.get() )
+ {
+ const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get());
+ if( pLabel )
+ {
+ Window* pLW = pLabel->getWindow( 0 );
+ if( pLW )
+ {
+ Size aLabSize( pLW->GetOptimalSize( WINDOWSIZE_MINIMUM ) );
+ if( aLabSize.Width() > nWidth )
+ nWidth = aLabSize.Width();
+ }
+ }
+ }
+ }
+ return nWidth + getBorderWidth();
+}
+
+Size LabelColumn::getOptimalSize( WindowSizeType i_eType ) const
+{
+ long nWidth = getLabelWidth();
+ Size aColumnSize;
+
+ // every child is a LabeledElement
+ size_t nEle = countElements();
+ for( size_t i = 0; i < nEle; i++ )
+ {
+ Size aElementSize;
+ const Element* pEle = getConstElement( i );
+ if( pEle && pEle->m_pChild.get() )
+ {
+ const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get());
+ if( pLabel ) // we have a label
+ {
+ aElementSize = pLabel->getLabelSize( WINDOWSIZE_MINIMUM );
+ if( aElementSize.Width() )
+ aElementSize.Width() = nWidth;
+ Size aSize( pLabel->getElementSize( i_eType ) );
+ aElementSize.Width() += aSize.Width();
+ if( aSize.Height() > aElementSize.Height() )
+ aElementSize.Height() = aSize.Height();
+ }
+ else // a non label, just treat it as a row
+ {
+ aElementSize = pEle->getOptimalSize( i_eType );
+ }
+ }
+ else if( pEle && pEle->m_pElement ) // a general window, treat is as a row
+ {
+ aElementSize = pEle->getOptimalSize( i_eType );
+ }
+ if( aElementSize.Width() )
+ {
+ aElementSize.Width() += 2*m_nOuterBorder;
+ if( aElementSize.Width() > aColumnSize.Width() )
+ aColumnSize.Width() = aElementSize.Width();
+ }
+ if( aElementSize.Height() )
+ {
+ aColumnSize.Height() += getBorderWidth() + aElementSize.Height();
+ }
+ }
+ if( nEle > 0 && aColumnSize.Height() )
+ {
+ aColumnSize.Height() -= getBorderWidth(); // for the first element
+ aColumnSize.Height() += 2*m_nOuterBorder;
+ }
+ return aColumnSize;
+}
+
+void LabelColumn::resize()
+{
+ long nWidth = getLabelWidth();
+ size_t nEle = countElements();
+ for( size_t i = 0; i < nEle; i++ )
+ {
+ Element* pEle = getElement( i );
+ if( pEle && pEle->m_pChild.get() )
+ {
+ LabeledElement* pLabel = dynamic_cast< LabeledElement* >(pEle->m_pChild.get());
+ if( pLabel )
+ pLabel->setLabelColumnWidth( nWidth );
+ }
+ }
+ RowOrColumn::resize();
+}
+
+size_t LabelColumn::addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent )
+{
+ boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) );
+ xLabel->setLabel( i_pLabel );
+ xLabel->setBorders( 0, i_nIndent, 0, 0, 0 );
+ xLabel->setElement( i_rElement );
+ size_t nIndex = addChild( xLabel );
+ resize();
+ return nIndex;
+}
+
+size_t LabelColumn::addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent )
+{
+ boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) );
+ xLabel->setLabel( i_pLabel );
+ xLabel->setBorders( 0, i_nIndent, 0, 0, 0 );
+ xLabel->setElement( i_pElement );
+ size_t nIndex = addChild( xLabel );
+ resize();
+ return nIndex;
+}
+
+// ----------------------------------------
+// vcl::Indenter
+//-----------------------------------------
+
+Indenter::~Indenter()
+{
+ m_aElement.deleteChild();
+}
+
+Size Indenter::getOptimalSize( WindowSizeType i_eType ) const
+{
+ Size aSize( m_aElement.getOptimalSize( i_eType ) );
+ aSize.Width() += 2*m_nOuterBorder + m_nIndent;
+ aSize.Height() += 2*m_nOuterBorder;
+ return aSize;
+}
+
+void Indenter::resize()
+{
+ Point aPt( m_aManagedArea.TopLeft() );
+ aPt.X() += m_nOuterBorder + m_nIndent;
+ aPt.Y() += m_nOuterBorder;
+ Size aSz( m_aManagedArea.GetSize() );
+ aSz.Width() -= 2*m_nOuterBorder + m_nIndent;
+ aSz.Height() -= 2*m_nOuterBorder;
+ m_aElement.setPosSize( aPt, aSz );
+}
+
+void Indenter::setWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio )
+{
+ OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0) || i_pWindow == 0 );
+ OSL_VERIFY( i_pWindow == 0 || i_pWindow->GetParent() == m_pParentWindow );
+ m_aElement.m_pElement = i_pWindow;
+ m_aElement.m_nExpandPriority = i_nExpandPrio;
+}
+
+void Indenter::setChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio )
+{
+ OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0 ) || i_pChild == 0 );
+ m_aElement.m_pChild = i_pChild;
+ m_aElement.m_nExpandPriority = i_nExpandPrio;
+}
+
+// ----------------------------------------
+// vcl::MatrixArranger
+//-----------------------------------------
+MatrixArranger::~MatrixArranger()
+{
+}
+
+Size MatrixArranger::getOptimalSize( WindowSizeType i_eType, std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights ) const
+{
+ Size aMatrixSize( 2*m_nOuterBorder, 2*m_nOuterBorder );
+
+ // first find out the current number of rows and columns
+ sal_uInt32 nRows = 0, nColumns = 0;
+ for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ if( it->m_nX >= nColumns )
+ nColumns = it->m_nX+1;
+ if( it->m_nY >= nRows )
+ nRows = it->m_nY+1;
+ }
+
+ // now allocate row and column depth vectors
+ o_rColumnWidths = std::vector< long >( nColumns, 0 );
+ o_rRowHeights = std::vector< long >( nRows, 0 );
+
+ // get sizes an allocate them into rows/columns
+ for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ Size aSize( it->getOptimalSize( i_eType ) );
+ if( aSize.Width() > o_rColumnWidths[ it->m_nX ] )
+ o_rColumnWidths[ it->m_nX ] = aSize.Width();
+ if( aSize.Height() > o_rRowHeights[ it->m_nY ] )
+ o_rRowHeights[ it->m_nY ] = aSize.Height();
+ }
+
+ // add up sizes
+ for( sal_uInt32 i = 0; i < nColumns; i++ )
+ aMatrixSize.Width() += o_rColumnWidths[i] + m_nBorderX;
+ if( nColumns > 0 )
+ aMatrixSize.Width() -= m_nBorderX;
+
+ for( sal_uInt32 i = 0; i < nRows; i++ )
+ aMatrixSize.Height() += o_rRowHeights[i] + m_nBorderY;
+ if( nRows > 0 )
+ aMatrixSize.Height() -= m_nBorderY;
+
+ return aMatrixSize;
+}
+
+Size MatrixArranger::getOptimalSize( WindowSizeType i_eType ) const
+{
+ std::vector<long> aColumnWidths, aRowHeights;
+ return getOptimalSize( i_eType, aColumnWidths, aRowHeights );
+}
+
+void MatrixArranger::resize()
+{
+ // assure that we have at least one row and column
+ if( m_aElements.empty() )
+ return;
+
+ // check if we can get optimal size, else fallback to minimal size
+ std::vector<long> aColumnWidths, aRowHeights;
+ Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED, aColumnWidths, aRowHeights ) );
+ if( aOptSize.Height() > m_aManagedArea.GetHeight() ||
+ aOptSize.Width() > m_aManagedArea.GetWidth() )
+ {
+ std::vector<long> aMinColumnWidths, aMinRowHeights;
+ getOptimalSize( WINDOWSIZE_MINIMUM, aMinColumnWidths, aMinRowHeights );
+ if( aOptSize.Height() > m_aManagedArea.GetHeight() )
+ aRowHeights = aMinRowHeights;
+ if( aOptSize.Width() > m_aManagedArea.GetWidth() )
+ aColumnWidths = aMinColumnWidths;
+ }
+
+ // FIXME: distribute extra space available
+
+ // prepare offsets
+ std::vector<long> aColumnX( aColumnWidths.size() );
+ aColumnX[0] = m_aManagedArea.Left() + m_nOuterBorder;
+ for( size_t i = 1; i < aColumnX.size(); i++ )
+ aColumnX[i] = aColumnX[i-1] + aColumnWidths[i-1] + m_nBorderX;
+
+ std::vector<long> aRowY( aRowHeights.size() );
+ aRowY[0] = m_aManagedArea.Top() + m_nOuterBorder;
+ for( size_t i = 1; i < aRowY.size(); i++ )
+ aRowY[i] = aRowY[i-1] + aRowHeights[i-1] + m_nBorderY;
+
+ // now iterate over the elements and assign their positions
+ for( std::vector< MatrixElement >::iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ Point aCellPos( aColumnX[it->m_nX], aRowY[it->m_nY] );
+ Size aCellSize( aColumnWidths[it->m_nX], aRowHeights[it->m_nY] );
+ it->setPosSize( aCellPos, aCellSize );
+ }
+}
+
+size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio )
+{
+ sal_uInt64 nMapValue = getMap( i_nX, i_nY );
+ std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue );
+ size_t nIndex = 0;
+ if( it == m_aMatrixMap.end() )
+ {
+ m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size();
+ m_aElements.push_back( MatrixElement( i_pWindow, i_nX, i_nY, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) );
+ }
+ else
+ {
+ MatrixElement& rEle( m_aElements[ it->second ] );
+ rEle.m_pElement = i_pWindow;
+ rEle.m_pChild.reset();
+ rEle.m_nExpandPriority = i_nExpandPrio;
+ rEle.m_nX = i_nX;
+ rEle.m_nY = i_nY;
+ nIndex = it->second;
+ }
+ return nIndex;
+}
+
+void MatrixArranger::remove( Window* i_pWindow )
+{
+ if( i_pWindow )
+ {
+ for( std::vector< MatrixElement >::iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ if( it->m_pElement == i_pWindow )
+ {
+ m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) );
+ m_aElements.erase( it );
+ return;
+ }
+ }
+ }
+}
+
+size_t MatrixArranger::addChild( boost::shared_ptr<WindowArranger> const &i_pChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio )
+{
+ sal_uInt64 nMapValue = getMap( i_nX, i_nY );
+ std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue );
+ size_t nIndex = 0;
+ if( it == m_aMatrixMap.end() )
+ {
+ m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size();
+ m_aElements.push_back( MatrixElement( NULL, i_nX, i_nY, i_pChild, i_nExpandPrio ) );
+ }
+ else
+ {
+ MatrixElement& rEle( m_aElements[ it->second ] );
+ rEle.m_pElement = 0;
+ rEle.m_pChild = i_pChild;
+ rEle.m_nExpandPriority = i_nExpandPrio;
+ rEle.m_nX = i_nX;
+ rEle.m_nY = i_nY;
+ nIndex = it->second;
+ }
+ return nIndex;
+}
+
+void MatrixArranger::remove( boost::shared_ptr<WindowArranger> const &i_pChild )
+{
+ if( i_pChild )
+ {
+ for( std::vector< MatrixElement >::iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ if( it->m_pChild == i_pChild )
+ {
+ m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) );
+ m_aElements.erase( it );
+ return;
+ }
+ }
+ }
+}
+
diff --git a/vcl/source/window/brdwin.cxx b/vcl/source/window/brdwin.cxx
new file mode 100644
index 000000000000..b221d1f7d928
--- /dev/null
+++ b/vcl/source/window/brdwin.cxx
@@ -0,0 +1,2353 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/event.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/dockwin.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/image.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/help.hxx>
+#include <vcl/edit.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/window.h>
+#include <vcl/metric.hxx>
+#include <tools/debug.hxx>
+
+using namespace ::com::sun::star::uno;
+
+// useful caption height for title bar buttons
+#define MIN_CAPTION_HEIGHT 18
+
+// =======================================================================
+
+static void ImplGetPinImage( USHORT nStyle, BOOL bPinIn, Image& rImage )
+{
+ // ImageListe laden, wenn noch nicht vorhanden
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maCtrlData.mpPinImgList )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ pSVData->maCtrlData.mpPinImgList = new ImageList();
+ if( pResMgr )
+ {
+ Color aMaskColor( 0x00, 0x00, 0xFF );
+ pSVData->maCtrlData.mpPinImgList->InsertFromHorizontalBitmap
+ ( ResId( SV_RESID_BITMAP_PIN, *pResMgr ), 4,
+ &aMaskColor, NULL, NULL, 0);
+ }
+ }
+
+ // Image ermitteln und zurueckgeben
+ USHORT nId;
+ if ( nStyle & BUTTON_DRAW_PRESSED )
+ {
+ if ( bPinIn )
+ nId = 4;
+ else
+ nId = 3;
+ }
+ else
+ {
+ if ( bPinIn )
+ nId = 2;
+ else
+ nId = 1;
+ }
+ rImage = pSVData->maCtrlData.mpPinImgList->GetImage( nId );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCalcSymbolRect( Rectangle& rRect )
+{
+ // Den Rand den der Button in der nicht Default-Darstellung freilaesst,
+ // dazuaddieren, da wir diesen bei kleinen Buttons mit ausnutzen wollen
+ rRect.Left()--;
+ rRect.Top()--;
+ rRect.Right()++;
+ rRect.Bottom()++;
+
+ // Zwischen dem Symbol und dem Button-Rand lassen wir 5% Platz
+ long nExtraWidth = ((rRect.GetWidth()*50)+500)/1000;
+ long nExtraHeight = ((rRect.GetHeight()*50)+500)/1000;
+ rRect.Left() += nExtraWidth;
+ rRect.Right() -= nExtraWidth;
+ rRect.Top() += nExtraHeight;
+ rRect.Bottom() -= nExtraHeight;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDrawBrdWinSymbol( OutputDevice* pDev,
+ const Rectangle& rRect, SymbolType eSymbol )
+{
+ // Zwischen dem Symbol und dem Button lassen wir 5% Platz
+ DecorationView aDecoView( pDev );
+ Rectangle aTempRect = rRect;
+ Window::ImplCalcSymbolRect( aTempRect );
+ aDecoView.DrawSymbol( aTempRect, eSymbol,
+ pDev->GetSettings().GetStyleSettings().GetButtonTextColor(), 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDrawBrdWinSymbolButton( OutputDevice* pDev,
+ const Rectangle& rRect,
+ SymbolType eSymbol, USHORT nState )
+{
+ BOOL bMouseOver = (nState & BUTTON_DRAW_HIGHLIGHT) != 0;
+ nState &= ~BUTTON_DRAW_HIGHLIGHT;
+
+ Rectangle aTempRect;
+ Window *pWin = dynamic_cast< Window* >(pDev);
+ if( pWin )
+ {
+ if( bMouseOver )
+ {
+ // provide a bright background for selection effect
+ pWin->SetFillColor( pDev->GetSettings().GetStyleSettings().GetWindowColor() );
+ pWin->SetLineColor();
+ pWin->DrawRect( rRect );
+ pWin->DrawSelectionBackground( rRect, 2, (nState & BUTTON_DRAW_PRESSED) ? TRUE : FALSE,
+ TRUE, FALSE );
+ }
+ aTempRect = rRect;
+ aTempRect.nLeft+=3;
+ aTempRect.nRight-=4;
+ aTempRect.nTop+=3;
+ aTempRect.nBottom-=4;
+ }
+ else
+ {
+ DecorationView aDecoView( pDev );
+ aTempRect = aDecoView.DrawButton( rRect, nState|BUTTON_DRAW_FLAT );
+ }
+ ImplDrawBrdWinSymbol( pDev, aTempRect, eSymbol );
+}
+
+
+// =======================================================================
+
+// ------------------------
+// - ImplBorderWindowView -
+// ------------------------
+
+ImplBorderWindowView::~ImplBorderWindowView()
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplBorderWindowView::MouseMove( const MouseEvent& )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplBorderWindowView::MouseButtonDown( const MouseEvent& )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplBorderWindowView::Tracking( const TrackingEvent& )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+String ImplBorderWindowView::RequestHelp( const Point&, Rectangle& )
+{
+ return String();
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ImplBorderWindowView::GetMenuRect() const
+{
+ return Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindowView::ImplInitTitle( ImplBorderFrameData* pData )
+{
+ ImplBorderWindow* pBorderWindow = pData->mpBorderWindow;
+
+ if ( !(pBorderWindow->GetStyle() & WB_MOVEABLE) ||
+ (pData->mnTitleType == BORDERWINDOW_TITLE_NONE) )
+ {
+ pData->mnTitleType = BORDERWINDOW_TITLE_NONE;
+ pData->mnTitleHeight = 0;
+ }
+ else
+ {
+ const StyleSettings& rStyleSettings = pData->mpOutDev->GetSettings().GetStyleSettings();
+ if ( pData->mnTitleType == BORDERWINDOW_TITLE_TEAROFF )
+ pData->mnTitleHeight = rStyleSettings.GetTearOffTitleHeight();
+ else
+ {
+ if ( pData->mnTitleType == BORDERWINDOW_TITLE_SMALL )
+ {
+ pBorderWindow->SetPointFont( rStyleSettings.GetFloatTitleFont() );
+ pData->mnTitleHeight = rStyleSettings.GetFloatTitleHeight();
+ }
+ else // pData->mnTitleType == BORDERWINDOW_TITLE_NORMAL
+ {
+ pBorderWindow->SetPointFont( rStyleSettings.GetTitleFont() );
+ pData->mnTitleHeight = rStyleSettings.GetTitleHeight();
+ }
+ long nTextHeight = pBorderWindow->GetTextHeight();
+ if ( nTextHeight > pData->mnTitleHeight )
+ pData->mnTitleHeight = nTextHeight;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplBorderWindowView::ImplHitTest( ImplBorderFrameData* pData, const Point& rPos )
+{
+ ImplBorderWindow* pBorderWindow = pData->mpBorderWindow;
+
+ if ( pData->maTitleRect.IsInside( rPos ) )
+ {
+ if ( pData->maCloseRect.IsInside( rPos ) )
+ return BORDERWINDOW_HITTEST_CLOSE;
+ else if ( pData->maRollRect.IsInside( rPos ) )
+ return BORDERWINDOW_HITTEST_ROLL;
+ else if ( pData->maMenuRect.IsInside( rPos ) )
+ return BORDERWINDOW_HITTEST_MENU;
+ else if ( pData->maDockRect.IsInside( rPos ) )
+ return BORDERWINDOW_HITTEST_DOCK;
+ else if ( pData->maHideRect.IsInside( rPos ) )
+ return BORDERWINDOW_HITTEST_HIDE;
+ else if ( pData->maHelpRect.IsInside( rPos ) )
+ return BORDERWINDOW_HITTEST_HELP;
+ else if ( pData->maPinRect.IsInside( rPos ) )
+ return BORDERWINDOW_HITTEST_PIN;
+ else
+ return BORDERWINDOW_HITTEST_TITLE;
+ }
+
+ if ( (pBorderWindow->GetStyle() & WB_SIZEABLE) &&
+ !pBorderWindow->mbRollUp )
+ {
+ long nSizeWidth = pData->mnNoTitleTop+pData->mnTitleHeight;
+ if ( nSizeWidth < 16 )
+ nSizeWidth = 16;
+
+ // no corner resize for floating toolbars, which would lead to jumps while formatting
+ // setting nSizeWidth = 0 will only return pure left,top,right,bottom
+ if( pBorderWindow->GetStyle() & WB_OWNERDRAWDECORATION )
+ nSizeWidth = 0;
+
+ if ( rPos.X() < pData->mnLeftBorder )
+ {
+ if ( rPos.Y() < nSizeWidth )
+ return BORDERWINDOW_HITTEST_TOPLEFT;
+ else if ( rPos.Y() >= pData->mnHeight-nSizeWidth )
+ return BORDERWINDOW_HITTEST_BOTTOMLEFT;
+ else
+ return BORDERWINDOW_HITTEST_LEFT;
+ }
+ else if ( rPos.X() >= pData->mnWidth-pData->mnRightBorder )
+ {
+ if ( rPos.Y() < nSizeWidth )
+ return BORDERWINDOW_HITTEST_TOPRIGHT;
+ else if ( rPos.Y() >= pData->mnHeight-nSizeWidth )
+ return BORDERWINDOW_HITTEST_BOTTOMRIGHT;
+ else
+ return BORDERWINDOW_HITTEST_RIGHT;
+ }
+ else if ( rPos.Y() < pData->mnNoTitleTop )
+ {
+ if ( rPos.X() < nSizeWidth )
+ return BORDERWINDOW_HITTEST_TOPLEFT;
+ else if ( rPos.X() >= pData->mnWidth-nSizeWidth )
+ return BORDERWINDOW_HITTEST_TOPRIGHT;
+ else
+ return BORDERWINDOW_HITTEST_TOP;
+ }
+ else if ( rPos.Y() >= pData->mnHeight-pData->mnBottomBorder )
+ {
+ if ( rPos.X() < nSizeWidth )
+ return BORDERWINDOW_HITTEST_BOTTOMLEFT;
+ else if ( rPos.X() >= pData->mnWidth-nSizeWidth )
+ return BORDERWINDOW_HITTEST_BOTTOMRIGHT;
+ else
+ return BORDERWINDOW_HITTEST_BOTTOM;
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplBorderWindowView::ImplMouseMove( ImplBorderFrameData* pData, const MouseEvent& rMEvt )
+{
+ USHORT oldCloseState = pData->mnCloseState;
+ USHORT oldMenuState = pData->mnMenuState;
+ pData->mnCloseState &= ~BUTTON_DRAW_HIGHLIGHT;
+ pData->mnMenuState &= ~BUTTON_DRAW_HIGHLIGHT;
+
+ Point aMousePos = rMEvt.GetPosPixel();
+ USHORT nHitTest = ImplHitTest( pData, aMousePos );
+ PointerStyle ePtrStyle = POINTER_ARROW;
+ if ( nHitTest & BORDERWINDOW_HITTEST_LEFT )
+ ePtrStyle = POINTER_WINDOW_WSIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_RIGHT )
+ ePtrStyle = POINTER_WINDOW_ESIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_TOP )
+ ePtrStyle = POINTER_WINDOW_NSIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_BOTTOM )
+ ePtrStyle = POINTER_WINDOW_SSIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_TOPLEFT )
+ ePtrStyle = POINTER_WINDOW_NWSIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_BOTTOMRIGHT )
+ ePtrStyle = POINTER_WINDOW_SESIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_TOPRIGHT )
+ ePtrStyle = POINTER_WINDOW_NESIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_BOTTOMLEFT )
+ ePtrStyle = POINTER_WINDOW_SWSIZE;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_CLOSE )
+ pData->mnCloseState |= BUTTON_DRAW_HIGHLIGHT;
+ else if ( nHitTest & BORDERWINDOW_HITTEST_MENU )
+ pData->mnMenuState |= BUTTON_DRAW_HIGHLIGHT;
+ pData->mpBorderWindow->SetPointer( Pointer( ePtrStyle ) );
+
+ if( pData->mnCloseState != oldCloseState )
+ pData->mpBorderWindow->Invalidate( pData->maCloseRect );
+ if( pData->mnMenuState != oldMenuState )
+ pData->mpBorderWindow->Invalidate( pData->maMenuRect );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplBorderWindowView::ImplMouseButtonDown( ImplBorderFrameData* pData, const MouseEvent& rMEvt )
+{
+ ImplBorderWindow* pBorderWindow = pData->mpBorderWindow;
+
+ if ( rMEvt.IsLeft() || rMEvt.IsRight() )
+ {
+ pData->maMouseOff = rMEvt.GetPosPixel();
+ pData->mnHitTest = ImplHitTest( pData, pData->maMouseOff );
+ USHORT nDragFullTest = 0;
+ if ( pData->mnHitTest )
+ {
+ BOOL bTracking = TRUE;
+ BOOL bHitTest = TRUE;
+
+ if ( pData->mnHitTest & BORDERWINDOW_HITTEST_CLOSE )
+ {
+ pData->mnCloseState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_CLOSE );
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_ROLL )
+ {
+ pData->mnRollState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_ROLL );
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_DOCK )
+ {
+ pData->mnDockState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_DOCK );
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_MENU )
+ {
+ pData->mnMenuState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_MENU );
+
+ // call handler already on mouse down
+ if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() )
+ {
+ SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow());
+ pClientWindow->TitleButtonClick( TITLE_BUTTON_MENU );
+ }
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HIDE )
+ {
+ pData->mnHideState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HIDE );
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HELP )
+ {
+ pData->mnHelpState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HELP );
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_PIN )
+ {
+ pData->mnPinState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_PIN );
+ }
+ else
+ {
+ if ( rMEvt.GetClicks() == 1 )
+ {
+ if ( bTracking )
+ {
+ Point aPos = pBorderWindow->GetPosPixel();
+ Size aSize = pBorderWindow->GetOutputSizePixel();
+ pData->mnTrackX = aPos.X();
+ pData->mnTrackY = aPos.Y();
+ pData->mnTrackWidth = aSize.Width();
+ pData->mnTrackHeight = aSize.Height();
+
+ if ( pData->mnHitTest & BORDERWINDOW_HITTEST_TITLE )
+ nDragFullTest = DRAGFULL_OPTION_WINDOWMOVE;
+ else
+ nDragFullTest = DRAGFULL_OPTION_WINDOWSIZE;
+ }
+ }
+ else
+ {
+ bTracking = FALSE;
+
+ if ( (pData->mnHitTest & BORDERWINDOW_DRAW_TITLE) &&
+ ((rMEvt.GetClicks() % 2) == 0) )
+ {
+ pData->mnHitTest = 0;
+ bHitTest = FALSE;
+
+ if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() )
+ {
+ SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow());
+ if ( TRUE /*pBorderWindow->mbDockBtn*/ ) // always perform docking on double click, no button required
+ pClientWindow->TitleButtonClick( TITLE_BUTTON_DOCKING );
+ else if ( pBorderWindow->GetStyle() & WB_ROLLABLE )
+ {
+ if ( pClientWindow->IsRollUp() )
+ pClientWindow->RollDown();
+ else
+ pClientWindow->RollUp();
+ pClientWindow->Roll();
+ }
+ }
+ }
+ }
+ }
+
+ if ( bTracking )
+ {
+ pData->mbDragFull = FALSE;
+ if ( nDragFullTest )
+ pData->mbDragFull = TRUE; // always fulldrag for proper docking, ignore system settings
+ pBorderWindow->StartTracking();
+ }
+ else if ( bHitTest )
+ pData->mnHitTest = 0;
+ }
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplBorderWindowView::ImplTracking( ImplBorderFrameData* pData, const TrackingEvent& rTEvt )
+{
+ ImplBorderWindow* pBorderWindow = pData->mpBorderWindow;
+
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ USHORT nHitTest = pData->mnHitTest;
+ pData->mnHitTest = 0;
+
+ if ( nHitTest & BORDERWINDOW_HITTEST_CLOSE )
+ {
+ if ( pData->mnCloseState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnCloseState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_CLOSE );
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ // dispatch to correct window type (why is Close() not virtual ??? )
+ // TODO: make Close() virtual
+ Window *pWin = pBorderWindow->ImplGetClientWindow()->ImplGetWindow();
+ SystemWindow *pSysWin = dynamic_cast<SystemWindow* >(pWin);
+ DockingWindow *pDockWin = dynamic_cast<DockingWindow*>(pWin);
+ if ( pSysWin )
+ pSysWin->Close();
+ else if ( pDockWin )
+ pDockWin->Close();
+ }
+ }
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_ROLL )
+ {
+ if ( pData->mnRollState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnRollState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_ROLL );
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() )
+ {
+ SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow());
+ if ( pClientWindow->IsRollUp() )
+ pClientWindow->RollDown();
+ else
+ pClientWindow->RollUp();
+ pClientWindow->Roll();
+ }
+ }
+ }
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_DOCK )
+ {
+ if ( pData->mnDockState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnDockState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_DOCK );
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() )
+ {
+ SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow());
+ pClientWindow->TitleButtonClick( TITLE_BUTTON_DOCKING );
+ }
+ }
+ }
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_MENU )
+ {
+ if ( pData->mnMenuState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnMenuState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_MENU );
+
+ // handler already called on mouse down
+ }
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_HIDE )
+ {
+ if ( pData->mnHideState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnHideState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HIDE );
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() )
+ {
+ SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow());
+ pClientWindow->TitleButtonClick( TITLE_BUTTON_HIDE );
+ }
+ }
+ }
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_HELP )
+ {
+ if ( pData->mnHelpState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnHelpState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HELP );
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ }
+ }
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_PIN )
+ {
+ if ( pData->mnPinState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnPinState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_PIN );
+
+ // Bei Abbruch kein Click-Handler rufen
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() )
+ {
+ SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow());
+ pClientWindow->SetPin( !pClientWindow->IsPined() );
+ pClientWindow->Pin();
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( pData->mbDragFull )
+ {
+ // Bei Abbruch alten Zustand wieder herstellen
+ if ( rTEvt.IsTrackingCanceled() )
+ pBorderWindow->SetPosSizePixel( Point( pData->mnTrackX, pData->mnTrackY ), Size( pData->mnTrackWidth, pData->mnTrackHeight ) );
+ }
+ else
+ {
+ pBorderWindow->HideTracking();
+ if ( !rTEvt.IsTrackingCanceled() )
+ pBorderWindow->SetPosSizePixel( Point( pData->mnTrackX, pData->mnTrackY ), Size( pData->mnTrackWidth, pData->mnTrackHeight ) );
+ }
+
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ if ( pBorderWindow->ImplGetClientWindow()->ImplIsFloatingWindow() )
+ {
+ if ( ((FloatingWindow*)pBorderWindow->ImplGetClientWindow())->IsInPopupMode() )
+ ((FloatingWindow*)pBorderWindow->ImplGetClientWindow())->EndPopupMode( FLOATWIN_POPUPMODEEND_TEAROFF );
+ }
+ }
+ }
+ }
+ else if ( !rTEvt.GetMouseEvent().IsSynthetic() )
+ {
+ Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
+
+ if ( pData->mnHitTest & BORDERWINDOW_HITTEST_CLOSE )
+ {
+ if ( pData->maCloseRect.IsInside( aMousePos ) )
+ {
+ if ( !(pData->mnCloseState & BUTTON_DRAW_PRESSED) )
+ {
+ pData->mnCloseState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_CLOSE );
+ }
+ }
+ else
+ {
+ if ( pData->mnCloseState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnCloseState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_CLOSE );
+ }
+ }
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_ROLL )
+ {
+ if ( pData->maRollRect.IsInside( aMousePos ) )
+ {
+ if ( !(pData->mnRollState & BUTTON_DRAW_PRESSED) )
+ {
+ pData->mnRollState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_ROLL );
+ }
+ }
+ else
+ {
+ if ( pData->mnRollState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnRollState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_ROLL );
+ }
+ }
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_DOCK )
+ {
+ if ( pData->maDockRect.IsInside( aMousePos ) )
+ {
+ if ( !(pData->mnDockState & BUTTON_DRAW_PRESSED) )
+ {
+ pData->mnDockState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_DOCK );
+ }
+ }
+ else
+ {
+ if ( pData->mnDockState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnDockState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_DOCK );
+ }
+ }
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_MENU )
+ {
+ if ( pData->maMenuRect.IsInside( aMousePos ) )
+ {
+ if ( !(pData->mnMenuState & BUTTON_DRAW_PRESSED) )
+ {
+ pData->mnMenuState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_MENU );
+
+ }
+ }
+ else
+ {
+ if ( pData->mnMenuState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnMenuState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_MENU );
+ }
+ }
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HIDE )
+ {
+ if ( pData->maHideRect.IsInside( aMousePos ) )
+ {
+ if ( !(pData->mnHideState & BUTTON_DRAW_PRESSED) )
+ {
+ pData->mnHideState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HIDE );
+ }
+ }
+ else
+ {
+ if ( pData->mnHideState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnHideState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HIDE );
+ }
+ }
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HELP )
+ {
+ if ( pData->maHelpRect.IsInside( aMousePos ) )
+ {
+ if ( !(pData->mnHelpState & BUTTON_DRAW_PRESSED) )
+ {
+ pData->mnHelpState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HELP );
+ }
+ }
+ else
+ {
+ if ( pData->mnHelpState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnHelpState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_HELP );
+ }
+ }
+ }
+ else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_PIN )
+ {
+ if ( pData->maPinRect.IsInside( aMousePos ) )
+ {
+ if ( !(pData->mnPinState & BUTTON_DRAW_PRESSED) )
+ {
+ pData->mnPinState |= BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_PIN );
+ }
+ }
+ else
+ {
+ if ( pData->mnPinState & BUTTON_DRAW_PRESSED )
+ {
+ pData->mnPinState &= ~BUTTON_DRAW_PRESSED;
+ DrawWindow( BORDERWINDOW_DRAW_PIN );
+ }
+ }
+ }
+ else
+ {
+ /*
+ // adjusting mousepos not required, we allow the whole screen (no desktop anymore...)
+ Point aFrameMousePos = pBorderWindow->ImplOutputToFrame( aMousePos );
+ Size aFrameSize = pBorderWindow->ImplGetFrameWindow()->GetOutputSizePixel();
+ if ( aFrameMousePos.X() < 0 )
+ aFrameMousePos.X() = 0;
+ if ( aFrameMousePos.Y() < 0 )
+ aFrameMousePos.Y() = 0;
+ if ( aFrameMousePos.X() > aFrameSize.Width()-1 )
+ aFrameMousePos.X() = aFrameSize.Width()-1;
+ if ( aFrameMousePos.Y() > aFrameSize.Height()-1 )
+ aFrameMousePos.Y() = aFrameSize.Height()-1;
+ aMousePos = pBorderWindow->ImplFrameToOutput( aFrameMousePos );
+ */
+
+ aMousePos.X() -= pData->maMouseOff.X();
+ aMousePos.Y() -= pData->maMouseOff.Y();
+
+ if ( pData->mnHitTest & BORDERWINDOW_HITTEST_TITLE )
+ {
+ pData->mpBorderWindow->SetPointer( Pointer( POINTER_MOVE ) );
+
+ Point aPos = pBorderWindow->GetPosPixel();
+ aPos.X() += aMousePos.X();
+ aPos.Y() += aMousePos.Y();
+ if ( pData->mbDragFull )
+ {
+ pBorderWindow->SetPosPixel( aPos );
+ pBorderWindow->ImplUpdateAll();
+ pBorderWindow->ImplGetFrameWindow()->ImplUpdateAll();
+ }
+ else
+ {
+ pData->mnTrackX = aPos.X();
+ pData->mnTrackY = aPos.Y();
+ pBorderWindow->ShowTracking( Rectangle( pBorderWindow->ScreenToOutputPixel( aPos ), pBorderWindow->GetOutputSizePixel() ), SHOWTRACK_BIG );
+ }
+ }
+ else
+ {
+ Point aOldPos = pBorderWindow->GetPosPixel();
+ Size aSize = pBorderWindow->GetSizePixel();
+ Rectangle aNewRect( aOldPos, aSize );
+ long nOldWidth = aSize.Width();
+ long nOldHeight = aSize.Height();
+ long nBorderWidth = pData->mnLeftBorder+pData->mnRightBorder;
+ long nBorderHeight = pData->mnTopBorder+pData->mnBottomBorder;
+ long nMinWidth = pBorderWindow->mnMinWidth+nBorderWidth;
+ long nMinHeight = pBorderWindow->mnMinHeight+nBorderHeight;
+ long nMinWidth2 = nBorderWidth;
+ long nMaxWidth = pBorderWindow->mnMaxWidth+nBorderWidth;
+ long nMaxHeight = pBorderWindow->mnMaxHeight+nBorderHeight;
+
+ if ( pData->mnTitleHeight )
+ {
+ nMinWidth2 += 4;
+
+ if ( pBorderWindow->GetStyle() & WB_CLOSEABLE )
+ nMinWidth2 += pData->maCloseRect.GetWidth();
+ }
+ if ( nMinWidth2 > nMinWidth )
+ nMinWidth = nMinWidth2;
+ if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_LEFT | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_BOTTOMLEFT) )
+ {
+ aNewRect.Left() += aMousePos.X();
+ if ( aNewRect.GetWidth() < nMinWidth )
+ aNewRect.Left() = aNewRect.Right()-nMinWidth+1;
+ else if ( aNewRect.GetWidth() > nMaxWidth )
+ aNewRect.Left() = aNewRect.Right()-nMaxWidth+1;
+ }
+ else if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_RIGHT | BORDERWINDOW_HITTEST_TOPRIGHT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) )
+ {
+ aNewRect.Right() += aMousePos.X();
+ if ( aNewRect.GetWidth() < nMinWidth )
+ aNewRect.Right() = aNewRect.Left()+nMinWidth+1;
+ else if ( aNewRect.GetWidth() > nMaxWidth )
+ aNewRect.Right() = aNewRect.Left()+nMaxWidth+1;
+ }
+ if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_TOP | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_TOPRIGHT) )
+ {
+ aNewRect.Top() += aMousePos.Y();
+ if ( aNewRect.GetHeight() < nMinHeight )
+ aNewRect.Top() = aNewRect.Bottom()-nMinHeight+1;
+ else if ( aNewRect.GetHeight() > nMaxHeight )
+ aNewRect.Top() = aNewRect.Bottom()-nMaxHeight+1;
+ }
+ else if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_BOTTOM | BORDERWINDOW_HITTEST_BOTTOMLEFT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) )
+ {
+ aNewRect.Bottom() += aMousePos.Y();
+ if ( aNewRect.GetHeight() < nMinHeight )
+ aNewRect.Bottom() = aNewRect.Top()+nMinHeight+1;
+ else if ( aNewRect.GetHeight() > nMaxHeight )
+ aNewRect.Bottom() = aNewRect.Top()+nMaxHeight+1;
+ }
+
+ // call Resizing-Handler for SystemWindows
+ if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() )
+ {
+ // adjust size for Resizing-call
+ aSize = aNewRect.GetSize();
+ aSize.Width() -= nBorderWidth;
+ aSize.Height() -= nBorderHeight;
+ ((SystemWindow*)pBorderWindow->ImplGetClientWindow())->Resizing( aSize );
+ aSize.Width() += nBorderWidth;
+ aSize.Height() += nBorderHeight;
+ if ( aSize.Width() < nMinWidth )
+ aSize.Width() = nMinWidth;
+ if ( aSize.Height() < nMinHeight )
+ aSize.Height() = nMinHeight;
+ if ( aSize.Width() > nMaxWidth )
+ aSize.Width() = nMaxWidth;
+ if ( aSize.Height() > nMaxHeight )
+ aSize.Height() = nMaxHeight;
+ if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_LEFT | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_BOTTOMLEFT) )
+ aNewRect.Left() = aNewRect.Right()-aSize.Width()+1;
+ else
+ aNewRect.Right() = aNewRect.Left()+aSize.Width()-1;
+ if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_TOP | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_TOPRIGHT) )
+ aNewRect.Top() = aNewRect.Bottom()-aSize.Height()+1;
+ else
+ aNewRect.Bottom() = aNewRect.Top()+aSize.Height()-1;
+ }
+
+ if ( pData->mbDragFull )
+ {
+ // no move (only resize) if position did not change
+ if( aOldPos != aNewRect.TopLeft() )
+ pBorderWindow->SetPosSizePixel( aNewRect.Left(), aNewRect.Top(),
+ aNewRect.GetWidth(), aNewRect.GetHeight(), WINDOW_POSSIZE_POSSIZE );
+ else
+ pBorderWindow->SetPosSizePixel( aNewRect.Left(), aNewRect.Top(),
+ aNewRect.GetWidth(), aNewRect.GetHeight(), WINDOW_POSSIZE_SIZE );
+
+ pBorderWindow->ImplUpdateAll();
+ pBorderWindow->ImplGetFrameWindow()->ImplUpdateAll();
+ if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_RIGHT | BORDERWINDOW_HITTEST_TOPRIGHT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) )
+ pData->maMouseOff.X() += aNewRect.GetWidth()-nOldWidth;
+ if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_BOTTOM | BORDERWINDOW_HITTEST_BOTTOMLEFT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) )
+ pData->maMouseOff.Y() += aNewRect.GetHeight()-nOldHeight;
+ }
+ else
+ {
+ pData->mnTrackX = aNewRect.Left();
+ pData->mnTrackY = aNewRect.Top();
+ pData->mnTrackWidth = aNewRect.GetWidth();
+ pData->mnTrackHeight = aNewRect.GetHeight();
+ pBorderWindow->ShowTracking( Rectangle( pBorderWindow->ScreenToOutputPixel( aNewRect.TopLeft() ), aNewRect.GetSize() ), SHOWTRACK_BIG );
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+String ImplBorderWindowView::ImplRequestHelp( ImplBorderFrameData* pData,
+ const Point& rPos,
+ Rectangle& rHelpRect )
+{
+ USHORT nHelpId = 0;
+ String aHelpStr;
+ USHORT nHitTest = ImplHitTest( pData, rPos );
+ if ( nHitTest )
+ {
+ if ( nHitTest & BORDERWINDOW_HITTEST_CLOSE )
+ {
+ nHelpId = SV_HELPTEXT_CLOSE;
+ rHelpRect = pData->maCloseRect;
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_ROLL )
+ {
+ if ( pData->mpBorderWindow->mbRollUp )
+ nHelpId = SV_HELPTEXT_ROLLDOWN;
+ else
+ nHelpId = SV_HELPTEXT_ROLLUP;
+ rHelpRect = pData->maRollRect;
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_DOCK )
+ {
+ nHelpId = SV_HELPTEXT_MAXIMIZE;
+ rHelpRect = pData->maDockRect;
+ }
+ /* no help string available
+ else if ( nHitTest & BORDERWINDOW_HITTEST_MENU )
+ {
+ nHelpId = SV_HELPTEXT_MENU;
+ rHelpRect = pData->maMenuRect;
+ }*/
+ else if ( nHitTest & BORDERWINDOW_HITTEST_HIDE )
+ {
+ nHelpId = SV_HELPTEXT_MINIMIZE;
+ rHelpRect = pData->maHideRect;
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_HELP )
+ {
+ nHelpId = SV_HELPTEXT_HELP;
+ rHelpRect = pData->maHelpRect;
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_PIN )
+ {
+ nHelpId = SV_HELPTEXT_ALWAYSVISIBLE;
+ rHelpRect = pData->maPinRect;
+ }
+ else if ( nHitTest & BORDERWINDOW_HITTEST_TITLE )
+ {
+ if( !pData->maTitleRect.IsEmpty() )
+ {
+ // tooltip only if title truncated
+ if( pData->mbTitleClipped )
+ {
+ rHelpRect = pData->maTitleRect;
+ // no help id, use window title as help string
+ aHelpStr = pData->mpBorderWindow->GetText();
+ }
+ }
+ }
+ }
+
+ if( nHelpId && ImplGetResMgr() )
+ aHelpStr = String( ResId( nHelpId, *ImplGetResMgr() ) );
+
+ return aHelpStr;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplBorderWindowView::ImplCalcTitleWidth( const ImplBorderFrameData* pData ) const
+{
+ // kein sichtbarer Title, dann auch keine Breite
+ if ( !pData->mnTitleHeight )
+ return 0;
+
+ ImplBorderWindow* pBorderWindow = pData->mpBorderWindow;
+ long nTitleWidth = pBorderWindow->GetTextWidth( pBorderWindow->GetText() )+6;
+ nTitleWidth += pData->maPinRect.GetWidth();
+ nTitleWidth += pData->maCloseRect.GetWidth();
+ nTitleWidth += pData->maRollRect.GetWidth();
+ nTitleWidth += pData->maDockRect.GetWidth();
+ nTitleWidth += pData->maMenuRect.GetWidth();
+ nTitleWidth += pData->maHideRect.GetWidth();
+ nTitleWidth += pData->maHelpRect.GetWidth();
+ nTitleWidth += pData->mnLeftBorder+pData->mnRightBorder;
+ return nTitleWidth;
+}
+
+// =======================================================================
+
+// --------------------------
+// - ImplNoBorderWindowView -
+// --------------------------
+
+ImplNoBorderWindowView::ImplNoBorderWindowView( ImplBorderWindow* )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ImplNoBorderWindowView::Init( OutputDevice*, long, long )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ImplNoBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
+{
+ rLeftBorder = 0;
+ rTopBorder = 0;
+ rRightBorder = 0;
+ rBottomBorder = 0;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplNoBorderWindowView::CalcTitleWidth() const
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplNoBorderWindowView::DrawWindow( USHORT, OutputDevice*, const Point* )
+{
+}
+
+// =======================================================================
+
+// -----------------------------
+// - ImplSmallBorderWindowView -
+// -----------------------------
+
+// =======================================================================
+
+ImplSmallBorderWindowView::ImplSmallBorderWindowView( ImplBorderWindow* pBorderWindow )
+{
+ mpBorderWindow = pBorderWindow;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSmallBorderWindowView::Init( OutputDevice* pDev, long nWidth, long nHeight )
+{
+ mpOutDev = pDev;
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ mbNWFBorder = false;
+
+ USHORT nBorderStyle = mpBorderWindow->GetBorderStyle();
+ if ( nBorderStyle & WINDOW_BORDER_NOBORDER )
+ {
+ mnLeftBorder = 0;
+ mnTopBorder = 0;
+ mnRightBorder = 0;
+ mnBottomBorder = 0;
+ }
+ else
+ {
+ // FIXME: this is currently only on aqua, check with other
+ // platforms
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects )
+ {
+ // for native widget drawing we must find out what
+ // control this border belongs to
+ Window *pWin = NULL, *pCtrl = NULL;
+ if( mpOutDev->GetOutDevType() == OUTDEV_WINDOW )
+ pWin = (Window*) mpOutDev;
+
+ ControlType aCtrlType = 0;
+ if( pWin && (pCtrl = mpBorderWindow->GetWindow( WINDOW_CLIENT )) != NULL )
+ {
+ switch( pCtrl->GetType() )
+ {
+ case WINDOW_LISTBOX:
+ if( pCtrl->GetStyle() & WB_DROPDOWN )
+ {
+ aCtrlType = CTRL_LISTBOX;
+ mbNWFBorder = true;
+ }
+ break;
+ case WINDOW_COMBOBOX:
+ if( pCtrl->GetStyle() & WB_DROPDOWN )
+ {
+ aCtrlType = CTRL_COMBOBOX;
+ mbNWFBorder = true;
+ }
+ break;
+ case WINDOW_MULTILINEEDIT:
+ aCtrlType = CTRL_MULTILINE_EDITBOX;
+ mbNWFBorder = true;
+ break;
+ case WINDOW_EDIT:
+ case WINDOW_PATTERNFIELD:
+ case WINDOW_METRICFIELD:
+ case WINDOW_CURRENCYFIELD:
+ case WINDOW_DATEFIELD:
+ case WINDOW_TIMEFIELD:
+ case WINDOW_LONGCURRENCYFIELD:
+ case WINDOW_NUMERICFIELD:
+ case WINDOW_SPINFIELD:
+ mbNWFBorder = true;
+ aCtrlType = (pCtrl->GetStyle() & WB_SPIN) ? CTRL_SPINBOX : CTRL_EDITBOX;
+ break;
+ default:
+ break;
+ }
+ }
+ if( mbNWFBorder )
+ {
+ ImplControlValue aControlValue;
+ Rectangle aCtrlRegion( (const Point&)Point(), Size( mnWidth < 10 ? 10 : mnWidth, mnHeight < 10 ? 10 : mnHeight ) );
+ Rectangle aBounds( aCtrlRegion );
+ Rectangle aContent( aCtrlRegion );
+ if( pWin->GetNativeControlRegion( aCtrlType, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBounds, aContent ) )
+ {
+ mnLeftBorder = aContent.Left() - aBounds.Left();
+ mnRightBorder = aBounds.Right() - aContent.Right();
+ mnTopBorder = aContent.Top() - aBounds.Top();
+ mnBottomBorder = aBounds.Bottom() - aContent.Bottom();
+ if( mnWidth && mnHeight )
+ {
+
+ mpBorderWindow->SetPaintTransparent( TRUE );
+ mpBorderWindow->SetBackground();
+ pCtrl->SetPaintTransparent( TRUE );
+
+ Window* pCompoundParent = NULL;
+ if( pWin->GetParent() && pWin->GetParent()->IsCompoundControl() )
+ pCompoundParent = pWin->GetParent();
+
+ if( pCompoundParent )
+ pCompoundParent->SetPaintTransparent( TRUE );
+
+ if( mnWidth < aBounds.GetWidth() || mnHeight < aBounds.GetHeight() )
+ {
+ if( ! pCompoundParent ) // compound controls have to fix themselves
+ {
+ Point aPos( mpBorderWindow->GetPosPixel() );
+ if( mnWidth < aBounds.GetWidth() )
+ aPos.X() -= (aBounds.GetWidth() - mnWidth) / 2;
+ if( mnHeight < aBounds.GetHeight() )
+ aPos.Y() -= (aBounds.GetHeight() - mnHeight) / 2;
+ mpBorderWindow->SetPosSizePixel( aPos, aBounds.GetSize() );
+ }
+ }
+ }
+ }
+ else
+ mbNWFBorder = false;
+ }
+ }
+
+ if( ! mbNWFBorder )
+ {
+ USHORT nStyle = FRAME_DRAW_NODRAW;
+ // Wenn Border umgesetzt wurde oder BorderWindow ein Frame-Fenster
+ // ist, dann Border nach aussen
+ if ( (nBorderStyle & WINDOW_BORDER_DOUBLEOUT) || mpBorderWindow->mbSmallOutBorder )
+ nStyle |= FRAME_DRAW_DOUBLEOUT;
+ else
+ nStyle |= FRAME_DRAW_DOUBLEIN;
+ if ( nBorderStyle & WINDOW_BORDER_MONO )
+ nStyle |= FRAME_DRAW_MONO;
+
+ DecorationView aDecoView( mpOutDev );
+ Rectangle aRect( 0, 0, 10, 10 );
+ Rectangle aCalcRect = aDecoView.DrawFrame( aRect, nStyle );
+ mnLeftBorder = aCalcRect.Left();
+ mnTopBorder = aCalcRect.Top();
+ mnRightBorder = aRect.Right()-aCalcRect.Right();
+ mnBottomBorder = aRect.Bottom()-aCalcRect.Bottom();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSmallBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
+{
+ rLeftBorder = mnLeftBorder;
+ rTopBorder = mnTopBorder;
+ rRightBorder = mnRightBorder;
+ rBottomBorder = mnBottomBorder;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplSmallBorderWindowView::CalcTitleWidth() const
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSmallBorderWindowView::DrawWindow( USHORT nDrawFlags, OutputDevice*, const Point* )
+{
+ USHORT nBorderStyle = mpBorderWindow->GetBorderStyle();
+ if ( nBorderStyle & WINDOW_BORDER_NOBORDER )
+ return;
+
+ BOOL bNativeOK = FALSE;
+ // for native widget drawing we must find out what
+ // control this border belongs to
+ Window *pWin = NULL, *pCtrl = NULL;
+ if( mpOutDev->GetOutDevType() == OUTDEV_WINDOW )
+ pWin = (Window*) mpOutDev;
+
+ ControlType aCtrlType = 0;
+ ControlPart aCtrlPart = PART_ENTIRE_CONTROL;
+
+ if( pWin && (pCtrl = mpBorderWindow->GetWindow( WINDOW_CLIENT )) != NULL )
+ {
+ switch( pCtrl->GetType() )
+ {
+ case WINDOW_MULTILINEEDIT:
+ aCtrlType = CTRL_MULTILINE_EDITBOX;
+ break;
+ case WINDOW_EDIT:
+ case WINDOW_PATTERNFIELD:
+ case WINDOW_METRICFIELD:
+ case WINDOW_CURRENCYFIELD:
+ case WINDOW_DATEFIELD:
+ case WINDOW_TIMEFIELD:
+ case WINDOW_LONGCURRENCYFIELD:
+ case WINDOW_NUMERICFIELD:
+ case WINDOW_SPINFIELD:
+ if( pCtrl->GetStyle() & WB_SPIN )
+ aCtrlType = CTRL_SPINBOX;
+ else
+ aCtrlType = CTRL_EDITBOX;
+ break;
+
+ case WINDOW_LISTBOX:
+ case WINDOW_MULTILISTBOX:
+ case WINDOW_TREELISTBOX:
+ aCtrlType = CTRL_LISTBOX;
+ if( pCtrl->GetStyle() & WB_DROPDOWN )
+ aCtrlPart = PART_ENTIRE_CONTROL;
+ else
+ aCtrlPart = PART_WINDOW;
+ break;
+
+ case WINDOW_LISTBOXWINDOW:
+ aCtrlType = CTRL_LISTBOX;
+ aCtrlPart = PART_WINDOW;
+ break;
+
+ case WINDOW_COMBOBOX:
+ case WINDOW_PATTERNBOX:
+ case WINDOW_NUMERICBOX:
+ case WINDOW_METRICBOX:
+ case WINDOW_CURRENCYBOX:
+ case WINDOW_DATEBOX:
+ case WINDOW_TIMEBOX:
+ case WINDOW_LONGCURRENCYBOX:
+ if( pCtrl->GetStyle() & WB_DROPDOWN )
+ {
+ aCtrlType = CTRL_COMBOBOX;
+ aCtrlPart = PART_ENTIRE_CONTROL;
+ }
+ else
+ {
+ aCtrlType = CTRL_LISTBOX;
+ aCtrlPart = PART_WINDOW;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ( aCtrlType && pCtrl->IsNativeControlSupported(aCtrlType, aCtrlPart) )
+ {
+ ImplControlValue aControlValue;
+ ControlState nState = CTRL_STATE_ENABLED;
+
+ if ( !pWin->IsEnabled() )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( pWin->HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ else if( mbNWFBorder )
+ {
+ // FIXME: this is curently only on aqua, see if other platforms can profit
+
+ // FIXME: for aqua focus rings all controls need to support GetNativeControlRegion
+ // for the dropdown style
+ if( pCtrl->HasFocus() || pCtrl->HasChildPathFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ }
+
+ BOOL bMouseOver = FALSE;
+ Window *pCtrlChild = pCtrl->GetWindow( WINDOW_FIRSTCHILD );
+ while( pCtrlChild && (bMouseOver = pCtrlChild->IsMouseOver()) == FALSE )
+ pCtrlChild = pCtrlChild->GetWindow( WINDOW_NEXT );
+
+ if( bMouseOver )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ Point aPoint;
+ Rectangle aCtrlRegion( aPoint, Size( mnWidth, mnHeight ) );
+
+ Rectangle aBoundingRgn( aPoint, Size( mnWidth, mnHeight ) );
+ Rectangle aContentRgn( aCtrlRegion );
+ if(pWin->GetNativeControlRegion( aCtrlType, aCtrlPart, aCtrlRegion,
+ nState, aControlValue, rtl::OUString(), aBoundingRgn, aContentRgn ))
+ {
+ aCtrlRegion=aContentRgn;
+ }
+
+ bNativeOK = pWin->DrawNativeControl( aCtrlType, aCtrlPart, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() );
+
+ // if the native theme draws the spinbuttons in one call, make sure the proper settings
+ // are passed, this might force a redraw though.... (TODO: improve)
+ if ( (aCtrlType == CTRL_SPINBOX) && !pCtrl->IsNativeControlSupported( CTRL_SPINBOX, PART_BUTTON_UP ) )
+ {
+ Edit *pEdit = ((Edit*) pCtrl)->GetSubEdit();
+ if ( pEdit )
+ pCtrl->Paint( Rectangle() ); // make sure the buttons are also drawn as they might overwrite the border
+ }
+ }
+
+ if( bNativeOK )
+ return;
+
+ if ( nDrawFlags & BORDERWINDOW_DRAW_FRAME )
+ {
+ if ( nBorderStyle & WINDOW_BORDER_ACTIVE )
+ {
+ Color aColor = mpOutDev->GetSettings().GetStyleSettings().GetHighlightColor();
+ mpOutDev->SetLineColor();
+ mpOutDev->SetFillColor( aColor );
+ mpOutDev->DrawRect( Rectangle( 0, 0, mnWidth-1, mnTopBorder ) );
+ mpOutDev->DrawRect( Rectangle( 0, mnHeight-mnBottomBorder, mnWidth-1, mnHeight-1 ) );
+ mpOutDev->DrawRect( Rectangle( 0, 0, mnLeftBorder, mnHeight-1 ) );
+ mpOutDev->DrawRect( Rectangle( mnWidth-mnRightBorder, 0, mnWidth-1, mnHeight-1 ) );
+ }
+ else
+ {
+ USHORT nStyle = 0;
+ // Wenn Border umgesetzt wurde oder BorderWindow ein Frame-Fenster
+ // ist, dann Border nach aussen
+ if ( (nBorderStyle & WINDOW_BORDER_DOUBLEOUT) || mpBorderWindow->mbSmallOutBorder )
+ nStyle |= FRAME_DRAW_DOUBLEOUT;
+ else
+ nStyle |= FRAME_DRAW_DOUBLEIN;
+ if ( nBorderStyle & WINDOW_BORDER_MONO )
+ nStyle |= FRAME_DRAW_MONO;
+ if ( nBorderStyle & WINDOW_BORDER_MENU )
+ nStyle |= FRAME_DRAW_MENU;
+ // tell DrawFrame that we're drawing a window border of a frame window to avoid round corners
+ if( pWin && pWin == pWin->ImplGetFrameWindow() )
+ nStyle |= FRAME_DRAW_WINDOWBORDER;
+
+ DecorationView aDecoView( mpOutDev );
+ Point aTmpPoint;
+ Rectangle aInRect( aTmpPoint, Size( mnWidth, mnHeight ) );
+ aDecoView.DrawFrame( aInRect, nStyle );
+ }
+ }
+}
+
+// =======================================================================
+
+// ---------------------------
+// - ImplStdBorderWindowView -
+// ---------------------------
+
+ImplStdBorderWindowView::ImplStdBorderWindowView( ImplBorderWindow* pBorderWindow )
+{
+ maFrameData.mpBorderWindow = pBorderWindow;
+ maFrameData.mbDragFull = FALSE;
+ maFrameData.mnHitTest = 0;
+ maFrameData.mnPinState = 0;
+ maFrameData.mnCloseState = 0;
+ maFrameData.mnRollState = 0;
+ maFrameData.mnDockState = 0;
+ maFrameData.mnMenuState = 0;
+ maFrameData.mnHideState = 0;
+ maFrameData.mnHelpState = 0;
+ maFrameData.mbTitleClipped = 0;
+
+ mpATitleVirDev = NULL;
+ mpDTitleVirDev = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplStdBorderWindowView::~ImplStdBorderWindowView()
+{
+ if ( mpATitleVirDev )
+ delete mpATitleVirDev;
+ if ( mpDTitleVirDev )
+ delete mpDTitleVirDev;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplStdBorderWindowView::MouseMove( const MouseEvent& rMEvt )
+{
+ return ImplMouseMove( &maFrameData, rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplStdBorderWindowView::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ return ImplMouseButtonDown( &maFrameData, rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplStdBorderWindowView::Tracking( const TrackingEvent& rTEvt )
+{
+ return ImplTracking( &maFrameData, rTEvt );
+}
+
+// -----------------------------------------------------------------------
+
+String ImplStdBorderWindowView::RequestHelp( const Point& rPos, Rectangle& rHelpRect )
+{
+ return ImplRequestHelp( &maFrameData, rPos, rHelpRect );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ImplStdBorderWindowView::GetMenuRect() const
+{
+ return maFrameData.maMenuRect;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplStdBorderWindowView::Init( OutputDevice* pDev, long nWidth, long nHeight )
+{
+ ImplBorderFrameData* pData = &maFrameData;
+ ImplBorderWindow* pBorderWindow = maFrameData.mpBorderWindow;
+ const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
+ DecorationView aDecoView( pDev );
+ Rectangle aRect( 0, 0, 10, 10 );
+ Rectangle aCalcRect = aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEOUT | FRAME_DRAW_NODRAW );
+
+ pData->mpOutDev = pDev;
+ pData->mnWidth = nWidth;
+ pData->mnHeight = nHeight;
+
+ pData->mnTitleType = pBorderWindow->mnTitleType;
+ pData->mbFloatWindow = pBorderWindow->mbFloatWindow;
+
+ if ( !(pBorderWindow->GetStyle() & WB_MOVEABLE) || (pData->mnTitleType == BORDERWINDOW_TITLE_NONE) )
+ pData->mnBorderSize = 0;
+ else if ( pData->mnTitleType == BORDERWINDOW_TITLE_TEAROFF )
+ pData->mnBorderSize = 0;
+ else
+ pData->mnBorderSize = rStyleSettings.GetBorderSize();
+ pData->mnLeftBorder = aCalcRect.Left();
+ pData->mnTopBorder = aCalcRect.Top();
+ pData->mnRightBorder = aRect.Right()-aCalcRect.Right();
+ pData->mnBottomBorder = aRect.Bottom()-aCalcRect.Bottom();
+ pData->mnLeftBorder += pData->mnBorderSize;
+ pData->mnTopBorder += pData->mnBorderSize;
+ pData->mnRightBorder += pData->mnBorderSize;
+ pData->mnBottomBorder += pData->mnBorderSize;
+ pData->mnNoTitleTop = pData->mnTopBorder;
+
+ ImplInitTitle( &maFrameData );
+ if ( pData->mnTitleHeight )
+ {
+ // to improve symbol display force a minum title height
+ if( pData->mnTitleHeight < MIN_CAPTION_HEIGHT )
+ pData->mnTitleHeight = MIN_CAPTION_HEIGHT;
+
+ // set a proper background for drawing
+ // highlighted buttons in the title
+ pBorderWindow->SetBackground( rStyleSettings.GetWindowColor() );
+
+ pData->maTitleRect.Left() = pData->mnLeftBorder;
+ pData->maTitleRect.Right() = nWidth-pData->mnRightBorder-1;
+ pData->maTitleRect.Top() = pData->mnTopBorder;
+ pData->maTitleRect.Bottom() = pData->maTitleRect.Top()+pData->mnTitleHeight-1;
+
+ if ( pData->mnTitleType & (BORDERWINDOW_TITLE_NORMAL | BORDERWINDOW_TITLE_SMALL) )
+ {
+ long nLeft = pData->maTitleRect.Left();
+ long nRight = pData->maTitleRect.Right();
+ long nItemTop = pData->maTitleRect.Top();
+ long nItemBottom = pData->maTitleRect.Bottom();
+ nLeft += 1;
+ nRight -= 3;
+ nItemTop += 2;
+ nItemBottom -= 2;
+
+ if ( pBorderWindow->GetStyle() & WB_PINABLE )
+ {
+ Image aImage;
+ ImplGetPinImage( 0, 0, aImage );
+ pData->maPinRect.Top() = nItemTop;
+ pData->maPinRect.Bottom() = nItemBottom;
+ pData->maPinRect.Left() = nLeft;
+ pData->maPinRect.Right() = pData->maPinRect.Left()+aImage.GetSizePixel().Width();
+ nLeft += pData->maPinRect.GetWidth()+3;
+ }
+
+ if ( pBorderWindow->GetStyle() & WB_CLOSEABLE )
+ {
+ pData->maCloseRect.Top() = nItemTop;
+ pData->maCloseRect.Bottom() = nItemBottom;
+ pData->maCloseRect.Right() = nRight;
+ pData->maCloseRect.Left() = pData->maCloseRect.Right()-pData->maCloseRect.GetHeight()+1;
+ nRight -= pData->maCloseRect.GetWidth()+3;
+ }
+
+ if ( pBorderWindow->mbMenuBtn )
+ {
+ pData->maMenuRect.Top() = nItemTop;
+ pData->maMenuRect.Bottom() = nItemBottom;
+ pData->maMenuRect.Right() = nRight;
+ pData->maMenuRect.Left() = pData->maMenuRect.Right()-pData->maMenuRect.GetHeight()+1;
+ nRight -= pData->maMenuRect.GetWidth();
+ }
+
+ if ( pBorderWindow->mbDockBtn )
+ {
+ pData->maDockRect.Top() = nItemTop;
+ pData->maDockRect.Bottom() = nItemBottom;
+ pData->maDockRect.Right() = nRight;
+ pData->maDockRect.Left() = pData->maDockRect.Right()-pData->maDockRect.GetHeight()+1;
+ nRight -= pData->maDockRect.GetWidth();
+ if ( !pBorderWindow->mbHideBtn &&
+ !(pBorderWindow->GetStyle() & WB_ROLLABLE) )
+ nRight -= 3;
+ }
+
+ if ( pBorderWindow->mbHideBtn )
+ {
+ pData->maHideRect.Top() = nItemTop;
+ pData->maHideRect.Bottom() = nItemBottom;
+ pData->maHideRect.Right() = nRight;
+ pData->maHideRect.Left() = pData->maHideRect.Right()-pData->maHideRect.GetHeight()+1;
+ nRight -= pData->maHideRect.GetWidth();
+ if ( !(pBorderWindow->GetStyle() & WB_ROLLABLE) )
+ nRight -= 3;
+ }
+
+ if ( pBorderWindow->GetStyle() & WB_ROLLABLE )
+ {
+ pData->maRollRect.Top() = nItemTop;
+ pData->maRollRect.Bottom() = nItemBottom;
+ pData->maRollRect.Right() = nRight;
+ pData->maRollRect.Left() = pData->maRollRect.Right()-pData->maRollRect.GetHeight()+1;
+ nRight -= pData->maRollRect.GetWidth();
+ }
+
+ if ( pBorderWindow->mbHelpBtn )
+ {
+ pData->maHelpRect.Top() = nItemTop;
+ pData->maHelpRect.Bottom() = nItemBottom;
+ pData->maHelpRect.Right() = nRight;
+ pData->maHelpRect.Left() = pData->maHelpRect.Right()-pData->maHelpRect.GetHeight()+1;
+ nRight -= pData->maHelpRect.GetWidth()+3;
+ }
+ }
+ else
+ {
+ pData->maPinRect.SetEmpty();
+ pData->maCloseRect.SetEmpty();
+ pData->maDockRect.SetEmpty();
+ pData->maMenuRect.SetEmpty();
+ pData->maHideRect.SetEmpty();
+ pData->maRollRect.SetEmpty();
+ pData->maHelpRect.SetEmpty();
+ }
+
+ pData->mnTopBorder += pData->mnTitleHeight;
+ }
+ else
+ {
+ pData->maTitleRect.SetEmpty();
+ pData->maPinRect.SetEmpty();
+ pData->maCloseRect.SetEmpty();
+ pData->maDockRect.SetEmpty();
+ pData->maMenuRect.SetEmpty();
+ pData->maHideRect.SetEmpty();
+ pData->maRollRect.SetEmpty();
+ pData->maHelpRect.SetEmpty();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplStdBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
+{
+ rLeftBorder = maFrameData.mnLeftBorder;
+ rTopBorder = maFrameData.mnTopBorder;
+ rRightBorder = maFrameData.mnRightBorder;
+ rBottomBorder = maFrameData.mnBottomBorder;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplStdBorderWindowView::CalcTitleWidth() const
+{
+ return ImplCalcTitleWidth( &maFrameData );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplStdBorderWindowView::DrawWindow( USHORT nDrawFlags, OutputDevice* pOutDev, const Point* pOffset )
+{
+ ImplBorderFrameData* pData = &maFrameData;
+ OutputDevice* pDev = pOutDev ? pOutDev : pData->mpOutDev;
+ ImplBorderWindow* pBorderWindow = pData->mpBorderWindow;
+ Point aTmpPoint = pOffset ? Point(*pOffset) : Point();
+ Rectangle aInRect( aTmpPoint, Size( pData->mnWidth, pData->mnHeight ) );
+ const StyleSettings& rStyleSettings = pData->mpOutDev->GetSettings().GetStyleSettings();
+ DecorationView aDecoView( pDev );
+ Color aFrameColor( rStyleSettings.GetFaceColor() );
+
+ aFrameColor.DecreaseContrast( (UINT8) (0.50 * 255));
+
+ // Draw Frame
+ if ( nDrawFlags & BORDERWINDOW_DRAW_FRAME )
+ {
+ // single line frame
+ pDev->SetLineColor( aFrameColor );
+ pDev->SetFillColor();
+ pDev->DrawRect( aInRect );
+ aInRect.nLeft++; aInRect.nRight--;
+ aInRect.nTop++; aInRect.nBottom--;
+ }
+ else
+ aInRect = aDecoView.DrawFrame( aInRect, FRAME_DRAW_DOUBLEOUT | FRAME_DRAW_NODRAW);
+
+ // Draw Border
+ pDev->SetLineColor();
+ long nBorderSize = pData->mnBorderSize;
+ if ( (nDrawFlags & BORDERWINDOW_DRAW_BORDER) && nBorderSize )
+ {
+ pDev->SetFillColor( rStyleSettings.GetFaceColor() );
+ pDev->DrawRect( Rectangle( Point( aInRect.Left(), aInRect.Top() ),
+ Size( aInRect.GetWidth(), nBorderSize ) ) );
+ pDev->DrawRect( Rectangle( Point( aInRect.Left(), aInRect.Top()+nBorderSize ),
+ Size( nBorderSize, aInRect.GetHeight()-nBorderSize ) ) );
+ pDev->DrawRect( Rectangle( Point( aInRect.Left(), aInRect.Bottom()-nBorderSize+1 ),
+ Size( aInRect.GetWidth(), nBorderSize ) ) );
+ pDev->DrawRect( Rectangle( Point( aInRect.Right()-nBorderSize+1, aInRect.Top()+nBorderSize ),
+ Size( nBorderSize, aInRect.GetHeight()-nBorderSize ) ) );
+ }
+
+ // Draw Title
+ if ( (nDrawFlags & BORDERWINDOW_DRAW_TITLE) && !pData->maTitleRect.IsEmpty() )
+ {
+ aInRect = pData->maTitleRect;
+
+ // use no gradient anymore, just a static titlecolor
+ pDev->SetFillColor( aFrameColor );
+ pDev->SetTextColor( rStyleSettings.GetButtonTextColor() );
+ Rectangle aTitleRect( pData->maTitleRect );
+ if( pOffset )
+ aTitleRect.Move( pOffset->X(), pOffset->Y() );
+ pDev->DrawRect( aTitleRect );
+
+
+ if ( pData->mnTitleType != BORDERWINDOW_TITLE_TEAROFF )
+ {
+ aInRect.Left() += 2;
+ aInRect.Right() -= 2;
+
+ if ( !pData->maPinRect.IsEmpty() )
+ aInRect.Left() = pData->maPinRect.Right()+2;
+
+ if ( !pData->maHelpRect.IsEmpty() )
+ aInRect.Right() = pData->maHelpRect.Left()-2;
+ else if ( !pData->maRollRect.IsEmpty() )
+ aInRect.Right() = pData->maRollRect.Left()-2;
+ else if ( !pData->maHideRect.IsEmpty() )
+ aInRect.Right() = pData->maHideRect.Left()-2;
+ else if ( !pData->maDockRect.IsEmpty() )
+ aInRect.Right() = pData->maDockRect.Left()-2;
+ else if ( !pData->maMenuRect.IsEmpty() )
+ aInRect.Right() = pData->maMenuRect.Left()-2;
+ else if ( !pData->maCloseRect.IsEmpty() )
+ aInRect.Right() = pData->maCloseRect.Left()-2;
+
+ if ( pOffset )
+ aInRect.Move( pOffset->X(), pOffset->Y() );
+
+ USHORT nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER | TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_CLIP;
+
+ // must show tooltip ?
+ TextRectInfo aInfo;
+ pDev->GetTextRect( aInRect, pBorderWindow->GetText(), nTextStyle, &aInfo );
+ pData->mbTitleClipped = aInfo.IsEllipses();
+
+ pDev->DrawText( aInRect, pBorderWindow->GetText(), nTextStyle );
+ }
+ }
+
+ if ( ((nDrawFlags & BORDERWINDOW_DRAW_CLOSE) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) &&
+ !pData->maCloseRect.IsEmpty() )
+ {
+ Rectangle aSymbolRect( pData->maCloseRect );
+ if ( pOffset )
+ aSymbolRect.Move( pOffset->X(), pOffset->Y() );
+ ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_CLOSE, pData->mnCloseState );
+ }
+ if ( ((nDrawFlags & BORDERWINDOW_DRAW_DOCK) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) &&
+ !pData->maDockRect.IsEmpty() )
+ {
+ Rectangle aSymbolRect( pData->maDockRect );
+ if ( pOffset )
+ aSymbolRect.Move( pOffset->X(), pOffset->Y() );
+ ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_DOCK, pData->mnDockState );
+ }
+ if ( ((nDrawFlags & BORDERWINDOW_DRAW_MENU) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) &&
+ !pData->maMenuRect.IsEmpty() )
+ {
+ Rectangle aSymbolRect( pData->maMenuRect );
+ if ( pOffset )
+ aSymbolRect.Move( pOffset->X(), pOffset->Y() );
+ ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_MENU, pData->mnMenuState );
+ }
+ if ( ((nDrawFlags & BORDERWINDOW_DRAW_HIDE) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) &&
+ !pData->maHideRect.IsEmpty() )
+ {
+ Rectangle aSymbolRect( pData->maHideRect );
+ if ( pOffset )
+ aSymbolRect.Move( pOffset->X(), pOffset->Y() );
+ ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_HIDE, pData->mnHideState );
+ }
+ if ( ((nDrawFlags & BORDERWINDOW_DRAW_ROLL) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) &&
+ !pData->maRollRect.IsEmpty() )
+ {
+ SymbolType eType;
+ if ( pBorderWindow->mbRollUp )
+ eType = SYMBOL_ROLLDOWN;
+ else
+ eType = SYMBOL_ROLLUP;
+ Rectangle aSymbolRect( pData->maRollRect );
+ if ( pOffset )
+ aSymbolRect.Move( pOffset->X(), pOffset->Y() );
+ ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, eType, pData->mnRollState );
+ }
+
+ if ( ((nDrawFlags & BORDERWINDOW_DRAW_HELP) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) &&
+ !pData->maHelpRect.IsEmpty() )
+ {
+ Rectangle aSymbolRect( pData->maHelpRect );
+ if ( pOffset )
+ aSymbolRect.Move( pOffset->X(), pOffset->Y() );
+ ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_HELP, pData->mnHelpState );
+ }
+ if ( ((nDrawFlags & BORDERWINDOW_DRAW_PIN) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) &&
+ !pData->maPinRect.IsEmpty() )
+ {
+ Image aImage;
+ ImplGetPinImage( pData->mnPinState, pBorderWindow->mbPined, aImage );
+ Size aImageSize = aImage.GetSizePixel();
+ long nRectHeight = pData->maPinRect.GetHeight();
+ Point aPos( pData->maPinRect.TopLeft() );
+ if ( pOffset )
+ aPos.Move( pOffset->X(), pOffset->Y() );
+ if ( nRectHeight < aImageSize.Height() )
+ {
+ pDev->DrawImage( aPos, Size( aImageSize.Width(), nRectHeight ), aImage );
+ }
+ else
+ {
+ aPos.Y() += (nRectHeight-aImageSize.Height())/2;
+ pDev->DrawImage( aPos, aImage );
+ }
+ }
+}
+
+
+// =======================================================================
+void ImplBorderWindow::ImplInit( Window* pParent,
+ WinBits nStyle, USHORT nTypeStyle,
+ const ::com::sun::star::uno::Any& )
+{
+ ImplInit( pParent, nStyle, nTypeStyle, NULL );
+}
+
+void ImplBorderWindow::ImplInit( Window* pParent,
+ WinBits nStyle, USHORT nTypeStyle,
+ SystemParentData* pSystemParentData
+ )
+{
+ // Alle WindowBits entfernen, die wir nicht haben wollen
+ WinBits nOrgStyle = nStyle;
+ WinBits nTestStyle = (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_PINABLE | WB_CLOSEABLE | WB_STANDALONE | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_SYSTEMFLOATWIN | WB_INTROWIN | WB_DEFAULTWIN | WB_TOOLTIPWIN | WB_NOSHADOW | WB_OWNERDRAWDECORATION | WB_SYSTEMCHILDWINDOW | WB_NEEDSFOCUS);
+ if ( nTypeStyle & BORDERWINDOW_STYLE_APP )
+ nTestStyle |= WB_APP;
+ nStyle &= nTestStyle;
+
+ mpWindowImpl->mbBorderWin = TRUE;
+ mbSmallOutBorder = FALSE;
+ if ( nTypeStyle & BORDERWINDOW_STYLE_FRAME )
+ {
+ if( (nStyle & WB_SYSTEMCHILDWINDOW) )
+ {
+ mpWindowImpl->mbOverlapWin = TRUE;
+ mpWindowImpl->mbFrame = TRUE;
+ mbFrameBorder = FALSE;
+ }
+ else if( (nStyle & WB_OWNERDRAWDECORATION) )
+ {
+ mpWindowImpl->mbOverlapWin = TRUE;
+ mpWindowImpl->mbFrame = TRUE;
+ mbFrameBorder = (nOrgStyle & WB_NOBORDER) ? FALSE : TRUE;
+ }
+ else
+ {
+ mpWindowImpl->mbOverlapWin = TRUE;
+ mpWindowImpl->mbFrame = TRUE;
+ mbFrameBorder = FALSE;
+ // closeable windows may have a border as well, eg. system floating windows without caption
+ if ( (nOrgStyle & (WB_BORDER | WB_NOBORDER | WB_MOVEABLE | WB_SIZEABLE/* | WB_CLOSEABLE*/)) == WB_BORDER )
+ mbSmallOutBorder = TRUE;
+ }
+ }
+ else if ( nTypeStyle & BORDERWINDOW_STYLE_OVERLAP )
+ {
+ mpWindowImpl->mbOverlapWin = TRUE;
+ mbFrameBorder = TRUE;
+ }
+ else
+ mbFrameBorder = FALSE;
+
+ if ( nTypeStyle & BORDERWINDOW_STYLE_FLOAT )
+ mbFloatWindow = TRUE;
+ else
+ mbFloatWindow = FALSE;
+
+ Window::ImplInit( pParent, nStyle, pSystemParentData );
+ SetBackground();
+ SetTextFillColor();
+
+ mpMenuBarWindow = NULL;
+ mnMinWidth = 0;
+ mnMinHeight = 0;
+ mnMaxWidth = SHRT_MAX;
+ mnMaxHeight = SHRT_MAX;
+ mnRollHeight = 0;
+ mnOrgMenuHeight = 0;
+ mbPined = FALSE;
+ mbRollUp = FALSE;
+ mbMenuHide = FALSE;
+ mbDockBtn = FALSE;
+ mbMenuBtn = FALSE;
+ mbHideBtn = FALSE;
+ mbHelpBtn = FALSE;
+ mbDisplayActive = IsActive();
+
+ if ( nTypeStyle & BORDERWINDOW_STYLE_FLOAT )
+ mnTitleType = BORDERWINDOW_TITLE_SMALL;
+ else
+ mnTitleType = BORDERWINDOW_TITLE_NORMAL;
+ mnBorderStyle = WINDOW_BORDER_NORMAL;
+ InitView();
+}
+
+// =======================================================================
+
+ImplBorderWindow::ImplBorderWindow( Window* pParent,
+ SystemParentData* pSystemParentData,
+ WinBits nStyle, USHORT nTypeStyle
+ ) : Window( WINDOW_BORDERWINDOW )
+{
+ ImplInit( pParent, nStyle, nTypeStyle, pSystemParentData );
+}
+
+// -----------------------------------------------------------------------
+
+ImplBorderWindow::ImplBorderWindow( Window* pParent, WinBits nStyle ,
+ USHORT nTypeStyle ) :
+ Window( WINDOW_BORDERWINDOW )
+{
+ ImplInit( pParent, nStyle, nTypeStyle, ::com::sun::star::uno::Any() );
+}
+
+ImplBorderWindow::ImplBorderWindow( Window* pParent,
+ WinBits nStyle, USHORT nTypeStyle,
+ const ::com::sun::star::uno::Any& aSystemToken ) :
+ Window( WINDOW_BORDERWINDOW )
+{
+ ImplInit( pParent, nStyle, nTypeStyle, aSystemToken );
+}
+
+// -----------------------------------------------------------------------
+
+ImplBorderWindow::~ImplBorderWindow()
+{
+ delete mpBorderView;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ mpBorderView->MouseMove( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ mpBorderView->MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::Tracking( const TrackingEvent& rTEvt )
+{
+ mpBorderView->Tracking( rTEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::Paint( const Rectangle& )
+{
+ mpBorderView->DrawWindow( BORDERWINDOW_DRAW_ALL );
+}
+
+void ImplBorderWindow::Draw( const Rectangle&, OutputDevice* pOutDev, const Point& rPos )
+{
+ mpBorderView->DrawWindow( BORDERWINDOW_DRAW_ALL, pOutDev, &rPos );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::Activate()
+{
+ SetDisplayActive( TRUE );
+ Window::Activate();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::Deactivate()
+{
+ // Fenster die immer Active sind, nehmen wir von dieser Regel aus,
+ // genauso, wenn ein Menu aktiv wird, ignorieren wir das Deactivate
+ if ( GetActivateMode() && !ImplGetSVData()->maWinData.mbNoDeactivate )
+ SetDisplayActive( FALSE );
+ Window::Deactivate();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ // no keyboard help for border win
+ if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) && !rHEvt.KeyboardActivated() )
+ {
+ Point aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
+ Rectangle aHelpRect;
+ String aHelpStr( mpBorderView->RequestHelp( aMousePosPixel, aHelpRect ) );
+
+ // Rechteck ermitteln
+ if ( aHelpStr.Len() )
+ {
+ aHelpRect.SetPos( OutputToScreenPixel( aHelpRect.TopLeft() ) );
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aHelpStr );
+ else
+ Help::ShowQuickHelp( this, aHelpRect, aHelpStr );
+ return;
+ }
+ }
+
+ Window::RequestHelp( rHEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::Resize()
+{
+ Size aSize = GetOutputSizePixel();
+
+ if ( !mbRollUp )
+ {
+ Window* pClientWindow = ImplGetClientWindow();
+
+ if ( mpMenuBarWindow )
+ {
+ sal_Int32 nLeftBorder;
+ sal_Int32 nTopBorder;
+ sal_Int32 nRightBorder;
+ sal_Int32 nBottomBorder;
+ long nMenuHeight = mpMenuBarWindow->GetSizePixel().Height();
+ if ( mbMenuHide )
+ {
+ if ( nMenuHeight )
+ mnOrgMenuHeight = nMenuHeight;
+ nMenuHeight = 0;
+ }
+ else
+ {
+ if ( !nMenuHeight )
+ nMenuHeight = mnOrgMenuHeight;
+ }
+ mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder );
+ mpMenuBarWindow->SetPosSizePixel( nLeftBorder,
+ nTopBorder,
+ aSize.Width()-nLeftBorder-nRightBorder,
+ nMenuHeight,
+ WINDOW_POSSIZE_POS |
+ WINDOW_POSSIZE_WIDTH | WINDOW_POSSIZE_HEIGHT );
+ }
+
+ GetBorder( pClientWindow->mpWindowImpl->mnLeftBorder, pClientWindow->mpWindowImpl->mnTopBorder,
+ pClientWindow->mpWindowImpl->mnRightBorder, pClientWindow->mpWindowImpl->mnBottomBorder );
+ pClientWindow->ImplPosSizeWindow( pClientWindow->mpWindowImpl->mnLeftBorder,
+ pClientWindow->mpWindowImpl->mnTopBorder,
+ aSize.Width()-pClientWindow->mpWindowImpl->mnLeftBorder-pClientWindow->mpWindowImpl->mnRightBorder,
+ aSize.Height()-pClientWindow->mpWindowImpl->mnTopBorder-pClientWindow->mpWindowImpl->mnBottomBorder,
+ WINDOW_POSSIZE_X | WINDOW_POSSIZE_Y |
+ WINDOW_POSSIZE_WIDTH | WINDOW_POSSIZE_HEIGHT );
+ }
+
+ // UpdateView
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+ InvalidateBorder();
+
+ Window::Resize();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::StateChanged( StateChangedType nType )
+{
+ if ( (nType == STATE_CHANGE_TEXT) ||
+ (nType == STATE_CHANGE_IMAGE) ||
+ (nType == STATE_CHANGE_DATA) )
+ {
+ if ( IsReallyVisible() && mbFrameBorder )
+ {
+ if ( HasPaintEvent() )
+ InvalidateBorder();
+ else
+ mpBorderView->DrawWindow( BORDERWINDOW_DRAW_TITLE );
+ }
+ }
+
+ Window::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ if ( !mpWindowImpl->mbFrame || (GetStyle() & WB_OWNERDRAWDECORATION) )
+ UpdateView( TRUE, ImplGetWindow()->GetOutputSizePixel() );
+ }
+
+ Window::DataChanged( rDCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::InitView()
+{
+ if ( mbSmallOutBorder )
+ mpBorderView = new ImplSmallBorderWindowView( this );
+ else if ( mpWindowImpl->mbFrame )
+ {
+ if( mbFrameBorder )
+ mpBorderView = new ImplStdBorderWindowView( this );
+ else
+ mpBorderView = new ImplNoBorderWindowView( this );
+ }
+ else if ( !mbFrameBorder )
+ mpBorderView = new ImplSmallBorderWindowView( this );
+ else
+ mpBorderView = new ImplStdBorderWindowView( this );
+ Size aSize = GetOutputSizePixel();
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::UpdateView( BOOL bNewView, const Size& rNewOutSize )
+{
+ sal_Int32 nLeftBorder;
+ sal_Int32 nTopBorder;
+ sal_Int32 nRightBorder;
+ sal_Int32 nBottomBorder;
+ Size aOldSize = GetSizePixel();
+ Size aOutputSize = rNewOutSize;
+
+ if ( bNewView )
+ {
+ delete mpBorderView;
+ InitView();
+ }
+ else
+ {
+ Size aSize = aOutputSize;
+ mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder );
+ aSize.Width() += nLeftBorder+nRightBorder;
+ aSize.Height() += nTopBorder+nBottomBorder;
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+ }
+
+ Window* pClientWindow = ImplGetClientWindow();
+ if ( pClientWindow )
+ {
+ GetBorder( pClientWindow->mpWindowImpl->mnLeftBorder, pClientWindow->mpWindowImpl->mnTopBorder,
+ pClientWindow->mpWindowImpl->mnRightBorder, pClientWindow->mpWindowImpl->mnBottomBorder );
+ }
+ GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder );
+ if ( aOldSize.Width() || aOldSize.Height() )
+ {
+ aOutputSize.Width() += nLeftBorder+nRightBorder;
+ aOutputSize.Height() += nTopBorder+nBottomBorder;
+ if ( aOutputSize == GetSizePixel() )
+ InvalidateBorder();
+ else
+ SetSizePixel( aOutputSize );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::InvalidateBorder()
+{
+ if ( IsReallyVisible() )
+ {
+ // Nur wenn wir einen Border haben, muessen wir auch invalidieren
+ sal_Int32 nLeftBorder;
+ sal_Int32 nTopBorder;
+ sal_Int32 nRightBorder;
+ sal_Int32 nBottomBorder;
+ mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder );
+ if ( nLeftBorder || nTopBorder || nRightBorder || nBottomBorder )
+ {
+ Rectangle aWinRect( Point( 0, 0 ), GetOutputSizePixel() );
+ Region aRegion( aWinRect );
+ aWinRect.Left() += nLeftBorder;
+ aWinRect.Top() += nTopBorder;
+ aWinRect.Right() -= nRightBorder;
+ aWinRect.Bottom() -= nBottomBorder;
+ // kein Output-Bereich mehr, dann alles invalidieren
+ if ( (aWinRect.Right() < aWinRect.Left()) ||
+ (aWinRect.Bottom() < aWinRect.Top()) )
+ Invalidate( INVALIDATE_NOCHILDREN );
+ else
+ {
+ aRegion.Exclude( aWinRect );
+ Invalidate( aRegion, INVALIDATE_NOCHILDREN );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetDisplayActive( BOOL bActive )
+{
+ if ( mbDisplayActive != bActive )
+ {
+ mbDisplayActive = bActive;
+ if ( mbFrameBorder )
+ InvalidateBorder();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetTitleType( USHORT nTitleType, const Size& rSize )
+{
+ mnTitleType = nTitleType;
+ UpdateView( FALSE, rSize );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetBorderStyle( USHORT nStyle )
+{
+ if ( !mbFrameBorder && (mnBorderStyle != nStyle) )
+ {
+ mnBorderStyle = nStyle;
+ UpdateView( FALSE, ImplGetWindow()->GetOutputSizePixel() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetPin( BOOL bPin )
+{
+ mbPined = bPin;
+ InvalidateBorder();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetRollUp( BOOL bRollUp, const Size& rSize )
+{
+ mbRollUp = bRollUp;
+ mnRollHeight = rSize.Height();
+ UpdateView( FALSE, rSize );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetCloser()
+{
+ SetStyle( GetStyle() | WB_CLOSEABLE );
+ Size aSize = GetOutputSizePixel();
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+ InvalidateBorder();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetDockButton( BOOL bDockButton )
+{
+ mbDockBtn = bDockButton;
+ Size aSize = GetOutputSizePixel();
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+ InvalidateBorder();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetHideButton( BOOL bHideButton )
+{
+ mbHideBtn = bHideButton;
+ Size aSize = GetOutputSizePixel();
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+ InvalidateBorder();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetHelpButton( BOOL bHelpButton )
+{
+ mbHelpBtn = bHelpButton;
+ Size aSize = GetOutputSizePixel();
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+ InvalidateBorder();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetMenuButton( BOOL bMenuButton )
+{
+ mbMenuBtn = bMenuButton;
+ Size aSize = GetOutputSizePixel();
+ mpBorderView->Init( this, aSize.Width(), aSize.Height() );
+ InvalidateBorder();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::UpdateMenuHeight()
+{
+ Resize();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetMenuBarWindow( Window* pWindow )
+{
+ mpMenuBarWindow = pWindow;
+ UpdateMenuHeight();
+ if ( pWindow )
+ pWindow->Show();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::SetMenuBarMode( BOOL bHide )
+{
+ mbMenuHide = bHide;
+ UpdateMenuHeight();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBorderWindow::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
+{
+ mpBorderView->GetBorder( rLeftBorder, rTopBorder, rRightBorder, rBottomBorder );
+ if ( mpMenuBarWindow && !mbMenuHide )
+ rTopBorder += mpMenuBarWindow->GetSizePixel().Height();
+}
+
+// -----------------------------------------------------------------------
+
+long ImplBorderWindow::CalcTitleWidth() const
+{
+ return mpBorderView->CalcTitleWidth();
+}
+
+Rectangle ImplBorderWindow::GetMenuRect() const
+{
+ return mpBorderView->GetMenuRect();
+}
diff --git a/vcl/source/window/btndlg.cxx b/vcl/source/window/btndlg.cxx
new file mode 100644
index 000000000000..e835fe749ed1
--- /dev/null
+++ b/vcl/source/window/btndlg.cxx
@@ -0,0 +1,551 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/ref.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/button.hxx>
+#include <vcl/btndlg.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+
+
+
+// =======================================================================
+
+struct ImplBtnDlgItem
+{
+ USHORT mnId;
+ BOOL mbOwnButton;
+ BOOL mbDummyAlign;
+ long mnSepSize;
+ PushButton* mpPushButton;
+};
+
+DECLARE_LIST( ImplBtnDlgItemList, ImplBtnDlgItem* )
+
+// =======================================================================
+
+void ButtonDialog::ImplInitButtonDialogData()
+{
+ mpItemList = new ImplBtnDlgItemList( 8, 8 );
+ mnButtonSize = 0;
+ mnCurButtonId = 0;
+ mnFocusButtonId = BUTTONDIALOG_BUTTON_NOTFOUND;
+ mbFormat = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ButtonDialog::ButtonDialog( WindowType nType ) :
+ Dialog( nType )
+{
+ ImplInitButtonDialogData();
+}
+
+// -----------------------------------------------------------------------
+
+ButtonDialog::ButtonDialog( Window* pParent, WinBits nStyle ) :
+ Dialog( WINDOW_BUTTONDIALOG )
+{
+ ImplInitButtonDialogData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ButtonDialog::ButtonDialog( Window* pParent, const ResId& rResId ) :
+ Dialog( WINDOW_BUTTONDIALOG )
+{
+ ImplInitButtonDialogData();
+ rResId.SetRT( RSC_DIALOG ); // !!!!!!!!!! RSC_BUTTONDIALOG !!!!!!!!
+ ImplInit( pParent, ImplInitRes( rResId ) );
+ ImplLoadRes( rResId );
+}
+
+// -----------------------------------------------------------------------
+
+ButtonDialog::~ButtonDialog()
+{
+ ImplBtnDlgItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mpPushButton && pItem->mbOwnButton )
+ delete pItem->mpPushButton;
+ delete pItem;
+ pItem = mpItemList->Next();
+ }
+
+ delete mpItemList;
+}
+
+// -----------------------------------------------------------------------
+
+PushButton* ButtonDialog::ImplCreatePushButton( USHORT nBtnFlags )
+{
+ PushButton* pBtn;
+ WinBits nStyle = 0;
+
+ if ( nBtnFlags & BUTTONDIALOG_DEFBUTTON )
+ nStyle |= WB_DEFBUTTON;
+ if ( nBtnFlags & BUTTONDIALOG_CANCELBUTTON )
+ pBtn = new CancelButton( this, nStyle );
+ else if ( nBtnFlags & BUTTONDIALOG_OKBUTTON )
+ pBtn = new OKButton( this, nStyle );
+ else if ( nBtnFlags & BUTTONDIALOG_HELPBUTTON )
+ pBtn = new HelpButton( this, nStyle );
+ else
+ pBtn = new PushButton( this, nStyle );
+
+ if ( !(nBtnFlags & BUTTONDIALOG_HELPBUTTON) )
+ pBtn->SetClickHdl( LINK( this, ButtonDialog, ImplClickHdl ) );
+
+ return pBtn;
+}
+
+// -----------------------------------------------------------------------
+
+ImplBtnDlgItem* ButtonDialog::ImplGetItem( USHORT nId ) const
+{
+ ImplBtnDlgItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mnId == nId )
+ return pItem;
+
+ pItem = mpItemList->Next();
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+long ButtonDialog::ImplGetButtonSize()
+{
+ if ( !mbFormat )
+ return mnButtonSize;
+
+ // Calculate ButtonSize
+ long nLastSepSize = 0;
+ long nSepSize = 0;
+ long nButtonCount = 0;
+ maCtrlSize = Size( IMPL_MINSIZE_BUTTON_WIDTH, IMPL_MINSIZE_BUTTON_HEIGHT );
+ ImplBtnDlgItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ nSepSize += nLastSepSize;
+
+ long nTxtWidth = pItem->mpPushButton->GetCtrlTextWidth( pItem->mpPushButton->GetText() );
+ nTxtWidth += IMPL_EXTRA_BUTTON_WIDTH;
+ if ( nTxtWidth > maCtrlSize.Width() )
+ maCtrlSize.Width() = nTxtWidth;
+ long nTxtHeight = pItem->mpPushButton->GetTextHeight();
+ nTxtHeight += IMPL_EXTRA_BUTTON_HEIGHT;
+ if ( nTxtHeight > maCtrlSize.Height() )
+ maCtrlSize.Height() = nTxtHeight;
+
+ nSepSize += pItem->mnSepSize;
+
+ if ( GetStyle() & WB_HORZ )
+ nLastSepSize = IMPL_SEP_BUTTON_X;
+ else
+ nLastSepSize = IMPL_SEP_BUTTON_Y;
+
+ nButtonCount++;
+
+ pItem = mpItemList->Next();
+ }
+
+ if ( GetStyle() & WB_HORZ )
+ mnButtonSize = nSepSize + (nButtonCount*maCtrlSize.Width());
+ else
+ mnButtonSize = nSepSize + (nButtonCount*maCtrlSize.Height());
+
+ return mnButtonSize;
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::ImplPosControls()
+{
+ if ( !mbFormat )
+ return;
+
+ // Create PushButtons and determine Sizes
+ ImplGetButtonSize();
+
+ // determine dialog size
+ ImplBtnDlgItem* pItem;
+ Size aDlgSize = maPageSize;
+ long nX;
+ long nY;
+ if ( GetStyle() & WB_HORZ )
+ {
+ if ( mnButtonSize+(IMPL_DIALOG_OFFSET*2) > aDlgSize.Width() )
+ aDlgSize.Width() = mnButtonSize+(IMPL_DIALOG_OFFSET*2);
+ if ( GetStyle() & WB_LEFT )
+ nX = IMPL_DIALOG_OFFSET;
+ else if ( GetStyle() & WB_RIGHT )
+ nX = aDlgSize.Width()-mnButtonSize-IMPL_DIALOG_OFFSET;
+ else
+ nX = (aDlgSize.Width()-mnButtonSize)/2;
+
+ aDlgSize.Height() += IMPL_DIALOG_OFFSET+maCtrlSize.Height();
+ nY = aDlgSize.Height()-maCtrlSize.Height()-IMPL_DIALOG_OFFSET;
+ }
+ else
+ {
+ if ( mnButtonSize+(IMPL_DIALOG_OFFSET*2) > aDlgSize.Height() )
+ aDlgSize.Height() = mnButtonSize+(IMPL_DIALOG_OFFSET*2);
+ if ( GetStyle() & WB_BOTTOM )
+ nY = aDlgSize.Height()-mnButtonSize-IMPL_DIALOG_OFFSET;
+ else if ( GetStyle() & WB_VCENTER )
+ nY = (aDlgSize.Height()-mnButtonSize)/2;
+ else
+ nY = IMPL_DIALOG_OFFSET;
+
+ aDlgSize.Width() += IMPL_DIALOG_OFFSET+maCtrlSize.Width();
+ nX = aDlgSize.Width()-maCtrlSize.Width()-IMPL_DIALOG_OFFSET;
+ }
+
+ // Arrange PushButtons
+ pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( GetStyle() & WB_HORZ )
+ nX += pItem->mnSepSize;
+ else
+ nY += pItem->mnSepSize;
+ pItem->mpPushButton->SetPosSizePixel( Point( nX, nY ), maCtrlSize );
+ pItem->mpPushButton->Show();
+ if ( GetStyle() & WB_HORZ )
+ nX += maCtrlSize.Width()+IMPL_SEP_BUTTON_X;
+ else
+ nY += maCtrlSize.Height()+IMPL_SEP_BUTTON_Y;
+
+ pItem = mpItemList->Next();
+ }
+
+ SetOutputSizePixel( aDlgSize );
+
+ mbFormat = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ButtonDialog, ImplClickHdl, PushButton*, pBtn )
+{
+ ImplBtnDlgItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mpPushButton == pBtn )
+ {
+ mnCurButtonId = pItem->mnId;
+ Click();
+ break;
+ }
+
+ pItem = mpItemList->Next();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::Resize()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ ImplPosControls();
+
+ // Focus evt. auf den entsprechenden Button setzen
+ if ( mnFocusButtonId != BUTTONDIALOG_BUTTON_NOTFOUND )
+ {
+ ImplBtnDlgItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mnId == mnFocusButtonId )
+ {
+ if ( pItem->mpPushButton->IsVisible() )
+ pItem->mpPushButton->GrabFocus();
+ break;
+ }
+
+ pItem = mpItemList->Next();
+ }
+ }
+ }
+
+ Dialog::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::Click()
+{
+ if ( !maClickHdl )
+ {
+ if ( IsInExecute() )
+ EndDialog( GetCurButtonId() );
+ }
+ else
+ maClickHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::AddButton( const XubString& rText, USHORT nId,
+ USHORT nBtnFlags, long nSepPixel )
+{
+ // PageItem anlegen
+ ImplBtnDlgItem* pItem = new ImplBtnDlgItem;
+ pItem->mnId = nId;
+ pItem->mbOwnButton = TRUE;
+ pItem->mnSepSize = nSepPixel;
+ pItem->mpPushButton = ImplCreatePushButton( nBtnFlags );
+ if ( rText.Len() )
+ pItem->mpPushButton->SetText( rText );
+
+ // In die Liste eintragen
+ mpItemList->Insert( pItem, LIST_APPEND );
+
+ if ( nBtnFlags & BUTTONDIALOG_FOCUSBUTTON )
+ mnFocusButtonId = nId;
+
+ mbFormat = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::AddButton( StandardButtonType eType, USHORT nId,
+ USHORT nBtnFlags, long nSepPixel )
+{
+ // PageItem anlegen
+ ImplBtnDlgItem* pItem = new ImplBtnDlgItem;
+ pItem->mnId = nId;
+ pItem->mbOwnButton = TRUE;
+ pItem->mnSepSize = nSepPixel;
+
+ if ( eType == BUTTON_OK )
+ nBtnFlags |= BUTTONDIALOG_OKBUTTON;
+ else if ( eType == BUTTON_HELP )
+ nBtnFlags |= BUTTONDIALOG_HELPBUTTON;
+ else if ( (eType == BUTTON_CANCEL) || (eType == BUTTON_CLOSE) )
+ nBtnFlags |= BUTTONDIALOG_CANCELBUTTON;
+ pItem->mpPushButton = ImplCreatePushButton( nBtnFlags );
+
+ // Standard-Buttons have the right text already
+ if ( !((eType == BUTTON_OK) && (pItem->mpPushButton->GetType() == WINDOW_OKBUTTON)) ||
+ !((eType == BUTTON_CANCEL) && (pItem->mpPushButton->GetType() == WINDOW_CANCELBUTTON)) ||
+ !((eType == BUTTON_HELP) && (pItem->mpPushButton->GetType() == WINDOW_HELPBUTTON)) )
+ {
+ pItem->mpPushButton->SetText( Button::GetStandardText( eType ) );
+ pItem->mpPushButton->SetHelpText( Button::GetStandardHelpText( eType ) );
+ }
+
+ if ( nBtnFlags & BUTTONDIALOG_FOCUSBUTTON )
+ mnFocusButtonId = nId;
+
+ // In die Liste eintragen
+ mpItemList->Insert( pItem, LIST_APPEND );
+
+ mbFormat = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::AddButton( PushButton* pBtn, USHORT nId,
+ USHORT nBtnFlags, long nSepPixel )
+{
+ // PageItem anlegen
+ ImplBtnDlgItem* pItem = new ImplBtnDlgItem;
+ pItem->mnId = nId;
+ pItem->mbOwnButton = FALSE;
+ pItem->mnSepSize = nSepPixel;
+ pItem->mpPushButton = pBtn;
+
+ if ( nBtnFlags & BUTTONDIALOG_FOCUSBUTTON )
+ mnFocusButtonId = nId;
+
+ // In die View-Liste eintragen
+ mpItemList->Insert( pItem, LIST_APPEND );
+
+ mbFormat = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::RemoveButton( USHORT nId )
+{
+ ImplBtnDlgItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mnId == nId )
+ {
+ pItem->mpPushButton->Hide();
+ if ( pItem->mbOwnButton )
+ delete pItem->mpPushButton;
+ delete pItem;
+ mpItemList->Remove();
+ mbFormat = TRUE;
+ break;
+ }
+
+ pItem = mpItemList->Next();
+ }
+
+ DBG_ERRORFILE( "ButtonDialog::RemoveButton(): ButtonId invalid" );
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::Clear()
+{
+ ImplBtnDlgItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ pItem->mpPushButton->Hide();
+ if ( pItem->mbOwnButton )
+ delete pItem->mpPushButton;
+ delete pItem;
+ pItem = mpItemList->Next();
+ }
+
+ mpItemList->Clear();
+ mbFormat = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ButtonDialog::GetButtonCount() const
+{
+ return (USHORT)mpItemList->Count();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ButtonDialog::GetButtonId( USHORT nButton ) const
+{
+ if ( nButton < mpItemList->Count() )
+ return (USHORT)mpItemList->GetObject( nButton )->mnId;
+ else
+ return BUTTONDIALOG_BUTTON_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+PushButton* ButtonDialog::GetPushButton( USHORT nId ) const
+{
+ ImplBtnDlgItem* pItem = ImplGetItem( nId );
+
+ if ( pItem )
+ return pItem->mpPushButton;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::SetButtonText( USHORT nId, const XubString& rText )
+{
+ ImplBtnDlgItem* pItem = ImplGetItem( nId );
+
+ if ( pItem )
+ {
+ pItem->mpPushButton->SetText( rText );
+ mbFormat = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString ButtonDialog::GetButtonText( USHORT nId ) const
+{
+ ImplBtnDlgItem* pItem = ImplGetItem( nId );
+
+ if ( pItem )
+ return pItem->mpPushButton->GetText();
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::SetButtonHelpText( USHORT nId, const XubString& rText )
+{
+ ImplBtnDlgItem* pItem = ImplGetItem( nId );
+
+ if ( pItem )
+ pItem->mpPushButton->SetHelpText( rText );
+}
+
+// -----------------------------------------------------------------------
+
+XubString ButtonDialog::GetButtonHelpText( USHORT nId ) const
+{
+ ImplBtnDlgItem* pItem = ImplGetItem( nId );
+
+ if ( pItem )
+ return pItem->mpPushButton->GetHelpText();
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void ButtonDialog::SetButtonHelpId( USHORT nId, ULONG nHelpId )
+{
+ ImplBtnDlgItem* pItem = ImplGetItem( nId );
+
+ if ( pItem )
+ pItem->mpPushButton->SetHelpId( nHelpId );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG ButtonDialog::GetButtonHelpId( USHORT nId ) const
+{
+ ImplBtnDlgItem* pItem = ImplGetItem( nId );
+
+ if ( pItem )
+ return pItem->mpPushButton->GetHelpId();
+ else
+ return 0;
+}
diff --git a/vcl/source/window/cmdevt.cxx b/vcl/source/window/cmdevt.cxx
new file mode 100644
index 000000000000..03e01c96742b
--- /dev/null
+++ b/vcl/source/window/cmdevt.cxx
@@ -0,0 +1,101 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _STRING_H
+#include <string.h>
+#endif
+
+#ifndef _SV_CMDEVT_HXX
+#include <vcl/cmdevt.hxx>
+#endif
+
+// =======================================================================
+
+CommandExtTextInputData::CommandExtTextInputData()
+{
+ mpTextAttr = NULL;
+ mnCursorPos = 0;
+ mnDeltaStart = 0;
+ mnOldTextLen = 0;
+ mnCursorFlags = 0;
+ mbOnlyCursor = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+CommandExtTextInputData::CommandExtTextInputData( const XubString& rText,
+ const USHORT* pTextAttr,
+ xub_StrLen nCursorPos,
+ USHORT nCursorFlags,
+ xub_StrLen nDeltaStart,
+ xub_StrLen nOldTextLen,
+ BOOL bOnlyCursor ) :
+ maText( rText )
+{
+ if ( pTextAttr && maText.Len() )
+ {
+ mpTextAttr = new USHORT[maText.Len()];
+ memcpy( mpTextAttr, pTextAttr, maText.Len()*sizeof(USHORT) );
+ }
+ else
+ mpTextAttr = NULL;
+ mnCursorPos = nCursorPos;
+ mnDeltaStart = nDeltaStart;
+ mnOldTextLen = nOldTextLen;
+ mnCursorFlags = nCursorFlags;
+ mbOnlyCursor = bOnlyCursor;
+}
+
+// -----------------------------------------------------------------------
+
+CommandExtTextInputData::CommandExtTextInputData( const CommandExtTextInputData& rData ) :
+ maText( rData.maText )
+{
+ if ( rData.mpTextAttr && maText.Len() )
+ {
+ mpTextAttr = new USHORT[maText.Len()];
+ memcpy( mpTextAttr, rData.mpTextAttr, maText.Len()*sizeof(USHORT) );
+ }
+ else
+ mpTextAttr = NULL;
+ mnCursorPos = rData.mnCursorPos;
+ mnDeltaStart = rData.mnDeltaStart;
+ mnOldTextLen = rData.mnOldTextLen;
+ mnCursorFlags = rData.mnCursorFlags;
+ mbOnlyCursor = rData.mbOnlyCursor;
+}
+
+// -----------------------------------------------------------------------
+
+CommandExtTextInputData::~CommandExtTextInputData()
+{
+ if ( mpTextAttr )
+ delete [] mpTextAttr;
+}
diff --git a/vcl/source/window/cursor.cxx b/vcl/source/window/cursor.cxx
new file mode 100644
index 000000000000..5725189e10c3
--- /dev/null
+++ b/vcl/source/window/cursor.cxx
@@ -0,0 +1,462 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/svapp.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/window.hxx>
+#include <vcl/window.h>
+#include <tools/poly.hxx>
+#include <vcl/cursor.hxx>
+
+
+// =======================================================================
+
+struct ImplCursorData
+{
+ AutoTimer maTimer; // Timer
+ Point maPixPos; // Pixel-Position
+ Point maPixRotOff; // Pixel-Offset-Position
+ Size maPixSize; // Pixel-Size
+ long mnPixSlant; // Pixel-Slant
+ short mnOrientation; // Pixel-Orientation
+ unsigned char mnDirection; // indicates writing direction
+ USHORT mnStyle; // Cursor-Style
+ BOOL mbCurVisible; // Ist Cursor aktuell sichtbar
+ Window* mpWindow; // Zugeordnetes Windows
+};
+
+// =======================================================================
+
+static void ImplCursorInvert( ImplCursorData* pData )
+{
+ Window* pWindow = pData->mpWindow;
+ BOOL bMapMode = pWindow->IsMapModeEnabled();
+ pWindow->EnableMapMode( FALSE );
+ USHORT nInvertStyle;
+ if ( pData->mnStyle & CURSOR_SHADOW )
+ nInvertStyle = INVERT_50;
+ else
+ nInvertStyle = 0;
+
+ Rectangle aRect( pData->maPixPos, pData->maPixSize );
+ if ( pData->mnDirection || pData->mnOrientation || pData->mnPixSlant )
+ {
+ Polygon aPoly( aRect );
+ if( aPoly.GetSize() == 5 )
+ {
+ aPoly[1].X() += 1; // include the right border
+ aPoly[2].X() += 1;
+ if ( pData->mnPixSlant )
+ {
+ Point aPoint = aPoly.GetPoint( 0 );
+ aPoint.X() += pData->mnPixSlant;
+ aPoly.SetPoint( aPoint, 0 );
+ aPoly.SetPoint( aPoint, 4 );
+ aPoint = aPoly.GetPoint( 1 );
+ aPoint.X() += pData->mnPixSlant;
+ aPoly.SetPoint( aPoint, 1 );
+ }
+
+ // apply direction flag after slant to use the correct shape
+ if ( pData->mnDirection )
+ {
+ Point pAry[7];
+ int delta = 3*aRect.getWidth()+1;
+ if( pData->mnDirection == CURSOR_DIRECTION_LTR )
+ {
+ // left-to-right
+ pAry[0] = aPoly.GetPoint( 0 );
+ pAry[1] = aPoly.GetPoint( 1 );
+ pAry[2] = pAry[1];
+ pAry[2].X() += delta;
+ pAry[3] = pAry[1];
+ pAry[3].Y() += delta;
+ pAry[4] = aPoly.GetPoint( 2 );
+ pAry[5] = aPoly.GetPoint( 3 );
+ pAry[6] = aPoly.GetPoint( 4 );
+ }
+ else if( pData->mnDirection == CURSOR_DIRECTION_RTL )
+ {
+ // right-to-left
+ pAry[0] = aPoly.GetPoint( 0 );
+ pAry[1] = aPoly.GetPoint( 1 );
+ pAry[2] = aPoly.GetPoint( 2 );
+ pAry[3] = aPoly.GetPoint( 3 );
+ pAry[4] = pAry[0];
+ pAry[4].Y() += delta;
+ pAry[5] = pAry[0];
+ pAry[5].X() -= delta;
+ pAry[6] = aPoly.GetPoint( 4 );
+ }
+ aPoly = Polygon( 7, pAry);
+ }
+
+ if ( pData->mnOrientation )
+ aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation );
+ pWindow->Invert( aPoly, nInvertStyle );
+ }
+ }
+ else
+ pWindow->Invert( aRect, nInvertStyle );
+ pWindow->EnableMapMode( bMapMode );
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::ImplDraw()
+{
+ if ( mpData && mpData->mpWindow && !mpData->mbCurVisible )
+ {
+ Window* pWindow = mpData->mpWindow;
+ mpData->maPixPos = pWindow->LogicToPixel( maPos );
+ mpData->maPixSize = pWindow->LogicToPixel( maSize );
+ mpData->mnPixSlant = pWindow->LogicToPixel( Size( mnSlant, 0 ) ).Width();
+ mpData->mnOrientation = mnOrientation;
+ mpData->mnDirection = mnDirection;
+ long nOffsetY = pWindow->LogicToPixel( Size( 0, mnOffsetY ) ).Height();
+
+ // Position um den Offset korrigieren
+ mpData->maPixPos.Y() -= nOffsetY;
+ mpData->maPixRotOff = mpData->maPixPos;
+ mpData->maPixRotOff.Y() += nOffsetY;
+
+ // Wenn groesse 0 ist, nehmen wir die breite, die in den
+ // Settings eingestellt ist
+ if ( !mpData->maPixSize.Width() )
+ mpData->maPixSize.Width() = pWindow->GetSettings().GetStyleSettings().GetCursorSize();
+
+ // Ausgabeflaeche berechnen und ausgeben
+ ImplCursorInvert( mpData );
+ mpData->mbCurVisible = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::ImplRestore()
+{
+ if ( mpData && mpData->mbCurVisible )
+ {
+ ImplCursorInvert( mpData );
+ mpData->mbCurVisible = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::ImplShow( BOOL bDrawDirect )
+{
+ if ( mbVisible )
+ {
+ Window* pWindow;
+ if ( mpWindow )
+ pWindow = mpWindow;
+ else
+ {
+ // Gibt es ein aktives Fenster und ist der Cursor in dieses Fenster
+ // selektiert, dann zeige den Cursor an
+ pWindow = Application::GetFocusWindow();
+ if ( !pWindow || (pWindow->mpWindowImpl->mpCursor != this) || pWindow->mpWindowImpl->mbInPaint
+ || !pWindow->mpWindowImpl->mpFrameData->mbHasFocus )
+ pWindow = NULL;
+ }
+
+ if ( pWindow )
+ {
+ if ( !mpData )
+ {
+ mpData = new ImplCursorData;
+ mpData->mbCurVisible = FALSE;
+ mpData->maTimer.SetTimeoutHdl( LINK( this, Cursor, ImplTimerHdl ) );
+ }
+
+ mpData->mpWindow = pWindow;
+ mpData->mnStyle = mnStyle;
+ if ( bDrawDirect )
+ ImplDraw();
+
+ if ( !mpWindow )
+ {
+ mpData->maTimer.SetTimeout( pWindow->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
+ if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
+ mpData->maTimer.Start();
+ else if ( !mpData->mbCurVisible )
+ ImplDraw();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::ImplHide()
+{
+ if ( mpData && mpData->mpWindow )
+ {
+ if ( mpData->mbCurVisible )
+ ImplRestore();
+
+ mpData->maTimer.Stop();
+ mpData->mpWindow = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::ImplNew()
+{
+ if ( mbVisible && mpData && mpData->mpWindow )
+ {
+ if ( mpData->mbCurVisible )
+ ImplRestore();
+
+ ImplDraw();
+ if ( !mpWindow )
+ {
+ if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
+ mpData->maTimer.Start();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Cursor, ImplTimerHdl, AutoTimer*, EMPTYARG )
+{
+ if ( mpData->mbCurVisible )
+ ImplRestore();
+ else
+ ImplDraw();
+ return 0;
+}
+
+// =======================================================================
+
+Cursor::Cursor()
+{
+ mpData = NULL;
+ mpWindow = NULL;
+ mnSlant = 0;
+ mnOffsetY = 0;
+ mnOrientation = 0;
+ mnDirection = 0;
+ mnStyle = 0;
+ mbVisible = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Cursor::Cursor( const Cursor& rCursor ) :
+ maSize( rCursor.maSize ),
+ maPos( rCursor.maPos )
+{
+ mpData = NULL;
+ mpWindow = NULL;
+ mnSlant = rCursor.mnSlant;
+ mnOrientation = rCursor.mnOrientation;
+ mnDirection = rCursor.mnDirection;
+ mnStyle = 0;
+ mbVisible = rCursor.mbVisible;
+}
+
+// -----------------------------------------------------------------------
+
+Cursor::~Cursor()
+{
+ if ( mpData )
+ {
+ if ( mpData->mbCurVisible )
+ ImplRestore();
+
+ delete mpData;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetStyle( USHORT nStyle )
+{
+ if ( mnStyle != nStyle )
+ {
+ mnStyle = nStyle;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::Show()
+{
+ if ( !mbVisible )
+ {
+ mbVisible = TRUE;
+ ImplShow();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::Hide()
+{
+ if ( mbVisible )
+ {
+ mbVisible = FALSE;
+ ImplHide();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetWindow( Window* pWindow )
+{
+ if ( mpWindow != pWindow )
+ {
+ mpWindow = pWindow;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetPos( const Point& rPoint )
+{
+ if ( maPos != rPoint )
+ {
+ maPos = rPoint;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetOffsetY( long nNewOffsetY )
+{
+ if ( mnOffsetY != nNewOffsetY )
+ {
+ mnOffsetY = nNewOffsetY;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetSize( const Size& rSize )
+{
+ if ( maSize != rSize )
+ {
+ maSize = rSize;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetWidth( long nNewWidth )
+{
+ if ( maSize.Width() != nNewWidth )
+ {
+ maSize.Width() = nNewWidth;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetHeight( long nNewHeight )
+{
+ if ( maSize.Height() != nNewHeight )
+ {
+ maSize.Height() = nNewHeight;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetSlant( long nNewSlant )
+{
+ if ( mnSlant != nNewSlant )
+ {
+ mnSlant = nNewSlant;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetOrientation( short nNewOrientation )
+{
+ if ( mnOrientation != nNewOrientation )
+ {
+ mnOrientation = nNewOrientation;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Cursor::SetDirection( unsigned char nNewDirection )
+{
+ if ( mnDirection != nNewDirection )
+ {
+ mnDirection = nNewDirection;
+ ImplNew();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Cursor& Cursor::operator=( const Cursor& rCursor )
+{
+ maPos = rCursor.maPos;
+ maSize = rCursor.maSize;
+ mnSlant = rCursor.mnSlant;
+ mnOrientation = rCursor.mnOrientation;
+ mnDirection = rCursor.mnDirection;
+ mbVisible = rCursor.mbVisible;
+ ImplNew();
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Cursor::operator==( const Cursor& rCursor ) const
+{
+ if ( (maPos == rCursor.maPos) &&
+ (maSize == rCursor.maSize) &&
+ (mnSlant == rCursor.mnSlant) &&
+ (mnOrientation == rCursor.mnOrientation) &&
+ (mnDirection == rCursor.mnDirection) &&
+ (mbVisible == rCursor.mbVisible) )
+ return TRUE;
+ else
+ return FALSE;
+}
diff --git a/vcl/source/window/decoview.cxx b/vcl/source/window/decoview.cxx
new file mode 100644
index 000000000000..e5c3dc525cec
--- /dev/null
+++ b/vcl/source/window/decoview.cxx
@@ -0,0 +1,1388 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/settings.hxx>
+#include <tools/poly.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/window.hxx>
+#include <vcl/ctrl.hxx>
+
+// =======================================================================
+
+#define BUTTON_DRAW_FLATTEST (BUTTON_DRAW_FLAT | \
+ BUTTON_DRAW_PRESSED | \
+ BUTTON_DRAW_CHECKED | \
+ BUTTON_DRAW_HIGHLIGHT)
+
+// =======================================================================
+
+void ImplDrawOS2Symbol( OutputDevice* pDev, const Rectangle& rRect,
+ USHORT nStyle, BOOL bClose )
+{
+ DecorationView aView( pDev );
+ const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
+ Rectangle aRect = rRect;
+ Color aColor1;
+ Color aColor2;
+
+ pDev->SetFillColor();
+
+ if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) )
+ {
+ aColor1 = rStyleSettings.GetShadowColor();
+ aColor2 = rStyleSettings.GetLightColor();
+ }
+ else
+ {
+ aColor1 = rStyleSettings.GetLightColor();
+ aColor2 = rStyleSettings.GetShadowColor();
+ }
+ aView.DrawFrame( aRect, aColor1, aColor2 );
+
+ aRect.Left() += 2;
+ aRect.Top() += 2;
+ aRect.Right() -= 2;
+ aRect.Bottom() -= 2;
+
+ if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) )
+ pDev->SetLineColor( rStyleSettings.GetLightColor() );
+ else
+ pDev->SetLineColor( rStyleSettings.GetShadowColor() );
+ if ( bClose )
+ {
+ pDev->DrawLine( aRect.TopLeft(), Point( aRect.Left(), aRect.Bottom()-2 ) );
+ pDev->DrawLine( aRect.TopLeft(), Point( aRect.Right()-2, aRect.Top() ) );
+ pDev->DrawLine( Point( aRect.Left()+2, aRect.Bottom()-1 ),
+ Point( aRect.Right()-1, aRect.Top()+2 ) );
+ }
+ else
+ {
+ pDev->DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
+ pDev->DrawLine( aRect.TopLeft(), Point( aRect.Right()-1, aRect.Top() ) );
+ }
+
+ if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) )
+ pDev->SetLineColor( rStyleSettings.GetShadowColor() );
+ else
+ pDev->SetLineColor( rStyleSettings.GetLightColor() );
+ if ( bClose )
+ {
+ pDev->DrawLine( Point( aRect.Right(), aRect.Top()+2 ), aRect.BottomRight() );
+ pDev->DrawLine( Point( aRect.Left()+2, aRect.Bottom() ), aRect.BottomRight() );
+ pDev->DrawLine( Point( aRect.Right()-2, aRect.Top()+1 ),
+ Point( aRect.Left()+1, aRect.Bottom()-2 ) );
+ }
+ else
+ {
+ pDev->DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ pDev->DrawLine( Point( aRect.Left()+1, aRect.Bottom() ), aRect.BottomRight() );
+ }
+}
+
+// =======================================================================
+
+static void ImplDrawSymbol( OutputDevice* pDev, const Rectangle& rRect,
+ SymbolType eType )
+{
+ // Groessen vorberechnen
+ long nMin = Min( rRect.GetWidth(), rRect.GetHeight() );
+ long nSize = nMin;
+
+ if ( nMin & 0x01 )
+ nMin--;
+ Point aCenter = rRect.Center();
+ long nCenterX = aCenter.X();
+ long nCenterY = aCenter.Y();
+ long n2 = nMin / 2;
+ long n4 = nMin / 4;
+ long nLeft;
+ long nTop;
+ long nRight;
+ long nBottom;
+ long nTemp;
+ long i;
+
+ switch ( eType )
+ {
+ case SYMBOL_ARROW_UP:
+ {
+ if ( !(nMin & 0x01) )
+ {
+ n2--;
+ n4--;
+ }
+ nTop = nCenterY-n2;
+ nBottom = nCenterY;
+ pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nTop++;
+ nTemp = nCenterX-i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ nTemp = nCenterX+i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ i++;
+ }
+ pDev->DrawRect( Rectangle( nCenterX-n4, nBottom,
+ nCenterX+n4, nBottom+n2 ) );
+ }
+ break;
+
+ case SYMBOL_ARROW_DOWN:
+ {
+ if ( !(nMin & 0x01) )
+ {
+ n2--;
+ n4--;
+ }
+ nTop = nCenterY;
+ nBottom = nCenterY+n2;
+ pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nBottom--;
+ nTemp = nCenterX-i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ nTemp = nCenterX+i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ i++;
+ }
+ pDev->DrawRect( Rectangle( nCenterX-n4, nTop-n2,
+ nCenterX+n4, nTop ) );
+ }
+ break;
+
+ case SYMBOL_ARROW_LEFT:
+ {
+ if ( !(nMin & 0x01) )
+ {
+ n2--;
+ n4--;
+ }
+ nLeft = nCenterX-n2;
+ nRight = nCenterX;
+ pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nLeft++;
+ nTemp = nCenterY-i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ nTemp = nCenterY+i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ i++;
+ }
+ pDev->DrawRect( Rectangle( nRight, nCenterY-n4,
+ nRight+n2, nCenterY+n4 ) );
+ }
+ break;
+
+ case SYMBOL_ARROW_RIGHT:
+ {
+ if ( !(nMin & 0x01) )
+ {
+ n2--;
+ n4--;
+ }
+ nLeft = nCenterX;
+ nRight = nCenterX+n2;
+ pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nRight--;
+ nTemp = nCenterY-i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ nTemp = nCenterY+i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ i++;
+ }
+ pDev->DrawRect( Rectangle( nLeft-n2, nCenterY-n4,
+ nLeft, nCenterY+n4 ) );
+ }
+ break;
+
+
+ case SYMBOL_SPIN_UP:
+ {
+ if ( !(nMin & 0x01) )
+ n2--;
+ nTop = nCenterY-n4;
+ nBottom = nTop+n2;
+ pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nTop++;
+ nTemp = nCenterX-i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ nTemp = nCenterX+i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ i++;
+ }
+ }
+ break;
+
+ case SYMBOL_SPIN_DOWN:
+ {
+ if ( !(nMin & 0x01) )
+ n2--;
+ nTop = nCenterY-n4;
+ nBottom = nTop+n2;
+ pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nBottom--;
+ nTemp = nCenterX-i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ nTemp = nCenterX+i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ i++;
+ }
+ }
+ break;
+
+ case SYMBOL_SPIN_LEFT:
+ case SYMBOL_FIRST:
+ case SYMBOL_PREV:
+ case SYMBOL_REVERSEPLAY:
+ {
+ if ( !(nMin & 0x01) )
+ n2--;
+ nLeft = nCenterX-n4;
+ if ( eType == SYMBOL_FIRST )
+ nLeft++;
+ nRight = nLeft+n2;
+ pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nLeft++;
+ nTemp = nCenterY-i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ nTemp = nCenterY+i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ i++;
+ }
+ if ( eType == SYMBOL_FIRST )
+ {
+ pDev->DrawRect( Rectangle( nCenterX-n4-1, nCenterY-n2,
+ nCenterX-n4-1, nCenterY+n2 ) );
+ }
+ }
+ break;
+
+ case SYMBOL_SPIN_RIGHT:
+ case SYMBOL_LAST:
+ case SYMBOL_NEXT:
+ case SYMBOL_PLAY:
+ {
+ if ( !(nMin & 0x01) )
+ n2--;
+ nLeft = nCenterX-n4;
+ if ( eType == SYMBOL_LAST )
+ nLeft--;
+ nRight = nLeft+n2;
+ pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nRight--;
+ nTemp = nCenterY-i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ nTemp = nCenterY+i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ i++;
+ }
+ if ( eType == SYMBOL_LAST )
+ {
+ pDev->DrawRect( Rectangle( nCenterX+n4+1, nCenterY-n2,
+ nCenterX+n4+1, nCenterY+n2 ) );
+ }
+ }
+ break;
+
+ case SYMBOL_PAGEUP:
+ case SYMBOL_PAGEDOWN:
+ {
+ if ( !( nSize & 0x01 ))
+ {
+ // An even rectangle size means we have to use a smaller size for
+ // our arrows as we want to use one pixel for the spearhead! Otherwise
+ // it will be clipped!
+ nCenterX++;
+ n2 = ( nMin-1 ) / 2;
+ n4 = ( nMin-1 ) / 4;
+ }
+
+ nTop = nCenterY-n2;
+ nBottom = nCenterY-1;
+ pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) );
+ pDev->DrawRect( Rectangle( nCenterX, nTop+n2+1, nCenterX, nBottom+n2+1 ) );
+ i = 1;
+ while ( i < n2 )
+ {
+ ( eType == SYMBOL_PAGEUP ) ? nTop++ : nBottom--;
+ nTemp = nCenterX-i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ pDev->DrawRect( Rectangle( nTemp, nTop+n2+1, nTemp, nBottom+n2+1 ) );
+ nTemp = nCenterX+i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ pDev->DrawRect( Rectangle( nTemp, nTop+n2+1, nTemp, nBottom+n2+1 ) );
+ i++;
+ }
+ }
+ break;
+
+ case SYMBOL_RADIOCHECKMARK:
+ case SYMBOL_RECORD:
+ {
+ const long nExt = ( n2 << 1 ) + 1;
+ Bitmap aBmp( Size( nExt, nExt ), 1 );
+ BitmapWriteAccess* pWAcc = aBmp.AcquireWriteAccess();
+
+ if( pWAcc )
+ {
+ const Color aWhite( COL_WHITE );
+ const Color aBlack( COL_BLACK );
+
+ pWAcc->Erase( aWhite );
+ pWAcc->SetLineColor( aBlack );
+ pWAcc->SetFillColor( aBlack );
+ pWAcc->DrawPolygon( Polygon( Point( n2, n2 ), n2, n2 ) );
+ aBmp.ReleaseAccess( pWAcc );
+ pDev->DrawMask( Point( nCenterX - n2, nCenterY - n2 ), aBmp, pDev->GetFillColor() );
+ }
+ else
+ pDev->DrawPolygon( Polygon( Point( nCenterX, nCenterY ), n2, n2 ) );
+ }
+ break;
+
+ case SYMBOL_STOP:
+ {
+ nLeft = nCenterX-n2;
+ nRight = nCenterX+n2;
+ nTop = nCenterY-n2;
+ nBottom = nCenterY+n2;
+ pDev->DrawRect( Rectangle( nLeft, nTop, nRight, nBottom ) );
+ }
+ break;
+
+ case SYMBOL_PAUSE:
+ {
+ nLeft = nCenterX-n2;
+ nRight = nCenterX+n2-1;
+ nTop = nCenterY-n2;
+ nBottom = nCenterY+n2;
+ pDev->DrawRect( Rectangle( nLeft, nTop, nCenterX-2, nBottom ) );
+ pDev->DrawRect( Rectangle( nCenterX+1, nTop, nRight, nBottom ) );
+ }
+ break;
+
+ case SYMBOL_WINDSTART:
+ case SYMBOL_WINDBACKWARD:
+ {
+ nLeft = nCenterX-n2+1;
+ nRight = nCenterX;
+ pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) );
+ pDev->DrawRect( Rectangle( nLeft+n2, nCenterY, nRight+n2, nCenterY ) );
+ i = 1;
+ while ( i < n2 )
+ {
+ nLeft++;
+ nTemp = nCenterY-i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) );
+ nTemp = nCenterY+i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) );
+ i++;
+ }
+ if ( eType == SYMBOL_WINDSTART )
+ {
+ pDev->DrawRect( Rectangle( nCenterX-n2, nCenterY-n2,
+ nCenterX-n2, nCenterY+n2 ) );
+ }
+ }
+ break;
+
+ case SYMBOL_WINDEND:
+ case SYMBOL_WINDFORWARD:
+ {
+ nLeft = nCenterX-n2;
+ nRight = nCenterX-1;
+ pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) );
+ pDev->DrawRect( Rectangle( nLeft+n2, nCenterY, nRight+n2, nCenterY ) );
+ i = 1;
+ while ( i < n2 )
+ {
+ nRight--;
+ nTemp = nCenterY-i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) );
+ nTemp = nCenterY+i;
+ pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) );
+ pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) );
+ i++;
+ }
+ if ( eType == SYMBOL_WINDEND )
+ {
+ pDev->DrawRect( Rectangle( nCenterX+n2, nCenterY-n2,
+ nCenterX+n2, nCenterY+n2 ) );
+ }
+ }
+ break;
+
+ case SYMBOL_CLOSE:
+ {
+ Size aRectSize( 2, 1 );
+ if ( nMin < 8 )
+ aRectSize.Width() = 1;
+ else if ( nMin > 20 )
+ aRectSize.Width() = nMin/10;
+ nLeft = nCenterX-n2+1;
+ nTop = nCenterY-n2+1;
+ nBottom = nCenterY-n2+nMin-aRectSize.Width()+1;
+ i = 0;
+ while ( i < nMin-aRectSize.Width()+1 )
+ {
+ pDev->DrawRect( Rectangle( Point( nLeft+i, nTop+i ), aRectSize ) );
+ pDev->DrawRect( Rectangle( Point( nLeft+i, nBottom-i ), aRectSize ) );
+ i++;
+ }
+ }
+ break;
+
+ case SYMBOL_ROLLUP:
+ case SYMBOL_ROLLDOWN:
+ {
+ Rectangle aRect( nCenterX-n2, nCenterY-n2,
+ nCenterX+n2, nCenterY-n2+1 );
+ pDev->DrawRect( aRect );
+ if ( eType == SYMBOL_ROLLDOWN )
+ {
+ Rectangle aTempRect = aRect;
+ aTempRect.Bottom() = nCenterY+n2;
+ aTempRect.Right() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Left() = aRect.Right();
+ aTempRect.Right() = aRect.Right();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Top() = aTempRect.Bottom();
+ aTempRect.Left() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ }
+ }
+ break;
+ case SYMBOL_CHECKMARK:
+ {
+ // #106953# never mirror checkmarks
+ BOOL bRTL = pDev->ImplHasMirroredGraphics() && pDev->IsRTLEnabled();
+ Point aPos1( bRTL ? rRect.Right() : rRect.Left(),
+ rRect.Bottom() - rRect.GetHeight() / 3 );
+ Point aPos2( bRTL ? rRect.Right() - rRect.GetWidth()/3 : rRect.Left() + rRect.GetWidth()/3,
+ rRect.Bottom() );
+ Point aPos3( bRTL ? rRect.TopLeft() : rRect.TopRight() );
+ Size aRectSize( 1, 2 );
+ long nStepsY = aPos2.Y()-aPos1.Y();
+ long nX = aPos1.X();
+ long nY = aPos1.Y();
+ long n;
+ for ( n = 0; n <= nStepsY; n++ )
+ {
+ if( bRTL )
+ nX--;
+ pDev->DrawRect( Rectangle( Point( nX, nY++ ), aRectSize ) );
+ if( !bRTL )
+ nX++;
+ }
+ nStepsY = aPos2.Y()-aPos3.Y();
+ nX = aPos2.X();
+ nY = aPos2.Y();
+ for ( n = 0; n <= nStepsY; n++ )
+ {
+ if( bRTL )
+ if ( --nX < rRect.Left() )
+ break;
+ pDev->DrawRect( Rectangle( Point( nX, nY-- ), aRectSize ) );
+ if( !bRTL )
+ if ( ++nX > rRect.Right() )
+ break;
+ }
+ }
+ break;
+
+ case SYMBOL_SPIN_UPDOWN:
+ {
+ nTop = nCenterY-n2-1;
+ nBottom = nTop+n2;
+ pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nTop++;
+ nTemp = nCenterX-i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ nTemp = nCenterX+i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ i++;
+ }
+ nTop = nCenterY+1;
+ nBottom = nTop+n2;
+ pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) );
+ i = 1;
+ while ( i <= n2 )
+ {
+ nBottom--;
+ nTemp = nCenterX-i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ nTemp = nCenterX+i;
+ pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) );
+ i++;
+ }
+ }
+ break;
+
+
+ case SYMBOL_FLOAT:
+ {
+ Rectangle aRect( nCenterX-n2, nCenterY-n2+3,
+ nCenterX+n2-2, nCenterY-n2+4 );
+ pDev->DrawRect( aRect );
+ Rectangle aTempRect = aRect;
+ aTempRect.Bottom() = nCenterY+n2;
+ aTempRect.Right() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Left() = aRect.Right();
+ aTempRect.Right() = aRect.Right();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Top() = aTempRect.Bottom();
+ aTempRect.Left() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ aRect = Rectangle( nCenterX-n2+2, nCenterY-n2,
+ nCenterX+n2, nCenterY-n2+1 );
+ pDev->DrawRect( aRect );
+ aTempRect = aRect;
+ aTempRect.Bottom() = nCenterY+n2-3;
+ aTempRect.Right() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Left() = aRect.Right();
+ aTempRect.Right() = aRect.Right();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Top() = aTempRect.Bottom();
+ aTempRect.Left() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ }
+ break;
+ case SYMBOL_DOCK:
+ {
+ Rectangle aRect( nCenterX-n2, nCenterY-n2,
+ nCenterX+n2, nCenterY-n2 );
+ pDev->DrawRect( aRect );
+ Rectangle aTempRect = aRect;
+ aTempRect.Bottom() = nCenterY+n2;
+ aTempRect.Right() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Left() = aRect.Right();
+ aTempRect.Right() = aRect.Right();
+ pDev->DrawRect( aTempRect );
+ aTempRect.Top() = aTempRect.Bottom();
+ aTempRect.Left() = aRect.Left();
+ pDev->DrawRect( aTempRect );
+ }
+ break;
+ case SYMBOL_HIDE:
+ {
+ long nExtra = nMin / 8;
+ Rectangle aRect( nCenterX-n2+nExtra, nCenterY+n2-1,
+ nCenterX+n2-nExtra, nCenterY+n2 );
+ pDev->DrawRect( aRect );
+ }
+ break;
+
+ case SYMBOL_OS2CLOSE:
+ {
+ Rectangle aRect( nCenterX-n2, nCenterY-n2,
+ nCenterX+n2, nCenterY+n2 );
+ ImplDrawOS2Symbol( pDev, aRect, 0, TRUE );
+ }
+ break;
+
+ case SYMBOL_OS2FLOAT:
+ {
+ Rectangle aRect( nCenterX-n2+4, nCenterY-n2+4,
+ nCenterX+n2-4, nCenterY+n2-3 );
+ ImplDrawOS2Symbol( pDev, aRect, 0, FALSE );
+ DecorationView aDecoView( pDev );
+ Rectangle aRect2( nCenterX-n2, nCenterY-n2,
+ nCenterX-n2+2, nCenterY+n2 );
+ aDecoView.DrawFrame( aRect2,
+ pDev->GetSettings().GetStyleSettings().GetLightColor(),
+ pDev->GetSettings().GetStyleSettings().GetShadowColor() );
+ Rectangle aRect3( nCenterX+n2-2, nCenterY-n2,
+ nCenterX+n2, nCenterY+n2 );
+ aDecoView.DrawFrame( aRect3,
+ pDev->GetSettings().GetStyleSettings().GetLightColor(),
+ pDev->GetSettings().GetStyleSettings().GetShadowColor() );
+ }
+ break;
+
+ case SYMBOL_OS2HIDE:
+ {
+ Rectangle aRect( nCenterX-n2+3, nCenterY-n2+3,
+ nCenterX+n2-3, nCenterY+n2-3 );
+ ImplDrawOS2Symbol( pDev, aRect, 0, FALSE );
+ }
+ break;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DecorationView::DrawSymbol( const Rectangle& rRect, SymbolType eType,
+ const Color& rColor, USHORT nStyle )
+{
+ const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings();
+ Rectangle aRect = mpOutDev->LogicToPixel( rRect );
+ Color aOldLineColor = mpOutDev->GetLineColor();
+ Color aOldFillColor = mpOutDev->GetFillColor();
+ BOOL bOldMapMode = mpOutDev->IsMapModeEnabled();
+ mpOutDev->SetLineColor();
+ mpOutDev->SetFillColor( rColor );
+ mpOutDev->EnableMapMode( FALSE );
+
+ if ( (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ||
+ (mpOutDev->GetOutDevType() == OUTDEV_PRINTER) )
+ nStyle |= BUTTON_DRAW_MONO;
+
+ if ( nStyle & SYMBOL_DRAW_MONO )
+ {
+ if ( nStyle & SYMBOL_DRAW_DISABLE )
+ mpOutDev->SetFillColor( Color( COL_GRAY ) );
+ else
+ mpOutDev->SetFillColor( Color( COL_BLACK ) );
+ }
+ else
+ {
+ if ( nStyle & SYMBOL_DRAW_DISABLE )
+ {
+ // Als Embosed ausgeben
+ mpOutDev->SetFillColor( rStyleSettings.GetLightColor() );
+ Rectangle aTempRect = aRect;
+ aTempRect.Move( 1, 1 );
+ ImplDrawSymbol( mpOutDev, aTempRect, eType );
+ mpOutDev->SetFillColor( rStyleSettings.GetShadowColor() );
+ }
+ else
+ mpOutDev->SetFillColor( rColor );
+ }
+
+ ImplDrawSymbol( mpOutDev, aRect, eType );
+
+ mpOutDev->SetLineColor( aOldLineColor );
+ mpOutDev->SetFillColor( aOldFillColor );
+ mpOutDev->EnableMapMode( bOldMapMode );
+}
+
+// =======================================================================
+
+void DecorationView::DrawFrame( const Rectangle& rRect,
+ const Color& rLeftTopColor,
+ const Color& rRightBottomColor )
+{
+ Rectangle aRect = mpOutDev->LogicToPixel( rRect );
+ Color aOldLineColor = mpOutDev->GetLineColor();
+ Color aOldFillColor = mpOutDev->GetFillColor();
+ BOOL bOldMapMode = mpOutDev->IsMapModeEnabled();
+ mpOutDev->EnableMapMode( FALSE );
+ mpOutDev->SetLineColor();
+ mpOutDev->ImplDraw2ColorFrame( aRect, rLeftTopColor, rRightBottomColor );
+ mpOutDev->SetLineColor( aOldLineColor );
+ mpOutDev->SetFillColor( aOldFillColor );
+ mpOutDev->EnableMapMode( bOldMapMode );
+}
+
+// =======================================================================
+
+void DecorationView::DrawHighlightFrame( const Rectangle& rRect,
+ USHORT nStyle )
+{
+ const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings();
+ Color aLightColor = rStyleSettings.GetLightColor();
+ Color aShadowColor = rStyleSettings.GetShadowColor();
+
+ if ( (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ||
+ (mpOutDev->GetOutDevType() == OUTDEV_PRINTER) )
+ {
+ aLightColor = Color( COL_BLACK );
+ aShadowColor = Color( COL_BLACK );
+ }
+ else if ( nStyle & FRAME_HIGHLIGHT_TESTBACKGROUND )
+ {
+ Wallpaper aBackground = mpOutDev->GetBackground();
+ if ( aBackground.IsBitmap() || aBackground.IsGradient() )
+ {
+ aLightColor = rStyleSettings.GetFaceColor();
+ aShadowColor = Color( COL_BLACK );
+ }
+ else
+ {
+ Color aBackColor = aBackground.GetColor();
+ if ( (aLightColor.GetColorError( aBackColor ) < 32) ||
+ (aShadowColor.GetColorError( aBackColor ) < 32) )
+ {
+ aLightColor = Color( COL_WHITE );
+ aShadowColor = Color( COL_BLACK );
+
+ if ( aLightColor.GetColorError( aBackColor ) < 32 )
+ aLightColor.DecreaseLuminance( 64 );
+ if ( aShadowColor.GetColorError( aBackColor ) < 32 )
+ aShadowColor.IncreaseLuminance( 64 );
+ }
+ }
+ }
+
+ if ( (nStyle & FRAME_HIGHLIGHT_STYLE) == FRAME_HIGHLIGHT_IN )
+ {
+ Color aTempColor = aLightColor;
+ aLightColor = aShadowColor;
+ aShadowColor = aTempColor;
+ }
+
+ DrawFrame( rRect, aLightColor, aShadowColor );
+}
+
+// =======================================================================
+
+static void ImplDrawDPILineRect( OutputDevice* pDev, Rectangle& rRect,
+ const Color* pColor, BOOL bRound = FALSE )
+{
+ long nLineWidth = pDev->ImplGetDPIX()/300;
+ long nLineHeight = pDev->ImplGetDPIY()/300;
+ if ( !nLineWidth )
+ nLineWidth = 1;
+ if ( !nLineHeight )
+ nLineHeight = 1;
+
+ if ( pColor )
+ {
+ if ( (nLineWidth == 1) && (nLineHeight == 1) )
+ {
+ pDev->SetLineColor( *pColor );
+ pDev->SetFillColor();
+ if( bRound )
+ {
+ pDev->DrawLine( Point( rRect.Left()+1, rRect.Top()), Point( rRect.Right()-1, rRect.Top()) );
+ pDev->DrawLine( Point( rRect.Left()+1, rRect.Bottom()), Point( rRect.Right()-1, rRect.Bottom()) );
+ pDev->DrawLine( Point( rRect.Left(), rRect.Top()+1), Point( rRect.Left(), rRect.Bottom()-1) );
+ pDev->DrawLine( Point( rRect.Right(), rRect.Top()+1), Point( rRect.Right(), rRect.Bottom()-1) );
+ }
+ else
+ pDev->DrawRect( rRect );
+ }
+ else
+ {
+ long nWidth = rRect.GetWidth();
+ long nHeight = rRect.GetHeight();
+ pDev->SetLineColor();
+ pDev->SetFillColor( *pColor );
+ pDev->DrawRect( Rectangle( rRect.TopLeft(), Size( nWidth, nLineHeight ) ) );
+ pDev->DrawRect( Rectangle( rRect.TopLeft(), Size( nLineWidth, nHeight ) ) );
+ pDev->DrawRect( Rectangle( Point( rRect.Left(), rRect.Bottom()-nLineHeight ),
+ Size( nWidth, nLineHeight ) ) );
+ pDev->DrawRect( Rectangle( Point( rRect.Right()-nLineWidth, rRect.Top() ),
+ Size( nLineWidth, nHeight ) ) );
+ }
+ }
+
+ rRect.Left() += nLineWidth;
+ rRect.Top() += nLineHeight;
+ rRect.Right() -= nLineWidth;
+ rRect.Bottom() -= nLineHeight;
+}
+
+// =======================================================================
+
+static void ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect,
+ const StyleSettings& rStyleSettings, USHORT nStyle )
+{
+ // mask menu style
+ BOOL bMenuStyle = (nStyle & FRAME_DRAW_MENU) ? TRUE : FALSE;
+ nStyle &= ~FRAME_DRAW_MENU;
+
+ Window *pWin = NULL;
+ if( pDev->GetOutDevType() == OUTDEV_WINDOW )
+ pWin = (Window*) pDev;
+
+ // UseFlatBorders disables 3D style for all frames except menus
+ // menus may use different border colors (eg on XP)
+ // normal frames will be drawn using the shadow color
+ // whereas window frame borders will use black
+ BOOL bFlatBorders = ( !bMenuStyle && rStyleSettings.GetUseFlatBorders() );
+
+ // no flat borders for standard VCL controls (ie formcontrols that keep their classic look)
+ // will not affect frame windows (like dropdowns)
+ if( bFlatBorders && pWin && pWin->GetType() == WINDOW_BORDERWINDOW && (pWin != pWin->ImplGetFrameWindow()) )
+ {
+ // check for formcontrol, i.e., a control without NWF enabled
+ Control *pControl = dynamic_cast< Control* >( pWin->GetWindow( WINDOW_CLIENT ) );
+ if( pControl && pControl->IsNativeWidgetEnabled() )
+ bFlatBorders = TRUE;
+ else
+ bFlatBorders = FALSE;
+ }
+
+ // no round corners for window frame borders
+ BOOL bRound = (bFlatBorders && !(nStyle & FRAME_DRAW_WINDOWBORDER));
+
+ if ( (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ||
+ (pDev->GetOutDevType() == OUTDEV_PRINTER) ||
+ bFlatBorders )
+ nStyle |= FRAME_DRAW_MONO;
+
+ if ( nStyle & FRAME_DRAW_NODRAW )
+ {
+ USHORT nValueStyle = bMenuStyle ? nStyle | FRAME_DRAW_MENU : nStyle;
+ if( pWin->GetType() == WINDOW_BORDERWINDOW )
+ nValueStyle |= FRAME_DRAW_BORDERWINDOWBORDER;
+ ImplControlValue aControlValue( nValueStyle );
+ Rectangle aBound, aContent;
+ Rectangle aNatRgn( rRect );
+ if(pWin && pWin->GetNativeControlRegion(CTRL_FRAME, PART_BORDER,
+ aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ rRect = aContent;
+ }
+ else if ( nStyle & FRAME_DRAW_MONO )
+ ImplDrawDPILineRect( pDev, rRect, NULL, bRound );
+ else
+ {
+ USHORT nFrameStyle = nStyle & FRAME_DRAW_STYLE;
+
+ if ( nFrameStyle == FRAME_DRAW_GROUP )
+ {
+ rRect.Left() += 2;
+ rRect.Top() += 2;
+ rRect.Right() -= 2;
+ rRect.Bottom() -= 2;
+ }
+ else if ( (nFrameStyle == FRAME_DRAW_IN) ||
+ (nFrameStyle == FRAME_DRAW_OUT) )
+ {
+ rRect.Left()++;
+ rRect.Top()++;
+ rRect.Right()--;
+ rRect.Bottom()--;
+ }
+ else // FRAME_DRAW_DOUBLEIN || FRAME_DRAW_DOUBLEOUT
+ {
+ rRect.Left() += 2;
+ rRect.Top() += 2;
+ rRect.Right() -= 2;
+ rRect.Bottom() -= 2;
+ }
+ }
+ }
+ else
+ {
+ if( pWin && pWin->IsNativeControlSupported(CTRL_FRAME, PART_BORDER) )
+ {
+ USHORT nValueStyle = bMenuStyle ? nStyle | FRAME_DRAW_MENU : nStyle;
+ if( pWin->GetType() == WINDOW_BORDERWINDOW )
+ nValueStyle |= FRAME_DRAW_BORDERWINDOWBORDER;
+ ImplControlValue aControlValue( nValueStyle );
+ Rectangle aBound, aContent;
+ Rectangle aNatRgn( rRect );
+ if( pWin->GetNativeControlRegion(CTRL_FRAME, PART_BORDER,
+ aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ if( pWin->DrawNativeControl( CTRL_FRAME, PART_BORDER, aContent, CTRL_STATE_ENABLED,
+ aControlValue, rtl::OUString()) )
+ {
+ rRect = aContent;
+ return;
+ }
+ }
+ }
+
+ if ( nStyle & FRAME_DRAW_MONO )
+ {
+ Color aColor = bRound ? rStyleSettings.GetShadowColor()
+ : pDev->GetSettings().GetStyleSettings().GetMonoColor();
+ // when the MonoColor wasn't set, check face color
+ if (
+ (bRound && aColor.IsDark()) ||
+ (
+ (aColor == Color(COL_BLACK)) &&
+ (pDev->GetSettings().GetStyleSettings().GetFaceColor().IsDark())
+ )
+ )
+ {
+ aColor = Color( COL_WHITE );
+ }
+ ImplDrawDPILineRect( pDev, rRect, &aColor, bRound );
+ }
+ else
+ {
+ USHORT nFrameStyle = nStyle & FRAME_DRAW_STYLE;
+ if ( nFrameStyle == FRAME_DRAW_GROUP )
+ {
+ pDev->SetFillColor();
+ pDev->SetLineColor( rStyleSettings.GetLightColor() );
+ rRect.Top()++;
+ rRect.Left()++;
+ pDev->DrawRect( rRect );
+ rRect.Top()--;
+ rRect.Left()--;
+ pDev->SetLineColor( rStyleSettings.GetShadowColor() );
+ rRect.Right()--;
+ rRect.Bottom()--;
+ pDev->DrawRect( rRect );
+ rRect.Right()++;
+ rRect.Bottom()++;
+ }
+ else
+ {
+ pDev->SetLineColor();
+
+ if ( (nFrameStyle == FRAME_DRAW_IN) ||
+ (nFrameStyle == FRAME_DRAW_OUT) )
+ {
+ if ( nFrameStyle == FRAME_DRAW_IN )
+ {
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetShadowColor(),
+ rStyleSettings.GetLightColor() );
+ }
+ else
+ {
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetLightColor(),
+ rStyleSettings.GetShadowColor() );
+ }
+
+ rRect.Left()++;
+ rRect.Top()++;
+ rRect.Right()--;
+ rRect.Bottom()--;
+ }
+ else // FRAME_DRAW_DOUBLEIN || FRAME_DRAW_DOUBLEOUT
+ {
+ if ( nFrameStyle == FRAME_DRAW_DOUBLEIN )
+ {
+ if( bFlatBorders ) // no 3d effect
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetShadowColor(),
+ rStyleSettings.GetShadowColor() );
+ else
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetShadowColor(),
+ rStyleSettings.GetLightColor() );
+ }
+ else
+ {
+ if( bMenuStyle )
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetMenuBorderColor(),
+ rStyleSettings.GetDarkShadowColor() );
+ else
+ pDev->ImplDraw2ColorFrame( rRect,
+ bFlatBorders ? // no 3d effect
+ rStyleSettings.GetDarkShadowColor() :
+ rStyleSettings.GetLightBorderColor(),
+ rStyleSettings.GetDarkShadowColor() );
+
+ }
+
+ rRect.Left()++;
+ rRect.Top()++;
+ rRect.Right()--;
+ rRect.Bottom()--;
+
+ BOOL bDrawn = TRUE;
+ if ( nFrameStyle == FRAME_DRAW_DOUBLEIN )
+ {
+ if( bFlatBorders ) // no 3d effect
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetFaceColor(),
+ rStyleSettings.GetFaceColor() );
+ else
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetDarkShadowColor(),
+ rStyleSettings.GetLightBorderColor() );
+ }
+ else
+ {
+ // flat menues have no shadow border
+ if( !bMenuStyle || !rStyleSettings.GetUseFlatMenues() )
+ pDev->ImplDraw2ColorFrame( rRect,
+ rStyleSettings.GetLightColor(),
+ rStyleSettings.GetShadowColor() );
+ else
+ bDrawn = FALSE;
+ }
+ if( bDrawn )
+ {
+ rRect.Left()++;
+ rRect.Top()++;
+ rRect.Right()--;
+ rRect.Bottom()--;
+ }
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle DecorationView::DrawFrame( const Rectangle& rRect, USHORT nStyle )
+{
+ Rectangle aRect = rRect;
+ BOOL bOldMap = mpOutDev->IsMapModeEnabled();
+ if ( bOldMap )
+ {
+ aRect = mpOutDev->LogicToPixel( aRect );
+ mpOutDev->EnableMapMode( FALSE );
+ }
+
+ if ( !rRect.IsEmpty() )
+ {
+ if ( nStyle & FRAME_DRAW_NODRAW )
+ ImplDrawFrame( mpOutDev, aRect, mpOutDev->GetSettings().GetStyleSettings(), nStyle );
+ else
+ {
+ Color maOldLineColor = mpOutDev->GetLineColor();
+ Color maOldFillColor = mpOutDev->GetFillColor();
+ ImplDrawFrame( mpOutDev, aRect, mpOutDev->GetSettings().GetStyleSettings(), nStyle );
+ mpOutDev->SetLineColor( maOldLineColor );
+ mpOutDev->SetFillColor( maOldFillColor );
+ }
+ }
+
+ if ( bOldMap )
+ {
+ mpOutDev->EnableMapMode( bOldMap );
+ aRect = mpOutDev->PixelToLogic( aRect );
+ }
+
+ return aRect;
+}
+
+// =======================================================================
+
+static void ImplDrawButton( OutputDevice* pDev, Rectangle& rRect,
+ const StyleSettings& rStyleSettings, USHORT nStyle )
+{
+ Rectangle aFillRect = rRect;
+
+ if ( nStyle & BUTTON_DRAW_MONO )
+ {
+ if ( !(nStyle & BUTTON_DRAW_NODRAW) )
+ {
+ Color aBlackColor( COL_BLACK );
+
+ if ( nStyle & BUTTON_DRAW_DEFAULT )
+ ImplDrawDPILineRect( pDev, aFillRect, &aBlackColor );
+
+ ImplDrawDPILineRect( pDev, aFillRect, &aBlackColor );
+
+ Size aBrdSize( 1, 1 );
+ if ( pDev->GetOutDevType() == OUTDEV_PRINTER )
+ {
+ MapMode aResMapMode( MAP_100TH_MM );
+ aBrdSize = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode );
+ if ( !aBrdSize.Width() )
+ aBrdSize.Width() = 1;
+ if ( !aBrdSize.Height() )
+ aBrdSize.Height() = 1;
+ }
+ pDev->SetLineColor();
+ pDev->SetFillColor( aBlackColor );
+ Rectangle aRect1;
+ Rectangle aRect2;
+ aRect1.Left() = aFillRect.Left();
+ aRect1.Right() = aFillRect.Right(),
+ aRect2.Top() = aFillRect.Top();
+ aRect2.Bottom() = aFillRect.Bottom();
+ if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) )
+ {
+ aRect1.Top() = aFillRect.Top();
+ aRect1.Bottom() = aBrdSize.Height()-1;
+ aRect2.Left() = aFillRect.Left();
+ aRect2.Right() = aFillRect.Left()+aBrdSize.Width()-1;
+ aFillRect.Left() += aBrdSize.Width();
+ aFillRect.Top() += aBrdSize.Height();
+ }
+ else
+ {
+ aRect1.Top() = aFillRect.Bottom()-aBrdSize.Height()+1;
+ aRect1.Bottom() = aFillRect.Bottom();
+ aRect2.Left() = aFillRect.Right()-aBrdSize.Width()+1;
+ aRect2.Right() = aFillRect.Right(),
+ aFillRect.Right() -= aBrdSize.Width();
+ aFillRect.Bottom() -= aBrdSize.Height();
+ }
+ pDev->DrawRect( aRect1 );
+ pDev->DrawRect( aRect2 );
+ }
+ }
+ else
+ {
+ if ( !(nStyle & BUTTON_DRAW_NODRAW) )
+ {
+ if ( nStyle & BUTTON_DRAW_DEFAULT )
+ {
+ Color aDefBtnColor = rStyleSettings.GetDarkShadowColor();
+ ImplDrawDPILineRect( pDev, aFillRect, &aDefBtnColor );
+ }
+ }
+
+ if ( !(nStyle & BUTTON_DRAW_NODRAW) )
+ {
+ pDev->SetLineColor();
+ if ( nStyle & BUTTON_DRAW_NOLEFTLIGHTBORDER )
+ {
+ pDev->SetFillColor( rStyleSettings.GetLightBorderColor() );
+ pDev->DrawRect( Rectangle( aFillRect.Left(), aFillRect.Top(),
+ aFillRect.Left(), aFillRect.Bottom() ) );
+ aFillRect.Left()++;
+ }
+ if ( (nStyle & BUTTON_DRAW_NOTOPLIGHTBORDER) &&
+ !(nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED)) )
+ {
+ pDev->SetFillColor( rStyleSettings.GetLightBorderColor() );
+ pDev->DrawRect( Rectangle( aFillRect.Left(), aFillRect.Top(),
+ aFillRect.Right(), aFillRect.Top() ) );
+ aFillRect.Top()++;
+ }
+ if ( (( (nStyle & BUTTON_DRAW_NOBOTTOMSHADOWBORDER) | BUTTON_DRAW_FLAT) == (BUTTON_DRAW_NOBOTTOMSHADOWBORDER | BUTTON_DRAW_FLAT)) &&
+ !(nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED | BUTTON_DRAW_HIGHLIGHT)) )
+ {
+ pDev->SetFillColor( rStyleSettings.GetDarkShadowColor() );
+ pDev->DrawRect( Rectangle( aFillRect.Left(), aFillRect.Bottom(),
+ aFillRect.Right(), aFillRect.Bottom() ) );
+ aFillRect.Bottom()--;
+ }
+
+ Color aColor1;
+ Color aColor2;
+ if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) )
+ {
+ aColor1 = rStyleSettings.GetDarkShadowColor();
+ aColor2 = rStyleSettings.GetLightColor();
+ }
+ else
+ {
+ if ( nStyle & BUTTON_DRAW_NOLIGHTBORDER )
+ aColor1 = rStyleSettings.GetLightBorderColor();
+ else
+ aColor1 = rStyleSettings.GetLightColor();
+ if ( (nStyle & BUTTON_DRAW_FLATTEST) == BUTTON_DRAW_FLAT )
+ aColor2 = rStyleSettings.GetShadowColor();
+ else
+ aColor2 = rStyleSettings.GetDarkShadowColor();
+ }
+ pDev->ImplDraw2ColorFrame( aFillRect, aColor1, aColor2 );
+ aFillRect.Left()++;
+ aFillRect.Top()++;
+ aFillRect.Right()--;
+ aFillRect.Bottom()--;
+
+ if ( !((nStyle & BUTTON_DRAW_FLATTEST) == BUTTON_DRAW_FLAT) )
+ {
+ if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) )
+ {
+ aColor1 = rStyleSettings.GetShadowColor();
+ aColor2 = rStyleSettings.GetLightBorderColor();
+ }
+ else
+ {
+ if ( nStyle & BUTTON_DRAW_NOLIGHTBORDER )
+ aColor1 = rStyleSettings.GetLightColor();
+ else
+ aColor1 = rStyleSettings.GetLightBorderColor();
+ aColor2 = rStyleSettings.GetShadowColor();
+ }
+ pDev->ImplDraw2ColorFrame( aFillRect, aColor1, aColor2 );
+ aFillRect.Left()++;
+ aFillRect.Top()++;
+ aFillRect.Right()--;
+ aFillRect.Bottom()--;
+ }
+ }
+ }
+
+ if ( !(nStyle & (BUTTON_DRAW_NOFILL | BUTTON_DRAW_NODRAW)) )
+ {
+ pDev->SetLineColor();
+ if ( nStyle & BUTTON_DRAW_MONO )
+ {
+ // Hack: Auf Druckern wollen wir im MonoChrom-Modus trotzdem
+ // erstmal graue Buttons haben
+ if ( pDev->GetOutDevType() == OUTDEV_PRINTER )
+ pDev->SetFillColor( Color( COL_LIGHTGRAY ) );
+ else
+ pDev->SetFillColor( Color( COL_WHITE ) );
+ }
+ else
+ {
+ if ( nStyle & (BUTTON_DRAW_CHECKED | BUTTON_DRAW_DONTKNOW) )
+ pDev->SetFillColor( rStyleSettings.GetCheckedColor() );
+ else
+ pDev->SetFillColor( rStyleSettings.GetFaceColor() );
+ }
+ pDev->DrawRect( aFillRect );
+ }
+
+ // Ein Border freilassen, der jedoch bei Default-Darstellung
+ // mitbenutzt wird
+ rRect.Left()++;
+ rRect.Top()++;
+ rRect.Right()--;
+ rRect.Bottom()--;
+
+ if ( nStyle & BUTTON_DRAW_NOLIGHTBORDER )
+ {
+ rRect.Left()++;
+ rRect.Top()++;
+ }
+ else if ( nStyle & BUTTON_DRAW_NOLEFTLIGHTBORDER )
+ rRect.Left()++;
+
+ if ( nStyle & BUTTON_DRAW_PRESSED )
+ {
+ if ( (rRect.GetHeight() > 10) && (rRect.GetWidth() > 10) )
+ {
+ rRect.Left() += 4;
+ rRect.Top() += 4;
+ rRect.Right() -= 1;
+ rRect.Bottom() -= 1;
+ }
+ else
+ {
+ rRect.Left() += 3;
+ rRect.Top() += 3;
+ rRect.Right() -= 2;
+ rRect.Bottom() -= 2;
+ }
+ }
+ else if ( nStyle & BUTTON_DRAW_CHECKED )
+ {
+ rRect.Left() += 3;
+ rRect.Top() += 3;
+ rRect.Right() -= 2;
+ rRect.Bottom() -= 2;
+ }
+ else
+ {
+ rRect.Left() += 2;
+ rRect.Top() += 2;
+ rRect.Right() -= 3;
+ rRect.Bottom() -= 3;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle DecorationView::DrawButton( const Rectangle& rRect, USHORT nStyle )
+{
+ Rectangle aRect = rRect;
+ BOOL bOldMap = mpOutDev->IsMapModeEnabled();
+ if ( bOldMap )
+ {
+ aRect = mpOutDev->LogicToPixel( aRect );
+ mpOutDev->EnableMapMode( FALSE );
+ }
+
+ if ( !rRect.IsEmpty() )
+ {
+ const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings();
+
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO )
+ nStyle |= BUTTON_DRAW_MONO;
+
+ if ( nStyle & BUTTON_DRAW_NODRAW )
+ ImplDrawButton( mpOutDev, aRect, rStyleSettings, nStyle );
+ else
+ {
+ Color maOldLineColor = mpOutDev->GetLineColor();
+ Color maOldFillColor = mpOutDev->GetFillColor();
+ ImplDrawButton( mpOutDev, aRect, rStyleSettings, nStyle );
+ mpOutDev->SetLineColor( maOldLineColor );
+ mpOutDev->SetFillColor( maOldFillColor );
+ }
+ }
+
+ if ( bOldMap )
+ {
+ mpOutDev->EnableMapMode( bOldMap );
+ aRect = mpOutDev->PixelToLogic( aRect );
+ }
+
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+void DecorationView::DrawSeparator( const Point& rStart, const Point& rStop, bool bVertical )
+{
+ Point aStart( rStart ), aStop( rStop );
+ const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings();
+
+ mpOutDev->Push( PUSH_LINECOLOR );
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO )
+ mpOutDev->SetLineColor( Color( COL_BLACK ) );
+ else
+ mpOutDev->SetLineColor( rStyleSettings.GetShadowColor() );
+
+ mpOutDev->DrawLine( aStart, aStop );
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ {
+ mpOutDev->SetLineColor( rStyleSettings.GetLightColor() );
+ if( bVertical )
+ {
+ aStart.X()++;
+ aStop.X()++;
+ }
+ else
+ {
+ aStart.Y()++;
+ aStop.Y()++;
+ }
+ mpOutDev->DrawLine( aStart, aStop );
+ }
+ mpOutDev->Pop();
+}
+
diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx
new file mode 100644
index 000000000000..3b5585d3bc63
--- /dev/null
+++ b/vcl/source/window/dialog.cxx
@@ -0,0 +1,1028 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.h>
+#include <vcl/event.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/button.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/dialog.hxx>
+#include <vcl/decoview.hxx>
+
+#ifdef DBG_UTIL
+#include <vcl/msgbox.hxx>
+#endif
+
+#include <vcl/unowrap.hxx>
+
+
+
+// =======================================================================
+
+#ifdef DBG_UTIL
+
+static ByteString ImplGetDialogText( Dialog* pDialog )
+{
+ ByteString aErrorStr( pDialog->GetText(), RTL_TEXTENCODING_UTF8 );
+ if ( (pDialog->GetType() == WINDOW_MESSBOX) ||
+ (pDialog->GetType() == WINDOW_INFOBOX) ||
+ (pDialog->GetType() == WINDOW_WARNINGBOX) ||
+ (pDialog->GetType() == WINDOW_ERRORBOX) ||
+ (pDialog->GetType() == WINDOW_QUERYBOX) )
+ {
+ aErrorStr += ", ";
+ aErrorStr += ByteString( ((MessBox*)pDialog)->GetMessText(), RTL_TEXTENCODING_UTF8 );
+ }
+ return aErrorStr;
+}
+
+#endif
+
+// =======================================================================
+
+static BOOL ImplIsMnemonicCtrl( Window* pWindow )
+{
+ if( ! pWindow->GetSettings().GetStyleSettings().GetAutoMnemonic() )
+ return FALSE;
+
+ if ( (pWindow->GetType() == WINDOW_RADIOBUTTON) ||
+ (pWindow->GetType() == WINDOW_CHECKBOX) ||
+ (pWindow->GetType() == WINDOW_TRISTATEBOX) ||
+ (pWindow->GetType() == WINDOW_PUSHBUTTON) )
+ return TRUE;
+
+ if ( pWindow->GetType() == WINDOW_FIXEDTEXT )
+ {
+ if ( pWindow->GetStyle() & (WB_INFO | WB_NOLABEL) )
+ return FALSE;
+ Window* pNextWindow = pWindow->GetWindow( WINDOW_NEXT );
+ if ( !pNextWindow )
+ return FALSE;
+ pNextWindow = pNextWindow->GetWindow( WINDOW_CLIENT );
+ if ( !(pNextWindow->GetStyle() & WB_TABSTOP) ||
+ (pNextWindow->GetType() == WINDOW_FIXEDTEXT) ||
+ (pNextWindow->GetType() == WINDOW_GROUPBOX) ||
+ (pNextWindow->GetType() == WINDOW_RADIOBUTTON) ||
+ (pNextWindow->GetType() == WINDOW_CHECKBOX) ||
+ (pNextWindow->GetType() == WINDOW_TRISTATEBOX) ||
+ (pNextWindow->GetType() == WINDOW_PUSHBUTTON) )
+ return FALSE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWindowAutoMnemonic( Window* pWindow )
+{
+ MnemonicGenerator aMnemonicGenerator;
+ Window* pGetChild;
+ Window* pChild;
+
+ // Die schon vergebenen Mnemonics registieren
+ pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pGetChild )
+ {
+ pChild = pGetChild->ImplGetWindow();
+ aMnemonicGenerator.RegisterMnemonic( pChild->GetText() );
+ pGetChild = pGetChild->GetWindow( WINDOW_NEXT );
+ }
+
+ // Bei TabPages auch noch die Controls vom Dialog beruecksichtigen
+ if ( pWindow->GetType() == WINDOW_TABPAGE )
+ {
+ Window* pParent = pWindow->GetParent();
+ if ( pParent->GetType() == WINDOW_TABCONTROL )
+ pParent = pParent->GetParent();
+
+ if ( (pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL )
+ {
+ pGetChild = pParent->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pGetChild )
+ {
+ pChild = pGetChild->ImplGetWindow();
+ aMnemonicGenerator.RegisterMnemonic( pChild->GetText() );
+ pGetChild = pGetChild->GetWindow( WINDOW_NEXT );
+ }
+ }
+ }
+
+ // Die Mnemonics an die Controls vergeben, die noch keinen haben
+ pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pGetChild )
+ {
+ pChild = pGetChild->ImplGetWindow();
+ if ( ImplIsMnemonicCtrl( pChild ) )
+ {
+ XubString aText = pChild->GetText();
+ if ( aMnemonicGenerator.CreateMnemonic( aText ) )
+ pChild->SetText( aText );
+ }
+
+ pGetChild = pGetChild->GetWindow( WINDOW_NEXT );
+ }
+}
+
+// =======================================================================
+
+static PushButton* ImplGetDefaultButton( Dialog* pDialog )
+{
+ Window* pChild = pDialog->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pChild )
+ {
+ if ( pChild->ImplIsPushButton() )
+ {
+ PushButton* pPushButton = (PushButton*)pChild;
+ if ( pPushButton->ImplIsDefButton() )
+ return pPushButton;
+ }
+
+ pChild = pChild->GetWindow( WINDOW_NEXT );
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static PushButton* ImplGetOKButton( Dialog* pDialog )
+{
+ Window* pChild = pDialog->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pChild )
+ {
+ if ( pChild->GetType() == WINDOW_OKBUTTON )
+ return (PushButton*)pChild;
+
+ pChild = pChild->GetWindow( WINDOW_NEXT );
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static PushButton* ImplGetCancelButton( Dialog* pDialog )
+{
+ Window* pChild = pDialog->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pChild )
+ {
+ if ( pChild->GetType() == WINDOW_CANCELBUTTON )
+ return (PushButton*)pChild;
+
+ pChild = pChild->GetWindow( WINDOW_NEXT );
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplMouseAutoPos( Dialog* pDialog )
+{
+ ULONG nMouseOptions = pDialog->GetSettings().GetMouseSettings().GetOptions();
+ if ( nMouseOptions & MOUSE_OPTION_AUTOCENTERPOS )
+ {
+ Size aSize = pDialog->GetOutputSizePixel();
+ pDialog->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) );
+ }
+ else if ( nMouseOptions & MOUSE_OPTION_AUTODEFBTNPOS )
+ {
+ Window* pWindow = ImplGetDefaultButton( pDialog );
+ if ( !pWindow )
+ pWindow = ImplGetOKButton( pDialog );
+ if ( !pWindow )
+ pWindow = ImplGetCancelButton( pDialog );
+ if ( !pWindow )
+ pWindow = pDialog;
+ Size aSize = pWindow->GetOutputSizePixel();
+ pWindow->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) );
+ }
+}
+
+// =======================================================================
+
+struct DialogImpl
+{
+ long mnResult;
+ bool mbStartedModal;
+ Link maEndDialogHdl;
+
+ DialogImpl() : mnResult( -1 ), mbStartedModal( false ) {}
+};
+
+// =======================================================================
+
+void Dialog::ImplInitDialogData()
+{
+ mpWindowImpl->mbDialog = TRUE;
+ mpDialogParent = NULL;
+ mpPrevExecuteDlg = NULL;
+ mbInExecute = FALSE;
+ mbOldSaveBack = FALSE;
+ mbInClose = FALSE;
+ mbModalMode = FALSE;
+ mnMousePositioned = 0;
+ mpDialogImpl = new DialogImpl;
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::ImplInit( Window* pParent, WinBits nStyle )
+{
+ USHORT nSysWinMode = Application::GetSystemWindowMode();
+
+ if ( !(nStyle & WB_NODIALOGCONTROL) )
+ nStyle |= WB_DIALOGCONTROL;
+ nStyle |= WB_ROLLABLE;
+
+ // Now, all Dialogs are per default system windows !!!
+ nStyle |= WB_SYSTEMWINDOW;
+
+
+ // parent is NULL: get the default Dialog parent
+ if ( !pParent )
+ {
+ pParent = Application::GetDefDialogParent();
+ if ( !pParent && !(nStyle & WB_SYSTEMWINDOW) )
+ pParent = ImplGetSVData()->maWinData.mpAppWin;
+
+ // If Parent is disabled, then we search for a modal dialog
+ // in this frame
+ if ( pParent && (!pParent->IsInputEnabled() || pParent->IsInModalMode()) )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg;
+ while ( pExeDlg )
+ {
+ // Nur wenn er sichtbar und enabled ist
+ if ( pParent->ImplGetFirstOverlapWindow()->IsWindowOrChild( pExeDlg, TRUE ) &&
+ pExeDlg->IsReallyVisible() &&
+ pExeDlg->IsEnabled() && pExeDlg->IsInputEnabled() && !pExeDlg->IsInModalMode() )
+ {
+ pParent = pExeDlg;
+ break;
+ }
+
+ pExeDlg = pExeDlg->mpPrevExecuteDlg;
+ }
+ }
+ }
+ // DIALOG_NO_PARENT: explicitly don't have a parent for this Dialog
+ else if( pParent == DIALOG_NO_PARENT )
+ pParent = NULL;
+
+/*
+ // Now, all Dialogs are per default system windows !!!
+ if ( pParent && !(nSysWinMode & SYSTEMWINDOW_MODE_NOAUTOMODE) )
+ {
+ if ( !pParent->mpWindowImpl->mpFrameWindow->IsVisible() )
+ pParent = NULL;
+ else
+ {
+ if ( pParent->mpWindowImpl->mpFrameWindow->IsDialog() )
+ {
+ Size aOutSize = pParent->mpWindowImpl->mpFrameWindow->GetOutputSizePixel();
+ if ( (aOutSize.Width() < 210) ||(aOutSize.Height() < 160) )
+ nStyle |= WB_SYSTEMWINDOW;
+ }
+ }
+ }
+*/
+
+ if ( !pParent || (nStyle & WB_SYSTEMWINDOW) ||
+ (pParent->mpWindowImpl->mpFrameData->mbNeedSysWindow && !(nSysWinMode & SYSTEMWINDOW_MODE_NOAUTOMODE)) ||
+ (nSysWinMode & SYSTEMWINDOW_MODE_DIALOG) )
+ {
+ // create window with a small border ?
+ if ( (nStyle & (WB_BORDER | WB_NOBORDER | WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE)) == WB_BORDER )
+ {
+ ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle, BORDERWINDOW_STYLE_FRAME );
+ SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL );
+ pBorderWin->mpWindowImpl->mpClientWindow = this;
+ pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ mpWindowImpl->mpBorderWindow = pBorderWin;
+ mpWindowImpl->mpRealParent = pParent;
+ }
+ else
+ {
+ mpWindowImpl->mbFrame = TRUE;
+ mpWindowImpl->mbOverlapWin = TRUE;
+ SystemWindow::ImplInit( pParent, (nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_CLOSEABLE | WB_STANDALONE)) | WB_CLOSEABLE, NULL );
+ // Now set all style bits
+ mpWindowImpl->mnStyle = nStyle;
+ }
+ }
+ else
+ {
+ ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle, BORDERWINDOW_STYLE_OVERLAP | BORDERWINDOW_STYLE_BORDER );
+ SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL );
+ pBorderWin->mpWindowImpl->mpClientWindow = this;
+ pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ mpWindowImpl->mpBorderWindow = pBorderWin;
+ mpWindowImpl->mpRealParent = pParent;
+ }
+
+ SetActivateMode( ACTIVATE_MODE_GRABFOCUS );
+
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::ImplInitSettings()
+{
+ // user override
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ // NWF background
+ else if( IsNativeControlSupported( CTRL_WINDOW_BACKGROUND, PART_BACKGROUND_DIALOG ) )
+ {
+ mpWindowImpl->mnNativeBackground = PART_BACKGROUND_DIALOG;
+ EnableChildTransparentMode( TRUE );
+ }
+ // fallback to settings color
+ else
+ SetBackground( GetSettings().GetStyleSettings().GetDialogColor() );
+
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::ImplCenterDialog()
+{
+ Rectangle aDeskRect = ImplGetFrameWindow()->GetDesktopRectPixel();
+ Point aDeskPos = aDeskRect.TopLeft();
+ Size aDeskSize = aDeskRect.GetSize();
+ Size aWinSize = GetSizePixel();
+ Window *pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+ Point aWinPos( ((aDeskSize.Width() - aWinSize.Width()) / 2) + aDeskPos.X(),
+ ((aDeskSize.Height() - aWinSize.Height()) / 2) + aDeskPos.Y() );
+
+ // Pruefen, ob Dialogbox ausserhalb des Desks liegt
+ if ( (aWinPos.X() + aWinSize.Width()) > (aDeskPos.X()+aDeskSize.Width()) )
+ aWinPos.X() = aDeskPos.X()+aDeskSize.Width() - aWinSize.Width();
+ if ( (aWinPos.Y()+aWinSize.Height()) > (aDeskPos.Y()+aDeskSize.Height()) )
+ aWinPos.Y() = aDeskPos.Y()+aDeskSize.Height() - aWinSize.Height();
+ // Linke Ecke bevorzugen, da Titelbar oben ist
+ if ( aWinPos.X() < aDeskPos.X() )
+ aWinPos.X() = aDeskPos.X();
+ if ( aWinPos.Y() < aDeskPos.Y() )
+ aWinPos.Y() = aDeskPos.Y();
+
+ //SetPosPixel( aWinPos );
+ SetPosPixel( pWindow->ScreenToOutputPixel( aWinPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+Dialog::Dialog( WindowType nType ) :
+ SystemWindow( nType )
+{
+ ImplInitDialogData();
+}
+
+// -----------------------------------------------------------------------
+
+Dialog::Dialog( Window* pParent, WinBits nStyle ) :
+ SystemWindow( WINDOW_DIALOG )
+{
+ ImplInitDialogData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+Dialog::Dialog( Window* pParent, const ResId& rResId ) :
+ SystemWindow( WINDOW_DIALOG )
+{
+ ImplInitDialogData();
+ rResId.SetRT( RSC_DIALOG );
+ ImplInit( pParent, ImplInitRes( rResId ) );
+ ImplLoadRes( rResId );
+}
+
+// -----------------------------------------------------------------------
+
+Dialog::~Dialog()
+{
+ delete mpDialogImpl;
+ mpDialogImpl = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Dialog, ImplAsyncCloseHdl, void*, EMPTYARG )
+{
+ Close();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+long Dialog::Notify( NotifyEvent& rNEvt )
+{
+ // Zuerst Basisklasse rufen wegen TabSteuerung
+ long nRet = SystemWindow::Notify( rNEvt );
+ if ( !nRet )
+ {
+ if ( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
+ KeyCode aKeyCode = pKEvt->GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+
+ if ( (nKeyCode == KEY_ESCAPE) &&
+ ((GetStyle() & WB_CLOSEABLE) || ImplGetCancelButton( this ) || ImplGetOKButton( this )) )
+ {
+ // #i89505# for the benefit of slightly mentally challenged implementations
+ // like e.g. SfxModelessDialog which destroy themselves inside Close()
+ // post this Close asynchronous so we can leave our key handler before
+ // we get destroyed
+ PostUserEvent( LINK( this, Dialog, ImplAsyncCloseHdl ), this );
+ return TRUE;
+ }
+ }
+ else if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ {
+ // make sure the dialog is still modal
+ // changing focus between application frames may
+ // have re-enabled input for our parent
+ if( mbInExecute && mbModalMode )
+ {
+ // do not change modal counter (pSVData->maAppData.mnModalDialog)
+ SetModalInputMode( FALSE );
+ SetModalInputMode( TRUE );
+
+ // #93022# def-button might have changed after show
+ if( !mnMousePositioned )
+ {
+ mnMousePositioned = 1;
+ ImplMouseAutoPos( this );
+ }
+
+ }
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::StateChanged( StateChangedType nType )
+{
+ SystemWindow::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ if ( GetSettings().GetStyleSettings().GetAutoMnemonic() )
+ ImplWindowAutoMnemonic( this );
+
+ //if ( IsDefaultPos() && !mpWindowImpl->mbFrame )
+ // ImplCenterDialog();
+ if ( !HasChildPathFocus() || HasFocus() )
+ GrabFocusToFirstControl();
+ if ( !(GetStyle() & WB_CLOSEABLE) )
+ {
+ if ( ImplGetCancelButton( this ) || ImplGetOKButton( this ) )
+ {
+ if ( ImplGetBorderWindow() )
+ ((ImplBorderWindow*)ImplGetBorderWindow())->SetCloser();
+ }
+ }
+
+ ImplMouseAutoPos( this );
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SystemWindow::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Dialog::Close()
+{
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE );
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ ImplRemoveDel( &aDelData );
+
+ if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() )
+ return FALSE;
+
+ mbInClose = TRUE;
+
+ if ( !(GetStyle() & WB_CLOSEABLE) )
+ {
+ BOOL bRet = TRUE;
+ ImplAddDel( &aDelData );
+ PushButton* pButton = ImplGetCancelButton( this );
+ if ( pButton )
+ pButton->Click();
+ else
+ {
+ pButton = ImplGetOKButton( this );
+ if ( pButton )
+ pButton->Click();
+ else
+ bRet = FALSE;
+ }
+ if ( aDelData.IsDelete() )
+ return TRUE;
+ ImplRemoveDel( &aDelData );
+ return bRet;
+ }
+
+ if ( IsInExecute() )
+ {
+ EndDialog( FALSE );
+ mbInClose = FALSE;
+ return TRUE;
+ }
+ else
+ {
+ mbInClose = FALSE;
+ return SystemWindow::Close();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Dialog::ImplStartExecuteModal()
+{
+ if ( mbInExecute )
+ {
+#ifdef DBG_UTIL
+ ByteString aErrorStr( "Dialog::StartExecuteModal() is called in Dialog::StartExecuteModal(): " );
+ aErrorStr += ImplGetDialogText( this );
+ DBG_ERROR( aErrorStr.GetBuffer() );
+#endif
+ return FALSE;
+ }
+
+ if ( Application::IsDialogCancelEnabled() )
+ {
+#ifdef DBG_UTIL
+ ByteString aErrorStr( "Dialog::StartExecuteModal() is called in a none UI application: " );
+ aErrorStr += ImplGetDialogText( this );
+ DBG_ERROR( aErrorStr.GetBuffer() );
+#endif
+ return FALSE;
+ }
+
+#ifdef DBG_UTIL
+ Window* pParent = GetParent();
+ if ( pParent )
+ {
+ pParent = pParent->ImplGetFirstOverlapWindow();
+ DBG_ASSERT( pParent->IsReallyVisible(),
+ "Dialog::StartExecuteModal() - Parent not visible" );
+ DBG_ASSERT( pParent->IsInputEnabled(),
+ "Dialog::StartExecuteModal() - Parent input disabled, use another parent to ensure modality!" );
+ DBG_ASSERT( ! pParent->IsInModalMode(),
+ "Dialog::StartExecuteModal() - Parent already modally disabled, use another parent to ensure modality!" );
+
+ }
+#endif
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Dialoge, die sich in Execute befinden, miteinander verketten
+ mpPrevExecuteDlg = pSVData->maWinData.mpLastExecuteDlg;
+ pSVData->maWinData.mpLastExecuteDlg = this;
+
+ // Capture beenden, damit der Dialog bedient werden kann
+ if ( pSVData->maWinData.mpTrackWin )
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL );
+ if ( pSVData->maWinData.mpCaptureWin )
+ pSVData->maWinData.mpCaptureWin->ReleaseMouse();
+ EnableInput( TRUE, TRUE );
+
+ if ( GetParent() )
+ {
+ NotifyEvent aNEvt( EVENT_EXECUTEDIALOG, this );
+ GetParent()->Notify( aNEvt );
+ }
+ mbInExecute = TRUE;
+ SetModalInputMode( TRUE );
+ mbOldSaveBack = IsSaveBackgroundEnabled();
+ EnableSaveBackground();
+
+ // FIXME: no layouting, workaround some clipping issues
+ ImplAdjustNWFSizes();
+
+ Show();
+
+ pSVData->maAppData.mnModalMode++;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::ImplEndExecuteModal()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mnModalMode--;
+}
+
+// -----------------------------------------------------------------------
+
+short Dialog::Execute()
+{
+ if ( !ImplStartExecuteModal() )
+ return 0;
+
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+#ifdef DBG_UTIL
+ ImplDelData aParentDelData;
+ Window* pDialogParent = mpDialogParent;
+ if( pDialogParent )
+ pDialogParent->ImplAddDel( &aParentDelData );
+#endif
+
+ // Yield util EndDialog is called or dialog gets destroyed
+ // (the latter should not happen, but better safe than sorry
+ while ( !aDelData.IsDelete() && mbInExecute )
+ Application::Yield();
+
+ ImplEndExecuteModal();
+
+#ifdef DBG_UTIL
+ if( pDialogParent )
+ {
+ if( ! aParentDelData.IsDelete() )
+ pDialogParent->ImplRemoveDel( &aParentDelData );
+ else
+ DBG_ERROR( "Dialog::Execute() - Parent of dialog destroyed in Execute()" );
+ }
+#endif
+ if ( !aDelData.IsDelete() )
+ ImplRemoveDel( &aDelData );
+#ifdef DBG_UTIL
+ else
+ {
+ DBG_ERROR( "Dialog::Execute() - Dialog destroyed in Execute()" );
+ }
+#endif
+
+ long nRet = mpDialogImpl->mnResult;
+ mpDialogImpl->mnResult = -1;
+ return (short)nRet;
+}
+
+// -----------------------------------------------------------------------
+
+// virtual
+void Dialog::StartExecuteModal( const Link& rEndDialogHdl )
+{
+ if ( !ImplStartExecuteModal() )
+ return;
+
+ mpDialogImpl->maEndDialogHdl = rEndDialogHdl;
+ mpDialogImpl->mbStartedModal = true;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Dialog::IsStartedModal() const
+{
+ return mpDialogImpl->mbStartedModal;
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::EndDialog( long nResult )
+{
+ if ( mbInExecute )
+ {
+ SetModalInputMode( FALSE );
+
+ // Dialog aus der Kette der Dialoge die in Execute stehen entfernen
+ ImplSVData* pSVData = ImplGetSVData();
+ Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg;
+ while ( pExeDlg )
+ {
+ if ( pExeDlg == this )
+ {
+ pSVData->maWinData.mpLastExecuteDlg = mpPrevExecuteDlg;
+ break;
+ }
+ pExeDlg = pExeDlg->mpPrevExecuteDlg;
+ }
+ // set focus to previous modal dialogue if it is modal for
+ // the same frame parent (or NULL)
+ if( mpPrevExecuteDlg )
+ {
+ Window* pFrameParent = ImplGetFrameWindow()->ImplGetParent();
+ Window* pPrevFrameParent = mpPrevExecuteDlg->ImplGetFrameWindow()->ImplGetParent();
+ if( ( !pFrameParent && !pPrevFrameParent ) ||
+ ( pFrameParent && pPrevFrameParent && pFrameParent->ImplGetFrame() == pPrevFrameParent->ImplGetFrame() )
+ )
+ {
+ mpPrevExecuteDlg->GrabFocus();
+ }
+ }
+ mpPrevExecuteDlg = NULL;
+
+ Hide();
+ EnableSaveBackground( mbOldSaveBack );
+ if ( GetParent() )
+ {
+ NotifyEvent aNEvt( EVENT_ENDEXECUTEDIALOG, this );
+ GetParent()->Notify( aNEvt );
+ }
+
+ mpDialogImpl->mnResult = nResult;
+
+ if ( mpDialogImpl->mbStartedModal )
+ {
+ ImplEndExecuteModal();
+ mpDialogImpl->maEndDialogHdl.Call( this );
+
+ mpDialogImpl->maEndDialogHdl = Link();
+ mpDialogImpl->mbStartedModal = false;
+ mpDialogImpl->mnResult = -1;
+ }
+ mbInExecute = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long Dialog::GetResult() const
+{
+ return mpDialogImpl->mnResult;
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::EndAllDialogs( Window* pParent )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Dialog* pTempModDialog;
+ Dialog* pModDialog = pSVData->maWinData.mpLastExecuteDlg;
+ while ( pModDialog )
+ {
+ pTempModDialog = pModDialog->mpPrevExecuteDlg;
+ if( !pParent || ( pParent && pParent->IsWindowOrChild( pModDialog, TRUE ) ) )
+ {
+ pModDialog->EndDialog( FALSE );
+ pModDialog->PostUserEvent( Link() );
+ }
+ pModDialog = pTempModDialog;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::SetModalInputMode( BOOL bModal )
+{
+ if ( bModal == mbModalMode )
+ return;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ mbModalMode = bModal;
+ if ( bModal )
+ {
+ pSVData->maAppData.mnModalDialog++;
+
+ // Diable the prev Modal Dialog, because our dialog must close at first,
+ // before the other dialog can be closed (because the other dialog
+ // is on stack since our dialog returns)
+ if ( mpPrevExecuteDlg && !mpPrevExecuteDlg->IsWindowOrChild( this, TRUE ) )
+ mpPrevExecuteDlg->EnableInput( FALSE, TRUE, TRUE, this );
+
+ // determine next overlap dialog parent
+ Window* pParent = GetParent();
+ if ( pParent )
+ {
+ // #103716# dialogs should always be modal to the whole frame window
+ // #115933# disable the whole frame hierarchie, useful if our parent
+ // is a modeless dialog
+ mpDialogParent = pParent->mpWindowImpl->mpFrameWindow;
+ mpDialogParent->ImplIncModalCount();
+ }
+
+ }
+ else
+ {
+ pSVData->maAppData.mnModalDialog--;
+
+ if ( mpDialogParent )
+ {
+ // #115933# re-enable the whole frame hierarchie again (see above)
+ // note that code in getfocus assures that we do not accidentally enable
+ // windows that were disabled before
+ mpDialogParent->ImplDecModalCount();
+ }
+
+ // Enable the prev Modal Dialog
+ if ( mpPrevExecuteDlg && !mpPrevExecuteDlg->IsWindowOrChild( this, TRUE ) )
+ {
+ mpPrevExecuteDlg->EnableInput( TRUE, TRUE, TRUE, this );
+ // ensure continued modality of prev dialog
+ // do not change modality counter
+ mpPrevExecuteDlg->SetModalInputMode( FALSE );
+ mpPrevExecuteDlg->SetModalInputMode( TRUE );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::SetModalInputMode( BOOL bModal, BOOL bSubModalDialogs )
+{
+ if ( bSubModalDialogs )
+ {
+ Window* pOverlap = ImplGetFirstOverlapWindow();
+ pOverlap = pOverlap->mpWindowImpl->mpFirstOverlap;
+ while ( pOverlap )
+ {
+ if ( pOverlap->IsDialog() )
+ ((Dialog*)pOverlap)->SetModalInputMode( bModal, TRUE );
+ pOverlap = pOverlap->mpWindowImpl->mpNext;
+ }
+ }
+
+ SetModalInputMode( bModal );
+}
+
+// -----------------------------------------------------------------------
+
+void Dialog::GrabFocusToFirstControl()
+{
+ Window* pFocusControl;
+
+ // Wenn Dialog den Focus hat, versuchen wr trotzdem
+ // ein Focus-Control zu finden
+ if ( HasFocus() )
+ pFocusControl = NULL;
+ else
+ {
+ // Wenn schon ein Child-Fenster mal den Focus hatte,
+ // dann dieses bevorzugen
+ pFocusControl = ImplGetFirstOverlapWindow()->mpWindowImpl->mpLastFocusWindow;
+ // Control aus der Dialog-Steuerung suchen
+ if ( pFocusControl )
+ pFocusControl = ImplFindDlgCtrlWindow( pFocusControl );
+ }
+ // Kein Control hatte vorher den Focus, oder das Control
+ // befindet sich nicht in der Tab-Steuerung, dann das erste
+ // Control in der TabSteuerung den Focus geben
+ if ( !pFocusControl ||
+ !(pFocusControl->GetStyle() & WB_TABSTOP) ||
+ !pFocusControl->IsVisible() ||
+ !pFocusControl->IsEnabled() || !pFocusControl->IsInputEnabled() )
+ {
+ USHORT n = 0;
+ pFocusControl = ImplGetDlgWindow( n, DLGWINDOW_FIRST );
+ }
+ if ( pFocusControl )
+ pFocusControl->ImplControlFocus( GETFOCUS_INIT );
+}
+
+void Dialog::GetDrawWindowBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
+{
+ ImplBorderWindow aImplWin( (Window*)this, WB_BORDER|WB_STDWORK, BORDERWINDOW_STYLE_OVERLAP );
+// aImplWin.SetText( GetText() );
+// aImplWin.SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
+// aImplWin.SetDisplayActive( TRUE );
+// aImplWin.InitView();
+ aImplWin.GetBorder( rLeftBorder, rTopBorder, rRightBorder, rBottomBorder );
+}
+
+
+void Dialog::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+
+ Wallpaper aWallpaper = GetBackground();
+ if ( !aWallpaper.IsBitmap() )
+ ImplInitSettings();
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetLineColor();
+
+ if ( aWallpaper.IsBitmap() )
+ pDev->DrawBitmapEx( aPos, aSize, aWallpaper.GetBitmap() );
+ else
+ {
+ pDev->SetFillColor( aWallpaper.GetColor() );
+ pDev->DrawRect( Rectangle( aPos, aSize ) );
+ }
+
+ if (!( GetStyle() & WB_NOBORDER ))
+ {
+ ImplBorderWindow aImplWin( this, WB_BORDER|WB_STDWORK, BORDERWINDOW_STYLE_OVERLAP );
+ aImplWin.SetText( GetText() );
+ aImplWin.SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
+ aImplWin.SetDisplayActive( TRUE );
+ aImplWin.InitView();
+
+ aImplWin.Draw( Rectangle( aPos, aSize ), pDev, aPos );
+ }
+
+ pDev->Pop();
+}
+
+
+// =======================================================================
+
+ModelessDialog::ModelessDialog( Window* pParent, WinBits nStyle ) :
+ Dialog( WINDOW_MODELESSDIALOG )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ModelessDialog::ModelessDialog( Window* pParent, const ResId& rResId ) :
+ Dialog( WINDOW_MODELESSDIALOG )
+{
+ rResId.SetRT( RSC_MODELESSDIALOG );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// =======================================================================
+
+ModalDialog::ModalDialog( Window* pParent, WinBits nStyle ) :
+ Dialog( WINDOW_MODALDIALOG )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ModalDialog::ModalDialog( Window* pParent, const ResId& rResId ) :
+ Dialog( WINDOW_MODALDIALOG )
+{
+ rResId.SetRT( RSC_MODALDIALOG );
+ ImplInit( pParent, ImplInitRes( rResId ) );
+ ImplLoadRes( rResId );
+}
diff --git a/vcl/source/window/dlgctrl.cxx b/vcl/source/window/dlgctrl.cxx
new file mode 100644
index 000000000000..64f2b7e0d2a1
--- /dev/null
+++ b/vcl/source/window/dlgctrl.cxx
@@ -0,0 +1,1246 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/tabpage.hxx>
+#include <vcl/tabctrl.hxx>
+#include <vcl/tabdlg.hxx>
+#include <vcl/button.hxx>
+#include <vcl/window.h>
+
+#include <vcl/unohelp.hxx>
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+
+using namespace ::com::sun::star;
+
+// =======================================================================
+
+static BOOL ImplHasIndirectTabParent( Window* pWindow )
+{
+ // The window has inderect tab parent if it is included in tab hierarchy
+ // of the indirect parent window
+
+ return ( pWindow && pWindow->GetParent()
+ && ( pWindow->GetParent()->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL ) );
+}
+
+// -----------------------------------------------------------------------
+
+static Window* ImplGetTopParentOfTabHierarchy( Window* pParent )
+{
+ // The method allows to find the most close parent containing all the
+ // window from the current tab-hierarchy
+ // The direct parent should be provided as a parameter here
+
+ Window* pResult = pParent;
+
+ if ( pResult )
+ {
+ while ( pResult->GetParent() && ( pResult->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL ) )
+ pResult = pResult->GetParent();
+ }
+
+ return pResult;
+}
+
+// -----------------------------------------------------------------------
+
+static Window* ImplGetSubChildWindow( Window* pParent, USHORT n, USHORT& nIndex )
+{
+ Window* pTabPage = NULL;
+ Window* pFoundWindow = NULL;
+
+ Window* pWindow = pParent->GetWindow( WINDOW_FIRSTCHILD );
+ Window* pNextWindow = pWindow;
+ while ( pWindow )
+ {
+ pWindow = pWindow->ImplGetWindow();
+
+ // Unsichtbare und disablte Fenster werden uebersprungen
+ if ( pTabPage || pWindow->IsVisible() )
+ {
+ // Wenn das letzte Control ein TabControl war, wird von
+ // diesem die TabPage genommen
+ if ( pTabPage )
+ {
+ pFoundWindow = ImplGetSubChildWindow( pTabPage, n, nIndex );
+ pTabPage = NULL;
+ }
+ else
+ {
+ pFoundWindow = pWindow;
+
+ // Bei einem TabControl sich die aktuelle TabPage merken,
+ // damit diese dann genommen wird
+ if ( pWindow->GetType() == WINDOW_TABCONTROL )
+ {
+ TabControl* pTabControl = ((TabControl*)pWindow);
+ // Feststellen, ob TabPage Child vom TabControl ist
+ // und auch noch existiert (deshalb durch Vergleich,
+ // indem alle ChildFenster getestet werden). Denn es
+ // kann sein, das TabPages schon in einem Dialog-Dtor
+ // zerstoert wurden, obwohl das TabControl noch
+ // existiert.
+ TabPage* pTempTabPage = pTabControl->GetTabPage( pTabControl->GetCurPageId() );
+ if ( pTempTabPage )
+ {
+ Window* pTempWindow = pTabControl->GetWindow( WINDOW_FIRSTCHILD );
+ while ( pTempWindow )
+ {
+ if ( pTempWindow->ImplGetWindow() == pTempTabPage )
+ {
+ pTabPage = pTempTabPage;
+ break;
+ }
+ pTempWindow = pTempWindow->GetWindow( WINDOW_NEXT );
+ }
+ }
+ }
+ else if ( ( pWindow->GetStyle() & WB_DIALOGCONTROL )
+ || ( pWindow->GetStyle() & WB_CHILDDLGCTRL ) )
+ pFoundWindow = ImplGetSubChildWindow( pWindow, n, nIndex );
+ }
+
+ if ( n == nIndex )
+ return pFoundWindow;
+ nIndex++;
+ }
+
+ if ( pTabPage )
+ pWindow = pTabPage;
+ else
+ {
+ pWindow = pNextWindow->GetWindow( WINDOW_NEXT );
+ pNextWindow = pWindow;
+ }
+ }
+
+ nIndex--;
+ return pFoundWindow;
+}
+
+// -----------------------------------------------------------------------
+
+static Window* ImplGetChildWindow( Window* pParent, USHORT n, USHORT& nIndex, BOOL bTestEnable )
+{
+ pParent = ImplGetTopParentOfTabHierarchy( pParent );
+
+ nIndex = 0;
+ Window* pWindow = ImplGetSubChildWindow( pParent, n, nIndex );
+ if ( bTestEnable )
+ {
+ USHORT n2 = nIndex;
+ while ( pWindow && (!pWindow->IsEnabled() || !pWindow->IsInputEnabled()) )
+ {
+ n2 = nIndex+1;
+ nIndex = 0;
+ pWindow = ImplGetSubChildWindow( pParent, n2, nIndex );
+ if ( nIndex < n2 )
+ break;
+ }
+
+ if ( (nIndex < n2) && n )
+ {
+ do
+ {
+ n--;
+ nIndex = 0;
+ pWindow = ImplGetSubChildWindow( pParent, n, nIndex );
+ }
+ while ( pWindow && n && (!pWindow->IsEnabled() || !pWindow->IsInputEnabled()) );
+ }
+ }
+ return pWindow;
+}
+
+// -----------------------------------------------------------------------
+
+static Window* ImplGetNextWindow( Window* pParent, USHORT n, USHORT& nIndex, BOOL bTestEnable )
+{
+ Window* pWindow = ImplGetChildWindow( pParent, n+1, nIndex, bTestEnable );
+ if ( n == nIndex )
+ {
+ n = 0;
+ pWindow = ImplGetChildWindow( pParent, n, nIndex, bTestEnable );
+ }
+ return pWindow;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::ImplGetDlgWindow( USHORT nIndex, USHORT nType,
+ USHORT nFormStart, USHORT nFormEnd,
+ USHORT* pIndex )
+{
+ DBG_ASSERT( (nIndex >= nFormStart) && (nIndex <= nFormEnd),
+ "Window::ImplGetDlgWindow() - nIndex not in Form" );
+
+ Window* pWindow = NULL;
+ USHORT i;
+ USHORT nTemp;
+ USHORT nStartIndex;
+
+ if ( nType == DLGWINDOW_PREV )
+ {
+ i = nIndex;
+ do
+ {
+ if ( i > nFormStart )
+ i--;
+ else
+ i = nFormEnd;
+ pWindow = ImplGetChildWindow( this, i, nTemp, TRUE );
+ if ( !pWindow )
+ break;
+ if ( (i == nTemp) && (pWindow->GetStyle() & WB_TABSTOP) )
+ break;
+ }
+ while ( i != nIndex );
+ }
+ else
+ {
+ i = nIndex;
+ pWindow = ImplGetChildWindow( this, i, i, (nType == DLGWINDOW_FIRST) );
+ if ( pWindow )
+ {
+ nStartIndex = i;
+
+ if ( nType == DLGWINDOW_NEXT )
+ {
+ if ( i < nFormEnd )
+ {
+ pWindow = ImplGetNextWindow( this, i, i, TRUE );
+ if ( (i > nFormEnd) || (i < nFormStart) )
+ pWindow = ImplGetChildWindow( this, nFormStart, i, TRUE );
+ }
+ else
+ pWindow = ImplGetChildWindow( this, nFormStart, i, TRUE );
+ }
+
+ if ( i <= nFormEnd )
+ {
+ // 2ten Index mitfuehren, falls alle Controls disablte
+ USHORT nStartIndex2 = i;
+ USHORT nOldIndex = i+1;
+
+ do
+ {
+ if ( pWindow->GetStyle() & WB_TABSTOP )
+ break;
+ if( i == nOldIndex ) // only disabled controls ?
+ {
+ i = nStartIndex2;
+ break;
+ }
+ nOldIndex = i;
+ if ( (i > nFormEnd) || (i < nFormStart) )
+ pWindow = ImplGetChildWindow( this, nFormStart, i, TRUE );
+ else
+ pWindow = ImplGetNextWindow( this, i, i, TRUE );
+ }
+ while ( (i != nStartIndex) && (i != nStartIndex2) );
+
+ if ( (i == nStartIndex2) &&
+ (!(pWindow->GetStyle() & WB_TABSTOP) || !pWindow->IsEnabled()) )
+ i = nStartIndex;
+ }
+ }
+
+ if ( nType == DLGWINDOW_FIRST )
+ {
+ if ( pWindow )
+ {
+ if ( pWindow->GetType() == WINDOW_TABCONTROL )
+ {
+ Window* pNextWindow = ImplGetDlgWindow( i, DLGWINDOW_NEXT );
+ if ( pNextWindow )
+ {
+ if ( pWindow->IsChild( pNextWindow ) )
+ pWindow = pNextWindow;
+ }
+ }
+
+ if ( !(pWindow->GetStyle() & WB_TABSTOP) )
+ pWindow = NULL;
+ }
+ }
+ }
+
+ if ( pIndex )
+ *pIndex = i;
+
+ return pWindow;
+}
+
+// -----------------------------------------------------------------------
+
+static Window* ImplFindDlgCtrlWindow( Window* pParent, Window* pWindow, USHORT& rIndex,
+ USHORT& rFormStart, USHORT& rFormEnd )
+{
+ Window* pSWindow;
+ Window* pSecondWindow = NULL;
+ Window* pTempWindow = NULL;
+ USHORT i;
+ USHORT nSecond_i = 0;
+ USHORT nFormStart = 0;
+ USHORT nSecondFormStart = 0;
+ USHORT nFormEnd;
+
+ // Focus-Fenster in der Child-Liste suchen
+ Window* pFirstChildWindow = pSWindow = ImplGetChildWindow( pParent, 0, i, FALSE );
+
+ if( pWindow == NULL )
+ pWindow = pSWindow;
+
+ while ( pSWindow )
+ {
+ // the DialogControlStart mark is only accepted for the direct children
+ if ( !ImplHasIndirectTabParent( pSWindow )
+ && pSWindow->ImplGetWindow()->IsDialogControlStart() )
+ nFormStart = i;
+
+ // SecondWindow wegen zusammengesetzten Controls wie
+ // ComboBoxen und Feldern
+ if ( pSWindow->ImplIsWindowOrChild( pWindow ) )
+ {
+ pSecondWindow = pSWindow;
+ nSecond_i = i;
+ nSecondFormStart = nFormStart;
+ if ( pSWindow == pWindow )
+ break;
+ }
+
+ pSWindow = ImplGetNextWindow( pParent, i, i, FALSE );
+ if ( !i )
+ pSWindow = NULL;
+ }
+
+ if ( !pSWindow )
+ {
+ // Fenster nicht gefunden, dann koennen wir auch keine
+ // Steuerung uebernehmen
+ if ( !pSecondWindow )
+ return NULL;
+ else
+ {
+ pSWindow = pSecondWindow;
+ i = nSecond_i;
+ nFormStart = nSecondFormStart;
+ }
+ }
+
+ // Start-Daten setzen
+ rIndex = i;
+ rFormStart = nFormStart;
+
+ // Formularende suchen
+ nFormEnd = nFormStart;
+ pTempWindow = pSWindow;
+ sal_Int32 nIteration = 0;
+ do
+ {
+ nFormEnd = i;
+ pTempWindow = ImplGetNextWindow( pParent, i, i, FALSE );
+
+ // the DialogControlStart mark is only accepted for the direct children
+ if ( !i
+ || ( pTempWindow && !ImplHasIndirectTabParent( pTempWindow )
+ && pTempWindow->ImplGetWindow()->IsDialogControlStart() ) )
+ break;
+
+ if ( pTempWindow && pTempWindow == pFirstChildWindow )
+ {
+ // It is possible to go through the begin of hierarchy once
+ // while looking for DialogControlStart mark.
+ // If it happens second time, it looks like an endless loop,
+ // that should be impossible, but just for the case...
+ nIteration++;
+ if ( nIteration >= 2 )
+ {
+ // this is an unexpected scenario
+ DBG_ASSERT( FALSE, "It seems to be an endless loop!" );
+ rFormStart = 0;
+ break;
+ }
+ }
+ }
+ while ( pTempWindow );
+ rFormEnd = nFormEnd;
+
+ return pSWindow;
+}
+
+// -----------------------------------------------------------------------
+
+static Window* ImplFindAccelWindow( Window* pParent, USHORT& rIndex, xub_Unicode cCharCode,
+ USHORT nFormStart, USHORT nFormEnd, BOOL bCheckEnable = TRUE )
+{
+ DBG_ASSERT( (rIndex >= nFormStart) && (rIndex <= nFormEnd),
+ "Window::ImplFindAccelWindow() - rIndex not in Form" );
+
+ xub_Unicode cCompareChar;
+ USHORT nStart = rIndex;
+ USHORT i = rIndex;
+ int bSearch = TRUE;
+ Window* pWindow;
+
+ // MT: Where can we keep the CharClass?!
+ static uno::Reference< i18n::XCharacterClassification > xCharClass;
+ if ( !xCharClass.is() )
+ xCharClass = vcl::unohelper::CreateCharacterClassification();
+
+ const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale();
+ cCharCode = xCharClass->toUpper( String(cCharCode), 0, 1, rLocale )[0];
+
+ if ( i < nFormEnd )
+ pWindow = ImplGetNextWindow( pParent, i, i, TRUE );
+ else
+ pWindow = ImplGetChildWindow( pParent, nFormStart, i, TRUE );
+ while( bSearch && pWindow )
+ {
+ const XubString aStr = pWindow->GetText();
+ USHORT nPos = aStr.Search( '~' );
+ while ( nPos != STRING_NOTFOUND )
+ {
+ cCompareChar = aStr.GetChar( nPos+1 );
+ cCompareChar = xCharClass->toUpper( String(cCompareChar), 0, 1, rLocale )[0];
+ if ( cCompareChar == cCharCode )
+ {
+ // Bei Static-Controls auf das naechste Controlm weiterschalten
+ if ( (pWindow->GetType() == WINDOW_FIXEDTEXT) ||
+ (pWindow->GetType() == WINDOW_FIXEDLINE) ||
+ (pWindow->GetType() == WINDOW_GROUPBOX) )
+ pWindow = pParent->ImplGetDlgWindow( i, DLGWINDOW_NEXT );
+ rIndex = i;
+ return pWindow;
+ }
+ nPos = aStr.Search( '~', nPos+1 );
+ }
+
+ // #i93011# it would have made sense to have this really recursive
+ // right from the start. However this would cause unpredictable side effects now
+ // so instead we have a style bit for some child windows, that want their
+ // children checked for accelerators
+ if( (pWindow->GetStyle() & WB_CHILDDLGCTRL) != 0 )
+ {
+ USHORT nChildIndex;
+ USHORT nChildFormStart;
+ USHORT nChildFormEnd;
+
+ // get form start and end
+ ::ImplFindDlgCtrlWindow( pWindow, NULL,
+ nChildIndex, nChildFormStart, nChildFormEnd );
+ Window* pAccelWin = ImplFindAccelWindow( pWindow, nChildIndex, cCharCode,
+ nChildFormStart, nChildFormEnd,
+ bCheckEnable );
+ if( pAccelWin )
+ return pAccelWin;
+ }
+
+ if ( i == nStart )
+ break;
+
+ if ( i < nFormEnd )
+ {
+ pWindow = ImplGetNextWindow( pParent, i, i, bCheckEnable );
+ if( ! pWindow )
+ pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable );
+ }
+ else
+ pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable );
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplControlFocus( USHORT nFlags )
+{
+ if ( nFlags & GETFOCUS_MNEMONIC )
+ {
+ if ( GetType() == WINDOW_RADIOBUTTON )
+ {
+ if ( !((RadioButton*)this)->IsChecked() )
+ ((RadioButton*)this)->ImplCallClick( TRUE, nFlags );
+ else
+ ImplGrabFocus( nFlags );
+ }
+ else
+ {
+ ImplGrabFocus( nFlags );
+ if ( nFlags & GETFOCUS_UNIQUEMNEMONIC )
+ {
+ if ( GetType() == WINDOW_CHECKBOX )
+ ((CheckBox*)this)->ImplCheck();
+ else if ( mpWindowImpl->mbPushButton )
+ {
+ ((PushButton*)this)->SetPressed( TRUE );
+ ((PushButton*)this)->SetPressed( FALSE );
+ ((PushButton*)this)->Click();
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( GetType() == WINDOW_RADIOBUTTON )
+ {
+ if ( !((RadioButton*)this)->IsChecked() )
+ ((RadioButton*)this)->ImplCallClick( TRUE, nFlags );
+ else
+ ImplGrabFocus( nFlags );
+ }
+ else
+ ImplGrabFocus( nFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplDlgCtrl( const KeyEvent& rKEvt, BOOL bKeyInput )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+ Window* pSWindow;
+ Window* pTempWindow;
+ Window* pButtonWindow;
+ USHORT i;
+ USHORT iButton;
+ USHORT iButtonStart;
+ USHORT iTemp;
+ USHORT nIndex;
+ USHORT nFormStart;
+ USHORT nFormEnd;
+ USHORT nDlgCtrlFlags;
+
+ // Ohne Focus-Window koennen wir auch keine Steuerung uebernehmen
+ Window* pFocusWindow = Application::GetFocusWindow();
+ if ( !pFocusWindow || !ImplIsWindowOrChild( pFocusWindow ) )
+ return FALSE;
+
+ // Focus-Fenster in der Child-Liste suchen
+ pSWindow = ::ImplFindDlgCtrlWindow( this, pFocusWindow,
+ nIndex, nFormStart, nFormEnd );
+ if ( !pSWindow )
+ return FALSE;
+ i = nIndex;
+
+ nDlgCtrlFlags = 0;
+ pTempWindow = pSWindow;
+ do
+ {
+ nDlgCtrlFlags |= pTempWindow->GetDialogControlFlags();
+ if ( pTempWindow == this )
+ break;
+ pTempWindow = pTempWindow->ImplGetParent();
+ }
+ while ( pTempWindow );
+
+ pButtonWindow = NULL;
+
+ if ( nKeyCode == KEY_RETURN )
+ {
+ // Wir suchen zuerst nach einem DefPushButton/CancelButton
+ pButtonWindow = ImplGetChildWindow( this, nFormStart, iButton, TRUE );
+ iButtonStart = iButton;
+ while ( pButtonWindow )
+ {
+ if ( (pButtonWindow->GetStyle() & WB_DEFBUTTON) &&
+ pButtonWindow->mpWindowImpl->mbPushButton )
+ break;
+
+ pButtonWindow = ImplGetNextWindow( this, iButton, iButton, TRUE );
+ if ( (iButton <= iButtonStart) || (iButton > nFormEnd) )
+ pButtonWindow = NULL;
+ }
+
+ if ( bKeyInput && !pButtonWindow && (nDlgCtrlFlags & WINDOW_DLGCTRL_RETURN) )
+ {
+ USHORT nType;
+ USHORT nGetFocusFlags = GETFOCUS_TAB;
+ USHORT nNewIndex;
+ USHORT iStart;
+ if ( aKeyCode.IsShift() )
+ {
+ nType = DLGWINDOW_PREV;
+ nGetFocusFlags |= GETFOCUS_BACKWARD;
+ }
+ else
+ {
+ nType = DLGWINDOW_NEXT;
+ nGetFocusFlags |= GETFOCUS_FORWARD;
+ }
+ iStart = i;
+ pTempWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex );
+ while ( pTempWindow && (pTempWindow != pSWindow) )
+ {
+ if ( !pTempWindow->mpWindowImpl->mbPushButton )
+ {
+ // Around-Flag ermitteln
+ if ( nType == DLGWINDOW_PREV )
+ {
+ if ( nNewIndex > iStart )
+ nGetFocusFlags |= GETFOCUS_AROUND;
+ }
+ else
+ {
+ if ( nNewIndex < iStart )
+ nGetFocusFlags |= GETFOCUS_AROUND;
+ }
+ pTempWindow->ImplControlFocus( nGetFocusFlags );
+ return TRUE;
+ }
+ else
+ {
+ i = nNewIndex;
+ pTempWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex );
+ }
+ if ( (i <= iStart) || (i > nFormEnd) )
+ pTempWindow = NULL;
+ }
+ // Wenn es das gleiche Fenster ist, ein Get/LoseFocus
+ // simulieren, falls AROUND ausgewertet wird
+ if ( pTempWindow && (pTempWindow == pSWindow) )
+ {
+ NotifyEvent aNEvt1( EVENT_LOSEFOCUS, pSWindow );
+ if ( !ImplCallPreNotify( aNEvt1 ) )
+ pSWindow->LoseFocus();
+ pSWindow->mpWindowImpl->mnGetFocusFlags = nGetFocusFlags | GETFOCUS_AROUND;
+ NotifyEvent aNEvt2( EVENT_GETFOCUS, pSWindow );
+ if ( !ImplCallPreNotify( aNEvt2 ) )
+ pSWindow->GetFocus();
+ pSWindow->mpWindowImpl->mnGetFocusFlags = 0;
+ return TRUE;
+ }
+ }
+ }
+ else if ( nKeyCode == KEY_ESCAPE )
+ {
+ // Wir suchen zuerst nach einem DefPushButton/CancelButton
+ pButtonWindow = ImplGetChildWindow( this, nFormStart, iButton, TRUE );
+ iButtonStart = iButton;
+ while ( pButtonWindow )
+ {
+ if ( pButtonWindow->GetType() == WINDOW_CANCELBUTTON )
+ break;
+
+ pButtonWindow = ImplGetNextWindow( this, iButton, iButton, TRUE );
+ if ( (iButton <= iButtonStart) || (iButton > nFormEnd) )
+ pButtonWindow = NULL;
+ }
+
+ if ( bKeyInput && mpWindowImpl->mpDlgCtrlDownWindow )
+ {
+ if ( mpWindowImpl->mpDlgCtrlDownWindow != pButtonWindow )
+ {
+ ((PushButton*)mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( FALSE );
+ mpWindowImpl->mpDlgCtrlDownWindow = NULL;
+ return TRUE;
+ }
+ }
+ }
+ else if ( bKeyInput )
+ {
+ if ( nKeyCode == KEY_TAB )
+ {
+ // keine Alt-Taste abfangen, wegen Windows
+ if ( !aKeyCode.IsMod2() )
+ {
+ USHORT nType;
+ USHORT nGetFocusFlags = GETFOCUS_TAB;
+ USHORT nNewIndex;
+ BOOL bFormular = FALSE;
+
+ // Bei Ctrl-Tab erstmal testen, ob zwischen Formularen
+ // gesprungen werden soll
+ if ( aKeyCode.IsMod1() )
+ {
+ // Gruppe suchen
+ Window* pFormularFirstWindow = NULL;
+ Window* pLastFormularFirstWindow = NULL;
+ pTempWindow = ImplGetChildWindow( this, 0, iTemp, FALSE );
+ Window* pPrevFirstFormularFirstWindow = NULL;
+ Window* pFirstFormularFirstWindow = pTempWindow;
+ while ( pTempWindow )
+ {
+ if ( pTempWindow->ImplGetWindow()->IsDialogControlStart() )
+ {
+ if ( iTemp != 0 )
+ bFormular = TRUE;
+ if ( aKeyCode.IsShift() )
+ {
+ if ( iTemp <= nIndex )
+ pFormularFirstWindow = pPrevFirstFormularFirstWindow;
+ pPrevFirstFormularFirstWindow = pTempWindow;
+ }
+ else
+ {
+ if ( (iTemp > nIndex) && !pFormularFirstWindow )
+ pFormularFirstWindow = pTempWindow;
+ }
+ pLastFormularFirstWindow = pTempWindow;
+ }
+
+ pTempWindow = ImplGetNextWindow( this, iTemp, iTemp, FALSE );
+ if ( !iTemp )
+ pTempWindow = NULL;
+ }
+
+ if ( bFormular )
+ {
+ if ( !pFormularFirstWindow )
+ {
+ if ( aKeyCode.IsShift() )
+ pFormularFirstWindow = pLastFormularFirstWindow;
+ else
+ pFormularFirstWindow = pFirstFormularFirstWindow;
+ }
+
+ USHORT nFoundFormStart = 0;
+ USHORT nFoundFormEnd = 0;
+ USHORT nTempIndex = 0;
+ if ( ::ImplFindDlgCtrlWindow( this, pFormularFirstWindow, nTempIndex,
+ nFoundFormStart, nFoundFormEnd ) )
+ {
+ nTempIndex = nFoundFormStart;
+ pFormularFirstWindow = ImplGetDlgWindow( nTempIndex, DLGWINDOW_FIRST, nFoundFormStart, nFoundFormEnd );
+ if ( pFormularFirstWindow )
+ {
+ pFormularFirstWindow->ImplControlFocus();
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ if ( !bFormular )
+ {
+ // Only use Ctrl-TAB if it was allowed for the whole
+ // dialog or for the current control (#103667#)
+ if ( !aKeyCode.IsMod1() || (nDlgCtrlFlags & WINDOW_DLGCTRL_MOD1TAB) ||
+ ( pSWindow->GetStyle() & WINDOW_DLGCTRL_MOD1TAB) )
+ {
+ if ( aKeyCode.IsShift() )
+ {
+ nType = DLGWINDOW_PREV;
+ nGetFocusFlags |= GETFOCUS_BACKWARD;
+ }
+ else
+ {
+ nType = DLGWINDOW_NEXT;
+ nGetFocusFlags |= GETFOCUS_FORWARD;
+ }
+ Window* pWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex );
+ // Wenn es das gleiche Fenster ist, ein Get/LoseFocus
+ // simulieren, falls AROUND ausgewertet wird
+ if ( pWindow == pSWindow )
+ {
+ NotifyEvent aNEvt1( EVENT_LOSEFOCUS, pSWindow );
+ if ( !ImplCallPreNotify( aNEvt1 ) )
+ pSWindow->LoseFocus();
+ pSWindow->mpWindowImpl->mnGetFocusFlags = nGetFocusFlags | GETFOCUS_AROUND;
+ NotifyEvent aNEvt2( EVENT_GETFOCUS, pSWindow );
+ if ( !ImplCallPreNotify( aNEvt2 ) )
+ pSWindow->GetFocus();
+ pSWindow->mpWindowImpl->mnGetFocusFlags = 0;
+ return TRUE;
+ }
+ else if ( pWindow )
+ {
+ // Around-Flag ermitteln
+ if ( nType == DLGWINDOW_PREV )
+ {
+ if ( nNewIndex > i )
+ nGetFocusFlags |= GETFOCUS_AROUND;
+ }
+ else
+ {
+ if ( nNewIndex < i )
+ nGetFocusFlags |= GETFOCUS_AROUND;
+ }
+ pWindow->ImplControlFocus( nGetFocusFlags );
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ else if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_UP) )
+ {
+ Window* pWindow = pSWindow;
+ WinBits nStyle = pSWindow->GetStyle();
+ if ( !(nStyle & WB_GROUP) )
+ {
+ pWindow = pWindow->GetWindow( WINDOW_PREV );
+ while ( pWindow )
+ {
+ pWindow = pWindow->ImplGetWindow();
+
+ nStyle = pWindow->GetStyle();
+
+ if ( pWindow->IsVisible() && pWindow->IsEnabled() && pWindow->IsInputEnabled() )
+ {
+ if ( pWindow != pSWindow )
+ pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_BACKWARD );
+ return TRUE;
+ }
+
+ if ( nStyle & WB_GROUP )
+ break;
+
+ pWindow = pWindow->GetWindow( WINDOW_PREV );
+ }
+ }
+ }
+ else if ( (nKeyCode == KEY_RIGHT) || (nKeyCode == KEY_DOWN) )
+ {
+ Window* pWindow;
+ WinBits nStyle;
+ pWindow = pSWindow->GetWindow( WINDOW_NEXT );
+ while ( pWindow )
+ {
+ pWindow = pWindow->ImplGetWindow();
+
+ nStyle = pWindow->GetStyle();
+
+ if ( nStyle & WB_GROUP )
+ break;
+
+ if ( pWindow->IsVisible() && pWindow->IsEnabled() && pWindow->IsInputEnabled() )
+ {
+ pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_BACKWARD );
+ return TRUE;
+ }
+
+ pWindow = pWindow->GetWindow( WINDOW_NEXT );
+ }
+ }
+ else
+ {
+ xub_Unicode c = rKEvt.GetCharCode();
+ if ( c )
+ {
+ pSWindow = ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd );
+ if ( pSWindow )
+ {
+ USHORT nGetFocusFlags = GETFOCUS_MNEMONIC;
+ if ( pSWindow == ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd ) )
+ nGetFocusFlags |= GETFOCUS_UNIQUEMNEMONIC;
+ pSWindow->ImplControlFocus( nGetFocusFlags );
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ if ( pButtonWindow && pButtonWindow->IsVisible() && pButtonWindow->IsEnabled() && pButtonWindow->IsInputEnabled() )
+ {
+ if ( bKeyInput )
+ {
+ if ( mpWindowImpl->mpDlgCtrlDownWindow && (mpWindowImpl->mpDlgCtrlDownWindow != pButtonWindow) )
+ {
+ ((PushButton*)mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( FALSE );
+ mpWindowImpl->mpDlgCtrlDownWindow = NULL;
+ }
+
+ ((PushButton*)pButtonWindow)->SetPressed( TRUE );
+ mpWindowImpl->mpDlgCtrlDownWindow = pButtonWindow;
+ }
+ else if ( mpWindowImpl->mpDlgCtrlDownWindow == pButtonWindow )
+ {
+ mpWindowImpl->mpDlgCtrlDownWindow = NULL;
+ ((PushButton*)pButtonWindow)->SetPressed( FALSE );
+ ((PushButton*)pButtonWindow)->Click();
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+// checks if this window has dialog control
+BOOL Window::ImplHasDlgCtrl()
+{
+ Window* pDlgCtrlParent;
+ Window* pDlgCtrl;
+
+ // lookup window for dialog control
+ pDlgCtrl = this;
+ pDlgCtrlParent = ImplGetParent();
+ while ( pDlgCtrlParent &&
+ !pDlgCtrlParent->ImplIsOverlapWindow() &&
+ ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
+ pDlgCtrlParent = pDlgCtrlParent->ImplGetParent();
+
+ if ( !pDlgCtrlParent || ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
+ return FALSE;
+ else
+ return TRUE;
+}
+
+void Window::ImplDlgCtrlNextWindow()
+{
+ Window* pDlgCtrlParent;
+ Window* pDlgCtrl;
+ Window* pSWindow;
+ USHORT nIndex;
+ USHORT nFormStart;
+ USHORT nFormEnd;
+
+ // lookup window for dialog control
+ pDlgCtrl = this;
+ pDlgCtrlParent = ImplGetParent();
+ while ( pDlgCtrlParent &&
+ !pDlgCtrlParent->ImplIsOverlapWindow() &&
+ ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
+ pDlgCtrlParent = pDlgCtrlParent->ImplGetParent();
+
+if ( !pDlgCtrlParent || (GetStyle() & WB_NODIALOGCONTROL) || ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
+ return;
+
+ // lookup window in child list
+ pSWindow = ::ImplFindDlgCtrlWindow( pDlgCtrlParent, pDlgCtrl,
+ nIndex, nFormStart, nFormEnd );
+ if ( !pSWindow )
+ return;
+
+ Window* pWindow = pDlgCtrlParent->ImplGetDlgWindow( nIndex, DLGWINDOW_NEXT, nFormStart, nFormEnd );
+ if ( pWindow && (pWindow != pSWindow) )
+ pWindow->ImplControlFocus();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDlgCtrlUpdateDefButton( Window* pParent, Window* pFocusWindow,
+ BOOL bGetFocus )
+{
+ PushButton* pOldDefButton = NULL;
+ PushButton* pNewDefButton = NULL;
+ Window* pSWindow;
+ USHORT i;
+ USHORT nFormStart;
+ USHORT nFormEnd;
+
+ // Formular suchen
+ pSWindow = ::ImplFindDlgCtrlWindow( pParent, pFocusWindow, i, nFormStart, nFormEnd );
+ if ( !pSWindow )
+ {
+ nFormStart = 0;
+ nFormEnd = 0xFFFF;
+ }
+
+ pSWindow = ImplGetChildWindow( pParent, nFormStart, i, FALSE );
+ while ( pSWindow )
+ {
+ if ( pSWindow->ImplIsPushButton() )
+ {
+ PushButton* pPushButton = (PushButton*)pSWindow;
+ if ( pPushButton->ImplIsDefButton() )
+ pOldDefButton = pPushButton;
+ if ( pPushButton->HasChildPathFocus() )
+ pNewDefButton = pPushButton;
+ else if ( !pNewDefButton && (pPushButton->GetStyle() & WB_DEFBUTTON) )
+ pNewDefButton = pPushButton;
+ }
+
+ pSWindow = ImplGetNextWindow( pParent, i, i, FALSE );
+ if ( !i || (i > nFormEnd) )
+ pSWindow = NULL;
+ }
+
+ if ( !bGetFocus )
+ {
+ USHORT nDummy;
+ Window* pNewFocusWindow = Application::GetFocusWindow();
+ if ( !pNewFocusWindow || !pParent->ImplIsWindowOrChild( pNewFocusWindow ) )
+ pNewDefButton = NULL;
+ else if ( !::ImplFindDlgCtrlWindow( pParent, pNewFocusWindow, i, nDummy, nDummy ) ||
+ (i < nFormStart) || (i > nFormEnd) )
+ pNewDefButton = NULL;
+ }
+
+ if ( pOldDefButton != pNewDefButton )
+ {
+ if ( pOldDefButton )
+ pOldDefButton->ImplSetDefButton( FALSE );
+ if ( pNewDefButton )
+ pNewDefButton->ImplSetDefButton( TRUE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplDlgCtrlFocusChanged( Window* pWindow, BOOL bGetFocus )
+{
+ if ( mpWindowImpl->mpDlgCtrlDownWindow && !bGetFocus )
+ {
+ ((PushButton*)mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( FALSE );
+ mpWindowImpl->mpDlgCtrlDownWindow = NULL;
+ }
+
+ ImplDlgCtrlUpdateDefButton( this, pWindow, bGetFocus );
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::ImplFindDlgCtrlWindow( Window* pWindow )
+{
+ USHORT nIndex;
+ USHORT nFormStart;
+ USHORT nFormEnd;
+
+ // Focus-Fenster in der Child-Liste suchen und zurueckgeben
+ return ::ImplFindDlgCtrlWindow( this, pWindow, nIndex, nFormStart, nFormEnd );
+}
+
+
+// -----------------------------------------------------------------------
+
+Window* Window::GetParentLabelFor( const Window* ) const
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::GetParentLabeledBy( const Window* ) const
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Unicode getAccel( const String& rStr )
+{
+ sal_Unicode nChar = 0;
+ USHORT nPos = 0;
+ do
+ {
+ nPos = rStr.Search( '~', nPos );
+ if( nPos != STRING_NOTFOUND && nPos < rStr.Len() )
+ nChar = rStr.GetChar( ++nPos );
+ else
+ nChar = 0;
+ } while( nChar == '~' );
+ return nChar;
+}
+
+Window* Window::GetLabelFor() const
+{
+ if ( mpWindowImpl->mbDisableAccessibleLabelForRelation )
+ return NULL;
+
+ Window* pWindow = NULL;
+ Window* pFrameWindow = ImplGetFrameWindow();
+
+ WinBits nFrameStyle = pFrameWindow->GetStyle();
+ if( ! ( nFrameStyle & WB_DIALOGCONTROL )
+ || ( nFrameStyle & WB_NODIALOGCONTROL )
+ )
+ return NULL;
+
+ if ( mpWindowImpl->mpRealParent )
+ pWindow = mpWindowImpl->mpRealParent->GetParentLabelFor( this );
+
+ if( pWindow )
+ return pWindow;
+
+ sal_Unicode nAccel = getAccel( GetText() );
+
+ WindowType nMyType = GetType();
+ if( nMyType == WINDOW_FIXEDTEXT ||
+ nMyType == WINDOW_FIXEDLINE ||
+ nMyType == WINDOW_GROUPBOX )
+ {
+ // #i100833# MT 2010/02: Group box and fixed lines can also lable a fixed text.
+ // See tools/options/print for example.
+ BOOL bThisIsAGroupControl = (nMyType == WINDOW_GROUPBOX) || (nMyType == WINDOW_FIXEDLINE);
+ Window* pSWindow = NULL;
+ // get index, form start and form end
+ USHORT nIndex=0, nFormStart=0, nFormEnd=0;
+ pSWindow = ::ImplFindDlgCtrlWindow( pFrameWindow,
+ const_cast<Window*>(this),
+ nIndex,
+ nFormStart,
+ nFormEnd );
+ if( nAccel )
+ {
+ // find the accelerated window
+ pWindow = ::ImplFindAccelWindow( pFrameWindow,
+ nIndex,
+ nAccel,
+ nFormStart,
+ nFormEnd,
+ FALSE );
+ }
+ else
+ {
+ // find the next control; if that is a fixed text
+ // fixed line or group box, then return NULL
+ while( nIndex < nFormEnd )
+ {
+ nIndex++;
+ pSWindow = ::ImplGetChildWindow( pFrameWindow,
+ nIndex,
+ nIndex,
+ FALSE );
+ if( pSWindow && pSWindow->IsVisible() && ! (pSWindow->GetStyle() & WB_NOLABEL) )
+ {
+ WindowType nType = pSWindow->GetType();
+ if( nType != WINDOW_FIXEDTEXT &&
+ nType != WINDOW_FIXEDLINE &&
+ nType != WINDOW_GROUPBOX )
+ {
+ pWindow = pSWindow;
+ }
+ else if( bThisIsAGroupControl && ( nType == WINDOW_FIXEDTEXT ) )
+ {
+ pWindow = pSWindow;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return pWindow;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::GetLabeledBy() const
+{
+ if ( mpWindowImpl->mbDisableAccessibleLabeledByRelation )
+ return NULL;
+
+ Window* pWindow = NULL;
+ Window* pFrameWindow = ImplGetFrameWindow();
+
+ if ( mpWindowImpl->mpRealParent )
+ pWindow = mpWindowImpl->mpRealParent->GetParentLabeledBy( this );
+
+ if( pWindow )
+ return pWindow;
+
+ // #i62723#, #104191# checkboxes and radiobuttons are not supposed to have labels
+ if( GetType() == WINDOW_CHECKBOX || GetType() == WINDOW_RADIOBUTTON )
+ return NULL;
+
+// if( ! ( GetType() == WINDOW_FIXEDTEXT ||
+// GetType() == WINDOW_FIXEDLINE ||
+// GetType() == WINDOW_GROUPBOX ) )
+ // #i100833# MT 2010/02: Group box and fixed lines can also lable a fixed text.
+ // See tools/options/print for example.
+ WindowType nMyType = GetType();
+ if ( (nMyType != WINDOW_GROUPBOX) && (nMyType != WINDOW_FIXEDLINE) )
+ {
+ // search for a control that labels this window
+ // a label is considered the last fixed text, fixed line or group box
+ // that comes before this control; with the exception of push buttons
+ // which are labeled only if the fixed text, fixed line or group box
+ // is directly before the control
+
+ // get form start and form end and index of this control
+ USHORT nIndex, nFormStart, nFormEnd;
+ Window* pSWindow = ::ImplFindDlgCtrlWindow( pFrameWindow,
+ const_cast<Window*>(this),
+ nIndex,
+ nFormStart,
+ nFormEnd );
+ if( pSWindow && nIndex != nFormStart )
+ {
+ if( GetType() == WINDOW_PUSHBUTTON ||
+ GetType() == WINDOW_HELPBUTTON ||
+ GetType() == WINDOW_OKBUTTON ||
+ GetType() == WINDOW_CANCELBUTTON )
+ {
+ nFormStart = nIndex-1;
+ }
+ for( USHORT nSearchIndex = nIndex-1; nSearchIndex >= nFormStart; nSearchIndex-- )
+ {
+ USHORT nFoundIndex = 0;
+ pSWindow = ::ImplGetChildWindow( pFrameWindow,
+ nSearchIndex,
+ nFoundIndex,
+ FALSE );
+ if( pSWindow && pSWindow->IsVisible() && !(pSWindow->GetStyle() & WB_NOLABEL) )
+ {
+ WindowType nType = pSWindow->GetType();
+ if ( ( nType == WINDOW_FIXEDTEXT ||
+ nType == WINDOW_FIXEDLINE ||
+ nType == WINDOW_GROUPBOX ) )
+ {
+ // a fixed text can't be labeld by a fixed text.
+ if ( ( nMyType != WINDOW_FIXEDTEXT ) || ( nType != WINDOW_FIXEDTEXT ) )
+ pWindow = pSWindow;
+ break;
+ }
+ }
+ if( nFoundIndex > nSearchIndex || nSearchIndex == 0 )
+ break;
+ }
+ }
+ }
+ return pWindow;
+}
+
+// -----------------------------------------------------------------------
+
+KeyEvent Window::GetActivationKey() const
+{
+ KeyEvent aKeyEvent;
+
+ sal_Unicode nAccel = getAccel( GetText() );
+ if( ! nAccel )
+ {
+ Window* pWindow = GetLabeledBy();
+ if( pWindow )
+ nAccel = getAccel( pWindow->GetText() );
+ }
+ if( nAccel )
+ {
+ USHORT nCode = 0;
+ if( nAccel >= 'a' && nAccel <= 'z' )
+ nCode = KEY_A + (nAccel-'a');
+ else if( nAccel >= 'A' && nAccel <= 'Z' )
+ nCode = KEY_A + (nAccel-'A');
+ else if( nAccel >= '0' && nAccel <= '9' )
+ nCode = KEY_0 + (nAccel-'0');
+ KeyCode aKeyCode( nCode, FALSE, FALSE, TRUE, FALSE );
+ aKeyEvent = KeyEvent( nAccel, aKeyCode );
+ }
+ return aKeyEvent;
+}
diff --git a/vcl/source/window/dndevdis.cxx b/vcl/source/window/dndevdis.cxx
new file mode 100644
index 000000000000..e4d5a8c4c0eb
--- /dev/null
+++ b/vcl/source/window/dndevdis.cxx
@@ -0,0 +1,564 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/dndevdis.hxx>
+#include <vcl/dndlcon.hxx>
+#include <vcl/window.h>
+
+#include <vos/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/svdata.hxx>
+using namespace ::osl;
+using namespace ::vos;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::dnd;
+
+//==================================================================================================
+// DNDEventDispatcher::DNDEventDispatcher
+//==================================================================================================
+
+DNDEventDispatcher::DNDEventDispatcher( Window * pTopWindow ):
+ m_pTopWindow( pTopWindow ),
+ m_pCurrentWindow( NULL )
+{
+}
+
+//==================================================================================================
+// DNDEventDispatcher::~DNDEventDispatcher
+//==================================================================================================
+
+DNDEventDispatcher::~DNDEventDispatcher()
+{
+}
+
+//==================================================================================================
+// DNDEventDispatcher::drop
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::drop( const DropTargetDropEvent& dtde )
+ throw(RuntimeException)
+{
+ MutexGuard aImplGuard( m_aMutex );
+
+ Point location( dtde.LocationX, dtde.LocationY );
+
+ // find the window that is toplevel for this coordinates
+ OClearableGuard aSolarGuard( Application::GetSolarMutex() );
+
+ // because those coordinates come from outside, they must be mirrored if RTL layout is active
+ if( Application::GetSettings().GetLayoutRTL() )
+ m_pTopWindow->ImplMirrorFramePos( location );
+ Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
+
+ if( NULL == pChildWindow )
+ pChildWindow = m_pTopWindow;
+
+ while( pChildWindow->ImplGetClientWindow() )
+ pChildWindow = pChildWindow->ImplGetClientWindow();
+
+ if( pChildWindow->ImplIsAntiparallel() )
+ pChildWindow->ImplReMirror( location );
+
+ aSolarGuard.clear();
+
+ // handle the case that drop is in an other vcl window than the last dragOver
+ if( pChildWindow != m_pCurrentWindow )
+ {
+ // fire dragExit on listeners of previous window
+ fireDragExitEvent( m_pCurrentWindow );
+
+ fireDragEnterEvent( pChildWindow, static_cast < XDropTargetDragContext * > (this),
+ dtde.DropAction, location, dtde.SourceActions, m_aDataFlavorList );
+ }
+
+ sal_Int32 nListeners = 0;
+
+ // send drop event to the child window
+ nListeners = fireDropEvent( pChildWindow, dtde.Context, dtde.DropAction,
+ location, dtde.SourceActions, dtde.Transferable );
+
+ // reject drop if no listeners found
+ if( nListeners == 0 ) {
+ OSL_TRACE( "rejecting drop due to missing listeners." );
+ dtde.Context->rejectDrop();
+ }
+
+ // this is a drop -> no further drag overs
+ m_pCurrentWindow = NULL;
+ m_aDataFlavorList.realloc( 0 );
+}
+
+//==================================================================================================
+// DNDEventDispatcher::dragEnter
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent& dtdee )
+ throw(RuntimeException)
+{
+ MutexGuard aImplGuard( m_aMutex );
+ Point location( dtdee.LocationX, dtdee.LocationY );
+
+ // find the window that is toplevel for this coordinates
+ OClearableGuard aSolarGuard( Application::GetSolarMutex() );
+
+ // because those coordinates come from outside, they must be mirrored if RTL layout is active
+ if( Application::GetSettings().GetLayoutRTL() )
+ m_pTopWindow->ImplMirrorFramePos( location );
+ Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
+
+ if( NULL == pChildWindow )
+ pChildWindow = m_pTopWindow;
+
+ while( pChildWindow->ImplGetClientWindow() )
+ pChildWindow = pChildWindow->ImplGetClientWindow();
+
+ if( pChildWindow->ImplIsAntiparallel() )
+ pChildWindow->ImplReMirror( location );
+
+ aSolarGuard.clear();
+
+ // assume pointer write operation to be atomic
+ m_pCurrentWindow = pChildWindow;
+ m_aDataFlavorList = dtdee.SupportedDataFlavors;
+
+ // fire dragEnter on listeners of current window
+ sal_Int32 nListeners = fireDragEnterEvent( pChildWindow, dtdee.Context, dtdee.DropAction, location,
+ dtdee.SourceActions, dtdee.SupportedDataFlavors );
+
+ // reject drag if no listener found
+ if( nListeners == 0 ) {
+ OSL_TRACE( "rejecting drag enter due to missing listeners." );
+ dtdee.Context->rejectDrag();
+ }
+
+}
+
+//==================================================================================================
+// DNDEventDispatcher::dragExit
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::dragExit( const DropTargetEvent& /*dte*/ )
+ throw(RuntimeException)
+{
+ MutexGuard aImplGuard( m_aMutex );
+
+ fireDragExitEvent( m_pCurrentWindow );
+
+ // reset member values
+ m_pCurrentWindow = NULL;
+ m_aDataFlavorList.realloc( 0 );
+}
+
+//==================================================================================================
+// DNDEventDispatcher::dragOver
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::dragOver( const DropTargetDragEvent& dtde )
+ throw(RuntimeException)
+{
+ MutexGuard aImplGuard( m_aMutex );
+
+ Point location( dtde.LocationX, dtde.LocationY );
+ sal_Int32 nListeners;
+
+ // find the window that is toplevel for this coordinates
+ OClearableGuard aSolarGuard( Application::GetSolarMutex() );
+
+ // because those coordinates come from outside, they must be mirrored if RTL layout is active
+ if( Application::GetSettings().GetLayoutRTL() )
+ m_pTopWindow->ImplMirrorFramePos( location );
+ Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
+
+ if( NULL == pChildWindow )
+ pChildWindow = m_pTopWindow;
+
+ while( pChildWindow->ImplGetClientWindow() )
+ pChildWindow = pChildWindow->ImplGetClientWindow();
+
+ if( pChildWindow->ImplIsAntiparallel() )
+ pChildWindow->ImplReMirror( location );
+
+ aSolarGuard.clear();
+
+ if( pChildWindow != m_pCurrentWindow )
+ {
+ // fire dragExit on listeners of previous window
+ fireDragExitEvent( m_pCurrentWindow );
+
+ // remember new window
+ m_pCurrentWindow = pChildWindow;
+
+ // fire dragEnter on listeners of current window
+ nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
+ dtde.SourceActions, m_aDataFlavorList );
+ }
+ else
+ {
+ // fire dragOver on listeners of current window
+ nListeners = fireDragOverEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
+ dtde.SourceActions );
+ }
+
+ // reject drag if no listener found
+ if( nListeners == 0 )
+ {
+ OSL_TRACE( "rejecting drag over due to missing listeners." );
+ dtde.Context->rejectDrag();
+ }
+}
+
+//==================================================================================================
+// DNDEventDispatcher::dropActionChanged
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent& dtde )
+ throw(RuntimeException)
+{
+ MutexGuard aImplGuard( m_aMutex );
+
+ Point location( dtde.LocationX, dtde.LocationY );
+ sal_Int32 nListeners;
+
+ // find the window that is toplevel for this coordinates
+ OClearableGuard aSolarGuard( Application::GetSolarMutex() );
+
+ // because those coordinates come from outside, they must be mirrored if RTL layout is active
+ if( Application::GetSettings().GetLayoutRTL() )
+ m_pTopWindow->ImplMirrorFramePos( location );
+ Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
+
+ if( NULL == pChildWindow )
+ pChildWindow = m_pTopWindow;
+
+ while( pChildWindow->ImplGetClientWindow() )
+ pChildWindow = pChildWindow->ImplGetClientWindow();
+
+ if( pChildWindow->ImplIsAntiparallel() )
+ pChildWindow->ImplReMirror( location );
+
+ aSolarGuard.clear();
+
+ if( pChildWindow != m_pCurrentWindow )
+ {
+ // fire dragExit on listeners of previous window
+ fireDragExitEvent( m_pCurrentWindow );
+
+ // remember new window
+ m_pCurrentWindow = pChildWindow;
+
+ // fire dragEnter on listeners of current window
+ nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
+ dtde.SourceActions, m_aDataFlavorList );
+ }
+ else
+ {
+ // fire dropActionChanged on listeners of current window
+ nListeners = fireDropActionChangedEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
+ dtde.SourceActions );
+ }
+
+ // reject drag if no listener found
+ if( nListeners == 0 )
+ {
+ OSL_TRACE( "rejecting dropActionChanged due to missing listeners." );
+ dtde.Context->rejectDrag();
+ }
+}
+
+
+//==================================================================================================
+// DNDEventDispatcher::dragGestureRecognized
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent& dge )
+ throw(RuntimeException)
+{ MutexGuard aImplGuard( m_aMutex );
+
+ Point origin( dge.DragOriginX, dge.DragOriginY );
+
+ // find the window that is toplevel for this coordinates
+ OClearableGuard aSolarGuard( Application::GetSolarMutex() );
+
+ // because those coordinates come from outside, they must be mirrored if RTL layout is active
+ if( Application::GetSettings().GetLayoutRTL() )
+ m_pTopWindow->ImplMirrorFramePos( origin );
+ Window * pChildWindow = m_pTopWindow->ImplFindWindow( origin );
+
+ if( NULL == pChildWindow )
+ pChildWindow = m_pTopWindow;
+
+ while( pChildWindow->ImplGetClientWindow() )
+ pChildWindow = pChildWindow->ImplGetClientWindow();
+
+ if( pChildWindow->ImplIsAntiparallel() )
+ pChildWindow->ImplReMirror( origin );
+
+ aSolarGuard.clear();
+
+ fireDragGestureEvent( pChildWindow, dge.DragSource, dge.Event, origin, dge.DragAction );
+}
+
+//==================================================================================================
+// DNDEventDispatcher::disposing
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::disposing( const EventObject& )
+ throw(RuntimeException)
+{
+}
+
+//==================================================================================================
+// DNDEventDispatcher::acceptDrag
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ ) throw(RuntimeException)
+{
+}
+
+//==================================================================================================
+// DNDEventDispatcher::rejectDrag
+//==================================================================================================
+
+void SAL_CALL DNDEventDispatcher::rejectDrag() throw(RuntimeException)
+{
+}
+
+//==================================================================================================
+// DNDEventDispatcher::fireDragEnterEvent
+//==================================================================================================
+
+sal_Int32 DNDEventDispatcher::fireDragEnterEvent( Window *pWindow,
+ const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
+ const Point& rLocation, const sal_Int8 nSourceActions, const Sequence< DataFlavor >& aFlavorList
+)
+ throw(RuntimeException)
+{
+ sal_Int32 n = 0;
+
+ if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
+ {
+ OClearableGuard aGuard( Application::GetSolarMutex() );
+
+ // set an UI lock
+ pWindow->IncrementLockCount();
+
+ // query DropTarget from window
+ Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
+
+ if( xDropTarget.is() )
+ {
+ // retrieve relative mouse position
+ Point relLoc = pWindow->ImplFrameToOutput( rLocation );
+ aGuard.clear();
+
+ n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragEnterEvent(
+ xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, aFlavorList );
+ }
+ }
+
+ return n;
+}
+
+//==================================================================================================
+// DNDEventDispatcher::fireDragOverEvent
+//==================================================================================================
+
+sal_Int32 DNDEventDispatcher::fireDragOverEvent( Window *pWindow,
+ const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
+ const Point& rLocation, const sal_Int8 nSourceActions
+)
+ throw(RuntimeException)
+{
+ sal_Int32 n = 0;
+
+ if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
+ {
+ OClearableGuard aGuard( Application::GetSolarMutex() );
+
+ // query DropTarget from window
+ Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
+
+ if( xDropTarget.is() )
+ {
+ // retrieve relative mouse position
+ Point relLoc = pWindow->ImplFrameToOutput( rLocation );
+ aGuard.clear();
+
+ n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragOverEvent(
+ xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
+ }
+ }
+
+ return n;
+}
+
+//==================================================================================================
+// DNDEventDispatcher::fireDragExitEvent
+//==================================================================================================
+
+sal_Int32 DNDEventDispatcher::fireDragExitEvent( Window *pWindow ) throw(RuntimeException)
+{
+ sal_Int32 n = 0;
+
+ if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
+ {
+ OClearableGuard aGuard( Application::GetSolarMutex() );
+
+ // query DropTarget from window
+ Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
+
+ aGuard.clear();
+
+ if( xDropTarget.is() )
+ n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragExitEvent();
+
+ // release UI lock
+ pWindow->DecrementLockCount();
+ }
+
+ return n;
+}
+
+//==================================================================================================
+// DNDEventDispatcher::fireDropActionChangedEvent
+//==================================================================================================
+
+sal_Int32 DNDEventDispatcher::fireDropActionChangedEvent( Window *pWindow,
+ const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
+ const Point& rLocation, const sal_Int8 nSourceActions
+)
+ throw(RuntimeException)
+{
+ sal_Int32 n = 0;
+
+ if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
+ {
+ OClearableGuard aGuard( Application::GetSolarMutex() );
+
+ // query DropTarget from window
+ Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
+
+ if( xDropTarget.is() )
+ {
+ // retrieve relative mouse position
+ Point relLoc = pWindow->ImplFrameToOutput( rLocation );
+ aGuard.clear();
+
+ n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropActionChangedEvent(
+ xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
+ }
+ }
+
+ return n;
+}
+
+//==================================================================================================
+// DNDEventDispatcher::fireDropEvent
+//==================================================================================================
+
+sal_Int32 DNDEventDispatcher::fireDropEvent( Window *pWindow,
+ const Reference< XDropTargetDropContext >& xContext, const sal_Int8 nDropAction, const Point& rLocation,
+ const sal_Int8 nSourceActions, const Reference< XTransferable >& xTransferable
+)
+ throw(RuntimeException)
+{
+ sal_Int32 n = 0;
+
+ if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
+ {
+ OClearableGuard aGuard( Application::GetSolarMutex() );
+
+ // query DropTarget from window
+ Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
+
+ // window may be destroyed in drop event handler
+ ImplDelData aDelData;
+ pWindow->ImplAddDel( &aDelData );
+
+ if( xDropTarget.is() )
+ {
+ // retrieve relative mouse position
+ Point relLoc = pWindow->ImplFrameToOutput( rLocation );
+ aGuard.clear();
+
+ n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropEvent(
+ xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, xTransferable );
+ }
+
+ if ( !aDelData.IsDelete() )
+ {
+ pWindow->ImplRemoveDel( &aDelData );
+ // release UI lock
+ pWindow->DecrementLockCount();
+ }
+
+ }
+
+ return n;
+}
+
+//==================================================================================================
+// DNDEventDispatcher::fireDragGestureRecognized
+//==================================================================================================
+
+sal_Int32 DNDEventDispatcher::fireDragGestureEvent( Window *pWindow,
+ const Reference< XDragSource >& xSource, const Any event,
+ const Point& rOrigin, const sal_Int8 nDragAction
+)
+ throw(::com::sun::star::uno::RuntimeException)
+{
+ sal_Int32 n = 0;
+
+ if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
+ {
+ OClearableGuard aGuard( Application::GetSolarMutex() );
+
+ // query DropTarget from window
+ Reference< XDragGestureRecognizer > xDragGestureRecognizer = pWindow->GetDragGestureRecognizer();
+
+ if( xDragGestureRecognizer.is() )
+ {
+ // retrieve relative mouse position
+ Point relLoc = pWindow->ImplFrameToOutput( rOrigin );
+ aGuard.clear();
+
+ n = static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent(
+ nDragAction, relLoc.X(), relLoc.Y(), xSource, event );
+ }
+
+ // release UI lock
+ pWindow->DecrementLockCount();
+ }
+
+ return n;
+}
diff --git a/vcl/source/window/dndlcon.cxx b/vcl/source/window/dndlcon.cxx
new file mode 100644
index 000000000000..07819e76f957
--- /dev/null
+++ b/vcl/source/window/dndlcon.cxx
@@ -0,0 +1,567 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <vcl/dndlcon.hxx>
+
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::dnd;
+
+//==================================================================================================
+//
+//==================================================================================================
+
+DNDListenerContainer::DNDListenerContainer( sal_Int8 nDefaultActions )
+ : WeakComponentImplHelper4< XDragGestureRecognizer, XDropTargetDragContext, XDropTargetDropContext, XDropTarget >(GetMutex())
+{
+ m_bActive = sal_True;
+ m_nDefaultActions = nDefaultActions;
+}
+
+//==================================================================================================
+//
+//==================================================================================================
+
+DNDListenerContainer::~DNDListenerContainer()
+{
+}
+
+//==================================================================================================
+// DNDListenerContainer::addDragGestureListener
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::addDragGestureListener( const Reference< XDragGestureListener >& dgl )
+ throw(RuntimeException)
+{
+ rBHelper.addListener( getCppuType( ( const Reference< XDragGestureListener > * ) 0 ), dgl );
+}
+
+//==================================================================================================
+// DNDListenerContainer::removeDragGestureListener
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::removeDragGestureListener( const Reference< XDragGestureListener >& dgl )
+ throw(RuntimeException)
+{
+ rBHelper.removeListener( getCppuType( ( const Reference< XDragGestureListener > * ) 0 ), dgl );
+}
+
+//==================================================================================================
+// DNDListenerContainer::resetRecognizer
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::resetRecognizer( )
+ throw(RuntimeException)
+{
+}
+
+//==================================================================================================
+// DNDListenerContainer::addDropTargetListener
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::addDropTargetListener( const Reference< XDropTargetListener >& dtl )
+ throw(RuntimeException)
+{
+ rBHelper.addListener( getCppuType( ( const Reference< XDropTargetListener > * ) 0 ), dtl );
+}
+
+//==================================================================================================
+// DNDListenerContainer::removeDropTargetListener
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::removeDropTargetListener( const Reference< XDropTargetListener >& dtl )
+ throw(RuntimeException)
+{
+ rBHelper.removeListener( getCppuType( ( const Reference< XDropTargetListener > * ) 0 ), dtl );
+}
+
+//==================================================================================================
+// DNDListenerContainer::isActive
+//==================================================================================================
+
+sal_Bool SAL_CALL DNDListenerContainer::isActive( )
+ throw(RuntimeException)
+{
+ return m_bActive;
+}
+
+//==================================================================================================
+// DNDListenerContainer::setActive
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::setActive( sal_Bool active )
+ throw(RuntimeException)
+{
+ m_bActive = active;
+}
+
+//==================================================================================================
+// DNDListenerContainer::getDefaultActions
+//==================================================================================================
+
+sal_Int8 SAL_CALL DNDListenerContainer::getDefaultActions( )
+ throw(RuntimeException)
+{
+ return m_nDefaultActions;
+}
+
+//==================================================================================================
+// DNDListenerContainer::setDefaultActions
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::setDefaultActions( sal_Int8 actions )
+ throw(RuntimeException)
+{
+ m_nDefaultActions = actions;
+}
+
+//==================================================================================================
+// DNDListenerContainer::fireDropEvent
+//==================================================================================================
+
+sal_uInt32 DNDListenerContainer::fireDropEvent( const Reference< XDropTargetDropContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions,
+ const Reference< XTransferable >& transferable )
+{
+ sal_uInt32 nRet = 0;
+
+ // fire DropTargetDropEvent on all XDropTargetListeners
+ OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) );
+
+ if( pContainer && m_bActive )
+ {
+ OInterfaceIteratorHelper aIterator( *pContainer );
+
+ // remember context to use in own context methods
+ m_xDropTargetDropContext = context;
+
+ // do not construct the event before you are sure at least one listener is registered
+ DropTargetDropEvent aEvent( static_cast < XDropTarget * > (this), 0,
+ static_cast < XDropTargetDropContext * > (this), dropAction,
+ locationX, locationY, sourceActions, transferable );
+
+ while (aIterator.hasMoreElements())
+ {
+ // FIXME: this can be simplified as soon as the Iterator has a remove method
+ Reference< XInterface > xElement( aIterator.next() );
+
+ try
+ {
+ // this may result in a runtime exception
+ Reference < XDropTargetListener > xListener( xElement, UNO_QUERY );
+
+ if( xListener.is() )
+ {
+ // fire drop until the first one has accepted
+ if( m_xDropTargetDropContext.is() )
+ xListener->drop( aEvent );
+ else
+ {
+ DropTargetEvent aDTEvent( static_cast < XDropTarget * > (this), 0 );
+ xListener->dragExit( aDTEvent );
+ }
+
+ nRet++;
+ }
+ }
+
+ catch( RuntimeException exc )
+ {
+ pContainer->removeInterface( xElement );
+ }
+ }
+
+ // if context still valid, then reject drop
+ if( m_xDropTargetDropContext.is() )
+ {
+ m_xDropTargetDropContext.clear();
+
+ try
+ {
+ context->rejectDrop();
+ }
+
+ catch( RuntimeException exc )
+ {
+ }
+ }
+ }
+
+ return nRet;
+}
+
+//==================================================================================================
+// DNDListenerContainer::fireDragExitEvent
+//==================================================================================================
+
+sal_uInt32 DNDListenerContainer::fireDragExitEvent()
+{
+ sal_uInt32 nRet = 0;
+
+ // fire DropTargetDropEvent on all XDropTargetListeners
+ OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) );
+
+ if( pContainer && m_bActive )
+ {
+ OInterfaceIteratorHelper aIterator( *pContainer );
+
+ // do not construct the event before you are sure at least one listener is registered
+ DropTargetEvent aEvent( static_cast < XDropTarget * > (this), 0 );
+
+ while (aIterator.hasMoreElements())
+ {
+ // FIXME: this can be simplified as soon as the Iterator has a remove method
+ Reference< XInterface > xElement( aIterator.next() );
+
+ try
+ {
+ // this may result in a runtime exception
+ Reference < XDropTargetListener > xListener( xElement, UNO_QUERY );
+
+ if( xListener.is() )
+ {
+ xListener->dragExit( aEvent );
+ nRet++;
+ }
+ }
+
+ catch( RuntimeException exc )
+ {
+ pContainer->removeInterface( xElement );
+ }
+ }
+ }
+
+ return nRet;
+}
+
+//==================================================================================================
+// DNDListenerContainer::fireDragOverEvent
+//==================================================================================================
+
+sal_uInt32 DNDListenerContainer::fireDragOverEvent( const Reference< XDropTargetDragContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions )
+{
+ sal_uInt32 nRet = 0;
+
+ // fire DropTargetDropEvent on all XDropTargetListeners
+ OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) );
+
+ if( pContainer && m_bActive )
+ {
+ OInterfaceIteratorHelper aIterator( *pContainer );
+
+ // remember context to use in own context methods
+ m_xDropTargetDragContext = context;
+
+ // do not construct the event before you are sure at least one listener is registered
+ DropTargetDragEvent aEvent( static_cast < XDropTarget * > (this), 0,
+ static_cast < XDropTargetDragContext * > (this),
+ dropAction, locationX, locationY, sourceActions );
+
+ while (aIterator.hasMoreElements())
+ {
+ // FIXME: this can be simplified as soon as the Iterator has a remove method
+ Reference< XInterface > xElement( aIterator.next() );
+
+ try
+ {
+ // this may result in a runtime exception
+ Reference < XDropTargetListener > xListener( xElement, UNO_QUERY );
+
+ if( xListener.is() )
+ {
+ if( m_xDropTargetDragContext.is() )
+ xListener->dragOver( aEvent );
+ nRet++;
+ }
+ }
+
+ catch( RuntimeException exc )
+ {
+ pContainer->removeInterface( xElement );
+ }
+ }
+
+ // if context still valid, then reject drag
+ if( m_xDropTargetDragContext.is() )
+ {
+ m_xDropTargetDragContext.clear();
+
+ try
+ {
+ context->rejectDrag();
+ }
+
+ catch( RuntimeException exc )
+ {
+ }
+ }
+ }
+
+ return nRet;
+}
+
+//==================================================================================================
+// DNDListenerContainer::fireDragEnterEvent
+//==================================================================================================
+
+sal_uInt32 DNDListenerContainer::fireDragEnterEvent( const Reference< XDropTargetDragContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions,
+ const Sequence< DataFlavor >& dataFlavors )
+{
+ sal_uInt32 nRet = 0;
+
+ // fire DropTargetDropEvent on all XDropTargetListeners
+ OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) );
+
+ if( pContainer && m_bActive )
+ {
+ OInterfaceIteratorHelper aIterator( *pContainer );
+
+ // remember context to use in own context methods
+ m_xDropTargetDragContext = context;
+
+ // do not construct the event before you are sure at least one listener is registered
+ DropTargetDragEnterEvent aEvent( static_cast < XDropTarget * > (this), 0,
+ static_cast < XDropTargetDragContext * > (this),
+ dropAction, locationX, locationY, sourceActions, dataFlavors );
+
+ while (aIterator.hasMoreElements())
+ {
+ // FIXME: this can be simplified as soon as the Iterator has a remove method
+ Reference< XInterface > xElement( aIterator.next() );
+
+ try
+ {
+ // this may result in a runtime exception
+ Reference < XDropTargetListener > xListener( xElement, UNO_QUERY );
+
+ if( xListener.is() )
+ {
+ if( m_xDropTargetDragContext.is() )
+ xListener->dragEnter( aEvent );
+ nRet++;
+ }
+ }
+
+ catch( RuntimeException exc )
+ {
+ pContainer->removeInterface( xElement );
+ }
+ }
+
+ // if context still valid, then reject drag
+ if( m_xDropTargetDragContext.is() )
+ {
+ m_xDropTargetDragContext.clear();
+
+ try
+ {
+ context->rejectDrag();
+ }
+
+ catch( RuntimeException exc )
+ {
+ }
+ }
+ }
+
+ return nRet;
+}
+
+//==================================================================================================
+// DNDListenerContainer::fireDropActionChangedEvent
+//==================================================================================================
+
+sal_uInt32 DNDListenerContainer::fireDropActionChangedEvent( const Reference< XDropTargetDragContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions )
+{
+ sal_uInt32 nRet = 0;
+
+ // fire DropTargetDropEvent on all XDropTargetListeners
+ OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) );
+
+ if( pContainer && m_bActive )
+ {
+ OInterfaceIteratorHelper aIterator( *pContainer );
+
+ // remember context to use in own context methods
+ m_xDropTargetDragContext = context;
+
+ // do not construct the event before you are sure at least one listener is registered
+ DropTargetDragEvent aEvent( static_cast < XDropTarget * > (this), 0,
+ static_cast < XDropTargetDragContext * > (this),
+ dropAction, locationX, locationY, sourceActions );
+
+ while (aIterator.hasMoreElements())
+ {
+ // FIXME: this can be simplified as soon as the Iterator has a remove method
+ Reference< XInterface > xElement( aIterator.next() );
+
+ try
+ {
+ // this may result in a runtime exception
+ Reference < XDropTargetListener > xListener( xElement, UNO_QUERY );
+
+ if( xListener.is() )
+ {
+ if( m_xDropTargetDragContext.is() )
+ xListener->dropActionChanged( aEvent );
+ nRet++;
+ }
+ }
+
+ catch( RuntimeException exc )
+ {
+ pContainer->removeInterface( xElement );
+ }
+ }
+
+ // if context still valid, then reject drag
+ if( m_xDropTargetDragContext.is() )
+ {
+ m_xDropTargetDragContext.clear();
+
+ try
+ {
+ context->rejectDrag();
+ }
+
+ catch( RuntimeException exc )
+ {
+ }
+ }
+ }
+
+ return nRet;
+}
+
+//==================================================================================================
+// DNDListenerContainer::fireDragGestureEvent
+//==================================================================================================
+
+sal_uInt32 DNDListenerContainer::fireDragGestureEvent( sal_Int8 dragAction, sal_Int32 dragOriginX,
+ sal_Int32 dragOriginY, const Reference< XDragSource >& dragSource, const Any& triggerEvent )
+{
+ sal_uInt32 nRet = 0;
+
+ // fire DropTargetDropEvent on all XDropTargetListeners
+ OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDragGestureListener > * ) 0) );
+
+ if( pContainer )
+ {
+ OInterfaceIteratorHelper aIterator( *pContainer );
+
+ // do not construct the event before you are sure at least one listener is registered
+ DragGestureEvent aEvent( static_cast < XDragGestureRecognizer * > (this), dragAction,
+ dragOriginX, dragOriginY, dragSource, triggerEvent );
+
+ while( aIterator.hasMoreElements() )
+ {
+ // FIXME: this can be simplified as soon as the Iterator has a remove method
+ Reference< XInterface > xElement( aIterator.next() );
+
+ try
+ {
+ // this may result in a runtime exception
+ Reference < XDragGestureListener > xListener( xElement, UNO_QUERY );
+
+ if( xListener.is() )
+ {
+ xListener->dragGestureRecognized( aEvent );
+ nRet++;
+ }
+ }
+
+ catch( RuntimeException exc )
+ {
+ pContainer->removeInterface( xElement );
+ }
+ }
+ }
+
+ return nRet;
+}
+
+//==================================================================================================
+// DNDListenerContainer::acceptDrag
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::acceptDrag( sal_Int8 dragOperation ) throw (RuntimeException)
+{
+ if( m_xDropTargetDragContext.is() )
+ {
+ m_xDropTargetDragContext->acceptDrag( dragOperation );
+ m_xDropTargetDragContext.clear();
+ }
+}
+
+//==================================================================================================
+// DNDListenerContainer::rejectDrag
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::rejectDrag( ) throw (RuntimeException)
+{
+ // nothing to do here
+}
+
+//==================================================================================================
+// DNDListenerContainer::acceptDrop
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::acceptDrop( sal_Int8 dropOperation ) throw (RuntimeException)
+{
+ if( m_xDropTargetDropContext.is() )
+ m_xDropTargetDropContext->acceptDrop( dropOperation );
+}
+
+//==================================================================================================
+// DNDListenerContainer::rejectDrop
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::rejectDrop( ) throw (RuntimeException)
+{
+ // nothing to do here
+}
+
+//==================================================================================================
+// DNDListenerContainer::dropComplete
+//==================================================================================================
+
+void SAL_CALL DNDListenerContainer::dropComplete( sal_Bool success ) throw (RuntimeException)
+{
+ if( m_xDropTargetDropContext.is() )
+ {
+ m_xDropTargetDropContext->dropComplete( success );
+ m_xDropTargetDropContext.clear();
+ }
+}
diff --git a/vcl/source/window/dockingarea.cxx b/vcl/source/window/dockingarea.cxx
new file mode 100644
index 000000000000..9ea407e52ee3
--- /dev/null
+++ b/vcl/source/window/dockingarea.cxx
@@ -0,0 +1,246 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <vcl/dockingarea.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/svdata.hxx>
+
+#include <map>
+
+// =======================================================================
+
+class DockingAreaWindow::ImplData
+{
+public:
+ ImplData();
+ ~ImplData();
+
+ WindowAlign meAlign;
+};
+
+DockingAreaWindow::ImplData::ImplData()
+{
+ meAlign = WINDOWALIGN_TOP;
+}
+
+DockingAreaWindow::ImplData::~ImplData()
+{
+}
+
+// =======================================================================
+
+static void ImplInitBackground( DockingAreaWindow* pThis )
+{
+ if( !pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) )
+ {
+ Wallpaper aWallpaper;
+ aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT );
+ pThis->SetBackground( aWallpaper );
+ }
+ else
+ pThis->SetBackground( Wallpaper( pThis->GetSettings().GetStyleSettings().GetFaceColor() ) );
+}
+
+DockingAreaWindow::DockingAreaWindow( Window* pParent ) :
+ Window( WINDOW_DOCKINGAREA )
+{
+ ImplInit( pParent, WB_CLIPCHILDREN|WB_3DLOOK, NULL );
+
+ mpImplData = new ImplData;
+ ImplInitBackground( this );
+}
+
+DockingAreaWindow::~DockingAreaWindow()
+{
+ delete mpImplData;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingAreaWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitBackground( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplInvalidateMenubar( DockingAreaWindow* pThis )
+{
+ // due to a possible comon gradient covering menubar and top dockingarea
+ // the menubar must be repainted if the top dockingarea changes size or visibility
+ if( ImplGetSVData()->maNWFData.mbMenuBarDockingAreaCommonBG &&
+ (pThis->GetAlign() == WINDOWALIGN_TOP)
+ && pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL )
+ && pThis->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ SystemWindow *pSysWin = pThis->GetSystemWindow();
+ if( pSysWin && pSysWin->GetMenuBar() )
+ {
+ Window *pMenubarWin = pSysWin->GetMenuBar()->GetWindow();
+ if( pMenubarWin )
+ pMenubarWin->Invalidate();
+ }
+ }
+}
+
+void DockingAreaWindow::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_VISIBLE )
+ ImplInvalidateMenubar( this );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DockingAreaWindow::IsHorizontal() const
+{
+ return ( mpImplData->meAlign == WINDOWALIGN_TOP || mpImplData->meAlign == WINDOWALIGN_BOTTOM );
+}
+
+void DockingAreaWindow::SetAlign( WindowAlign eNewAlign )
+{
+ if( eNewAlign != mpImplData->meAlign )
+ {
+ mpImplData->meAlign = eNewAlign;
+ Invalidate();
+ }
+}
+
+WindowAlign DockingAreaWindow::GetAlign() const
+{
+ return mpImplData->meAlign;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingAreaWindow::Paint( const Rectangle& )
+{
+ EnableNativeWidget( TRUE ); // only required because the toolkit curently switches this flag off
+ if( IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) )
+ {
+ ToolbarValue aControlValue;
+
+ if( GetAlign() == WINDOWALIGN_TOP && ImplGetSVData()->maNWFData.mbMenuBarDockingAreaCommonBG )
+ {
+ // give NWF a hint that this dockingarea is adjacent to the menubar
+ // useful for special gradient effects that should cover both windows
+ aControlValue.mbIsTopDockingArea = TRUE;
+ }
+ ControlState nState = CTRL_STATE_ENABLED;
+
+ if( !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB )
+ {
+ // draw a single toolbar background covering the whole docking area
+ Point tmp;
+ Rectangle aCtrlRegion( tmp, GetOutputSizePixel() );
+
+ DrawNativeControl( CTRL_TOOLBAR, IsHorizontal() ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT,
+ aCtrlRegion, nState, aControlValue, rtl::OUString() );
+
+ // each toolbar gets a thin border to better recognize its borders on the homogeneous docking area
+ USHORT nChildren = GetChildCount();
+ for( USHORT n = 0; n < nChildren; n++ )
+ {
+ Window* pChild = GetChild( n );
+ if ( pChild->IsVisible() )
+ {
+ Point aPos = pChild->GetPosPixel();
+ Size aSize = pChild->GetSizePixel();
+ Rectangle aRect( aPos, aSize );
+
+ SetLineColor( GetSettings().GetStyleSettings().GetLightColor() );
+ DrawLine( aRect.TopLeft(), aRect.TopRight() );
+ DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
+
+ SetLineColor( GetSettings().GetStyleSettings().GetSeparatorColor() );
+ DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ }
+ }
+ }
+ else
+ {
+ // create map to find toolbar lines
+ Size aOutSz = GetOutputSizePixel();
+ std::map< int, int > ranges;
+ USHORT nChildren = GetChildCount();
+ for( USHORT n = 0; n < nChildren; n++ )
+ {
+ Window* pChild = GetChild( n );
+ Point aPos = pChild->GetPosPixel();
+ Size aSize = pChild->GetSizePixel();
+ if( IsHorizontal() )
+ ranges[ aPos.Y() ] = aSize.Height();
+ else
+ ranges[ aPos.X() ] = aSize.Width();
+ }
+
+
+ // draw multiple toolbar backgrounds, i.e., one for each toolbar line
+ for( std::map<int,int>::const_iterator it = ranges.begin(); it != ranges.end(); ++it )
+ {
+ Rectangle aTBRect;
+ if( IsHorizontal() )
+ {
+ aTBRect.Left() = 0;
+ aTBRect.Right() = aOutSz.Width() - 1;
+ aTBRect.Top() = it->first;
+ aTBRect.Bottom() = it->first + it->second - 1;
+ }
+ else
+ {
+ aTBRect.Left() = it->first;
+ aTBRect.Right() = it->first + it->second - 1;
+ aTBRect.Top() = 0;
+ aTBRect.Bottom() = aOutSz.Height() - 1;
+ }
+ DrawNativeControl( CTRL_TOOLBAR, IsHorizontal() ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT,
+ aTBRect, nState, aControlValue, rtl::OUString() );
+ }
+ }
+ }
+}
+
+void DockingAreaWindow::Resize()
+{
+ ImplInvalidateMenubar( this );
+ if( IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) )
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/source/window/dockmgr.cxx b/vcl/source/window/dockmgr.cxx
new file mode 100644
index 000000000000..e67c2d9ecfd5
--- /dev/null
+++ b/vcl/source/window/dockmgr.cxx
@@ -0,0 +1,1689 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <tools/time.hxx>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/event.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/dockwin.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/window.h>
+#include <vcl/unowrap.hxx>
+#include <vcl/salframe.hxx>
+
+
+// =======================================================================
+
+#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_PINABLE | WB_ROLLABLE )
+
+// =======================================================================
+
+
+// =======================================================================
+
+class ImplDockFloatWin2 : public FloatingWindow
+{
+private:
+ ImplDockingWindowWrapper* mpDockWin;
+ ULONG mnLastTicks;
+ Timer maDockTimer;
+ Timer maEndDockTimer;
+ Point maDockPos;
+ Rectangle maDockRect;
+ BOOL mbInMove;
+ ULONG mnLastUserEvent;
+
+ DECL_LINK( DockingHdl, ImplDockFloatWin2* );
+ DECL_LINK( DockTimerHdl, ImplDockFloatWin2* );
+ DECL_LINK( EndDockTimerHdl, ImplDockFloatWin2* );
+public:
+ ImplDockFloatWin2( Window* pParent, WinBits nWinBits,
+ ImplDockingWindowWrapper* pDockingWin );
+ ~ImplDockFloatWin2();
+
+ virtual void Move();
+ virtual void Resize();
+ virtual void TitleButtonClick( USHORT nButton );
+ virtual void Pin();
+ virtual void Roll();
+ virtual void PopupModeEnd();
+ virtual void Resizing( Size& rSize );
+ virtual BOOL Close();
+ using Window::SetPosSizePixel;
+ virtual void SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags = WINDOW_POSSIZE_ALL );
+
+ ULONG GetLastTicks() const { return mnLastTicks; }
+};
+
+// =======================================================================
+
+ImplDockFloatWin2::ImplDockFloatWin2( Window* pParent, WinBits nWinBits,
+ ImplDockingWindowWrapper* pDockingWin ) :
+ FloatingWindow( pParent, nWinBits ),
+ mpDockWin( pDockingWin ),
+ mnLastTicks( Time::GetSystemTicks() ),
+ mbInMove( FALSE ),
+ mnLastUserEvent( 0 )
+{
+ // Daten vom DockingWindow uebernehmen
+ if ( pDockingWin )
+ {
+ SetSettings( pDockingWin->GetWindow()->GetSettings() );
+ Enable( pDockingWin->GetWindow()->IsEnabled(), FALSE );
+ EnableInput( pDockingWin->GetWindow()->IsInputEnabled(), FALSE );
+ AlwaysEnableInput( pDockingWin->GetWindow()->IsAlwaysEnableInput(), FALSE );
+ EnableAlwaysOnTop( pDockingWin->GetWindow()->IsAlwaysOnTopEnabled() );
+ SetActivateMode( pDockingWin->GetWindow()->GetActivateMode() );
+ }
+
+ SetBackground( GetSettings().GetStyleSettings().GetFaceColor() );
+
+ maDockTimer.SetTimeoutHdl( LINK( this, ImplDockFloatWin2, DockTimerHdl ) );
+ maDockTimer.SetTimeout( 50 );
+ maEndDockTimer.SetTimeoutHdl( LINK( this, ImplDockFloatWin2, EndDockTimerHdl ) );
+ maEndDockTimer.SetTimeout( 50 );
+}
+
+// -----------------------------------------------------------------------
+
+ImplDockFloatWin2::~ImplDockFloatWin2()
+{
+ if( mnLastUserEvent )
+ Application::RemoveUserEvent( mnLastUserEvent );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplDockFloatWin2, DockTimerHdl, ImplDockFloatWin2*, EMPTYARG )
+{
+ DBG_ASSERT( mpDockWin->IsFloatingMode(), "docktimer called but not floating" );
+
+ maDockTimer.Stop();
+ PointerState aState = GetPointerState();
+
+ if( aState.mnState & KEY_MOD1 )
+ {
+ // i43499 CTRL disables docking now
+ mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
+ if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
+ maDockTimer.Start();
+ }
+ else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
+ {
+ mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
+ mpDockWin->EndDocking( maDockRect, FALSE );
+ }
+ else
+ {
+ mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_BIG | SHOWTRACK_WINDOW );
+ maDockTimer.Start();
+ }
+
+ return 0;
+}
+
+IMPL_LINK( ImplDockFloatWin2, EndDockTimerHdl, ImplDockFloatWin2*, EMPTYARG )
+{
+ DBG_ASSERT( mpDockWin->IsFloatingMode(), "enddocktimer called but not floating" );
+
+ maEndDockTimer.Stop();
+ PointerState aState = GetPointerState();
+ if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
+ {
+ mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
+ mpDockWin->EndDocking( maDockRect, TRUE );
+ }
+ else
+ {
+ maEndDockTimer.Start();
+ }
+
+ return 0;
+}
+
+
+IMPL_LINK( ImplDockFloatWin2, DockingHdl, ImplDockFloatWin2*, EMPTYARG )
+{
+ // called during move of a floating window
+ mnLastUserEvent = 0;
+
+ Window *pDockingArea = mpDockWin->GetWindow()->GetParent();
+ PointerState aState = pDockingArea->GetPointerState();
+
+ BOOL bRealMove = TRUE;
+ if( GetStyle() & WB_OWNERDRAWDECORATION )
+ {
+ // for windows with ownerdraw decoration
+ // we allow docking only when the window was moved
+ // by dragging its caption
+ // and ignore move request due to resizing
+ Window *pBorder = GetWindow( WINDOW_BORDER );
+ if( pBorder != this )
+ {
+ Point aPt;
+ Rectangle aBorderRect( aPt, pBorder->GetSizePixel() );
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ GetBorder( nLeft, nTop, nRight, nBottom );
+ // limit borderrect to the caption part only and without the resizing borders
+ aBorderRect.nBottom = aBorderRect.nTop + nTop;
+ aBorderRect.nLeft += nLeft;
+ aBorderRect.nRight -= nRight;
+
+ PointerState aBorderState = pBorder->GetPointerState();
+ if( aBorderRect.IsInside( aBorderState.maPos ) )
+ bRealMove = TRUE;
+ else
+ bRealMove = FALSE;
+ }
+ }
+
+ if( mpDockWin->IsDockable() &&
+ mpDockWin->GetWindow()->IsVisible() &&
+ (Time::GetSystemTicks() - mnLastTicks > 500) &&
+ ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) &&
+ !(aState.mnState & KEY_MOD1) && // i43499 CTRL disables docking now
+ bRealMove )
+ {
+ maDockPos = Point( pDockingArea->OutputToScreenPixel( pDockingArea->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) ) );
+ maDockRect = Rectangle( maDockPos, mpDockWin->GetSizePixel() );
+
+ // mouse pos in screen pixels
+ Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos );
+
+ if( ! mpDockWin->IsDocking() )
+ mpDockWin->StartDocking( aMousePos, maDockRect );
+
+ BOOL bFloatMode = mpDockWin->Docking( aMousePos, maDockRect );
+
+ if( ! bFloatMode )
+ {
+ // indicates that the window could be docked at maDockRect
+ maDockRect.SetPos( mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ScreenToOutputPixel(
+ maDockRect.TopLeft() ) );
+ mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_BIG | SHOWTRACK_WINDOW );
+ maEndDockTimer.Stop();
+ DockTimerHdl( this );
+ }
+ else
+ {
+ mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
+ maDockTimer.Stop();
+ EndDockTimerHdl( this );
+ }
+ }
+ mbInMove = FALSE;
+ return 0;
+}
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin2::Move()
+{
+ if( mbInMove )
+ return;
+
+ mbInMove = TRUE;
+ FloatingWindow::Move();
+ mpDockWin->GetWindow()->Move();
+
+ /*
+ * note: the window should only dock if KEY_MOD1 is pressed
+ * and the user releases all mouse buttons. The real problem here
+ * is that we don't get mouse events (at least not on X)
+ * if the mouse is on the decoration. So we have to start an
+ * awkward timer based process that polls the modifier/buttons
+ * to see whether they are in the right condition shortly after the
+ * last Move message.
+ */
+ if( ! mnLastUserEvent )
+ mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin2, DockingHdl ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin2::Resize()
+{
+ // forwarding of resize only required if we have no borderwindow ( GetWindow() then returns 'this' )
+ if( GetWindow( WINDOW_BORDER ) == this )
+ {
+ FloatingWindow::Resize();
+ Size aSize( GetSizePixel() );
+ mpDockWin->GetWindow()->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), WINDOW_POSSIZE_POSSIZE ); // is this needed ???
+ }
+}
+
+void ImplDockFloatWin2::SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags )
+{
+ FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+
+void ImplDockFloatWin2::TitleButtonClick( USHORT nButton )
+{
+ FloatingWindow::TitleButtonClick( nButton );
+ mpDockWin->TitleButtonClick( nButton );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin2::Pin()
+{
+ FloatingWindow::Pin();
+ mpDockWin->Pin();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin2::Roll()
+{
+ FloatingWindow::Roll();
+ mpDockWin->Roll();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin2::PopupModeEnd()
+{
+ FloatingWindow::PopupModeEnd();
+ mpDockWin->PopupModeEnd();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin2::Resizing( Size& rSize )
+{
+ FloatingWindow::Resizing( rSize );
+ mpDockWin->Resizing( rSize );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplDockFloatWin2::Close()
+{
+ return mpDockWin->Close();
+}
+
+// =======================================================================
+
+DockingManager::DockingManager()
+{
+}
+
+DockingManager::~DockingManager()
+{
+ ::std::vector< ImplDockingWindowWrapper* >::iterator p;
+ p = mDockingWindows.begin();
+ for(; p != mDockingWindows.end(); ++p )
+ {
+ delete (*p);
+ }
+ mDockingWindows.clear();
+}
+
+ImplDockingWindowWrapper* DockingManager::GetDockingWindowWrapper( const Window *pWindow )
+{
+ ::std::vector< ImplDockingWindowWrapper* >::iterator p;
+ p = mDockingWindows.begin();
+ while( p != mDockingWindows.end() )
+ {
+ if( (*p)->mpDockingWindow == pWindow )
+ return (*p);
+ else
+ p++;
+ }
+ return NULL;
+}
+
+BOOL DockingManager::IsDockable( const Window *pWindow )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+
+ /*
+ if( pWindow->HasDockingHandler() )
+ return TRUE;
+ */
+ return (pWrapper != NULL);
+}
+
+BOOL DockingManager::IsFloating( const Window *pWindow )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ return pWrapper->IsFloatingMode();
+ else
+ return FALSE;
+}
+
+BOOL DockingManager::IsLocked( const Window *pWindow )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper && pWrapper->IsLocked() )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void DockingManager::Lock( const Window *pWindow )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ pWrapper->Lock();
+}
+
+void DockingManager::Unlock( const Window *pWindow )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ pWrapper->Unlock();
+}
+
+void DockingManager::SetFloatingMode( const Window *pWindow, BOOL bFloating )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ pWrapper->SetFloatingMode( bFloating );
+}
+
+void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const Window *pWindow, ULONG nFlags )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ pWrapper->StartPopupMode( pParentToolBox, nFlags );
+}
+
+void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const Window *pWindow )
+{
+ StartPopupMode( pParentToolBox, pWindow, FLOATWIN_POPUPMODE_ALLOWTEAROFF |
+ FLOATWIN_POPUPMODE_NOFOCUSCLOSE |
+ FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE |
+ FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE );
+}
+
+BOOL DockingManager::IsInPopupMode( const Window *pWindow )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper && pWrapper->IsInPopupMode() )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingManager::EndPopupMode( const Window *pWin )
+{
+ ImplDockingWindowWrapper *pWrapper = GetDockingWindowWrapper( pWin );
+ if( pWrapper && pWrapper->GetFloatingWindow() && pWrapper->GetFloatingWindow()->IsInPopupMode() )
+ pWrapper->GetFloatingWindow()->EndPopupMode();
+}
+
+// -----------------------------------------------------------------------
+
+void DockingManager::AddWindow( const Window *pWindow )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ return;
+ else
+ pWrapper = new ImplDockingWindowWrapper( pWindow );
+
+ mDockingWindows.push_back( pWrapper );
+}
+
+void DockingManager::RemoveWindow( const Window *pWindow )
+{
+ ::std::vector< ImplDockingWindowWrapper* >::iterator p;
+ p = mDockingWindows.begin();
+ while( p != mDockingWindows.end() )
+ {
+ if( (*p)->mpDockingWindow == pWindow )
+ {
+ delete (*p);
+ mDockingWindows.erase( p );
+ break;
+ }
+ else
+ p++;
+ }
+}
+
+void DockingManager::SetPosSizePixel( Window *pWindow, long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags )
+{
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ pWrapper->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+}
+
+Rectangle DockingManager::GetPosSizePixel( const Window *pWindow )
+{
+ Rectangle aRect;
+ ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
+ if( pWrapper )
+ aRect = Rectangle( pWrapper->GetPosPixel(), pWrapper->GetSizePixel() );
+
+ return aRect;
+}
+
+// =======================================================================
+// special floating window for popup mode
+// main purpose: provides tear-off area for undocking
+// =======================================================================
+
+// if TEAROFF_DASHED defined a single dashed line is used
+// otherwise multiple smaller lines will be painted
+//#define TEAROFF_DASHED
+
+// size of the drag area
+#ifdef TEAROFF_DASHED
+#define POPUP_DRAGBORDER 2
+#define POPUP_DRAGGRIP 5
+#else
+#define POPUP_DRAGBORDER 3
+#define POPUP_DRAGGRIP 5
+#endif
+#define POPUP_DRAGHEIGHT (POPUP_DRAGGRIP+POPUP_DRAGBORDER+POPUP_DRAGBORDER)
+#define POPUP_DRAGWIDTH 20
+
+class ImplPopupFloatWin : public FloatingWindow
+{
+private:
+ ImplDockingWindowWrapper* mpDockingWin;
+ BOOL mbHighlight;
+ BOOL mbMoving;
+ bool mbTrackingEnabled;
+ Point maDelta;
+ Point maTearOffPosition;
+ bool mbGripAtBottom;
+ bool mbHasGrip;
+ void ImplSetBorder();
+
+public:
+ ImplPopupFloatWin( Window* pParent, ImplDockingWindowWrapper* pDockingWin, bool bHasGrip );
+ ~ImplPopupFloatWin();
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+ virtual void Paint( const Rectangle& rRect );
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void Resize();
+ virtual Window* GetPreferredKeyInputWindow();
+
+ Rectangle GetDragRect() const;
+ Point GetToolboxPosition() const;
+ Point GetTearOffPosition() const;
+ void DrawGrip();
+ void DrawBorder();
+
+ bool hasGrip() const { return mbHasGrip; }
+};
+
+ImplPopupFloatWin::ImplPopupFloatWin( Window* pParent, ImplDockingWindowWrapper* pDockingWin, bool bHasGrip ) :
+ FloatingWindow( pParent, WB_NOBORDER | WB_SYSTEMWINDOW | WB_NOSHADOW)
+{
+ mpWindowImpl->mbToolbarFloatingWindow = TRUE; // indicate window type, required for accessibility
+ // which should not see this window as a toplevel window
+ mpDockingWin = pDockingWin;
+ mbHighlight = FALSE;
+ mbMoving = FALSE;
+ mbTrackingEnabled = FALSE;
+ mbGripAtBottom = TRUE;
+ mbHasGrip = bHasGrip;
+
+ ImplSetBorder();
+}
+
+ImplPopupFloatWin::~ImplPopupFloatWin()
+{
+ mpDockingWin = NULL;
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > ImplPopupFloatWin::CreateAccessible()
+{
+ // switch off direct accessibilty support for this window
+
+ // this is to avoid appearance of this window as standalone window in the accessibility hierarchy
+ // as this window is only used as a helper for subtoolbars that are not teared-off, the parent toolbar
+ // has to provide accessibility support (as implemented in the toolkit)
+ // so the contained toolbar should appear as child of the correponsing toolbar item of the parent toolbar
+ return ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >();
+}
+
+Window* ImplPopupFloatWin::GetPreferredKeyInputWindow()
+{
+ if( mpWindowImpl->mpClientWindow )
+ return mpWindowImpl->mpClientWindow;
+ else
+ return FloatingWindow::GetPreferredKeyInputWindow();
+}
+
+
+void ImplPopupFloatWin::ImplSetBorder()
+{
+ // although we have no border in the sense of a borderwindow
+ // we're using a special border for the grip
+ // by setting those members the method SetOutputSizePixel() can
+ // be used to set the proper window size
+ mpWindowImpl->mnTopBorder = 1;
+ if( hasGrip() )
+ mpWindowImpl->mnTopBorder += POPUP_DRAGHEIGHT+2;
+ mpWindowImpl->mnBottomBorder = 1;
+ mpWindowImpl->mnLeftBorder = 1;
+ mpWindowImpl->mnRightBorder = 1;
+}
+
+void ImplPopupFloatWin::Resize()
+{
+ // the borderview overwrites the border during resize so restore it
+ ImplSetBorder();
+}
+
+Rectangle ImplPopupFloatWin::GetDragRect() const
+{
+ Rectangle aRect;
+ if( hasGrip() )
+ {
+ aRect = Rectangle( 1,1, GetOutputSizePixel().Width()-1, 2+POPUP_DRAGHEIGHT );
+ if( mbGripAtBottom )
+ {
+ int height = GetOutputSizePixel().Height();
+ aRect.Top() = height - 3 - POPUP_DRAGHEIGHT;
+ aRect.Bottom() = aRect.Top() + 1 + POPUP_DRAGHEIGHT;
+ }
+ }
+ return aRect;
+}
+
+Point ImplPopupFloatWin::GetToolboxPosition() const
+{
+ // return inner position where a toolbox could be placed
+ Point aPt( 1, 1 + ((mbGripAtBottom || !hasGrip()) ? 0 : GetDragRect().getHeight()) ); // grip + border
+
+ return aPt;
+}
+
+Point ImplPopupFloatWin::GetTearOffPosition() const
+{
+ Point aPt( maTearOffPosition );
+ //aPt += GetToolboxPosition(); // remove 'decoration'
+ return aPt;
+}
+
+void ImplPopupFloatWin::DrawBorder()
+{
+ SetFillColor();
+ Point aPt;
+ Rectangle aRect( aPt, GetOutputSizePixel() );
+
+ Region oldClipRgn( GetClipRegion( ) );
+ Region aClipRgn( aRect );
+ Rectangle aItemClipRect( ImplGetItemEdgeClipRect() );
+ if( !aItemClipRect.IsEmpty() )
+ {
+ aItemClipRect.SetPos( AbsoluteScreenToOutputPixel( aItemClipRect.TopLeft() ) );
+
+ // draw the excluded border part with the background color of a toolbox
+ SetClipRegion( Region( aItemClipRect ) );
+ SetLineColor( GetSettings().GetStyleSettings().GetFaceColor() );
+ DrawRect( aRect );
+
+ aClipRgn.Exclude( aItemClipRect );
+ SetClipRegion( aClipRgn );
+ }
+ SetLineColor( GetSettings().GetStyleSettings().GetShadowColor() );
+ DrawRect( aRect );
+ SetClipRegion( oldClipRgn );
+}
+
+void ImplPopupFloatWin::DrawGrip()
+{
+ BOOL bLinecolor = IsLineColor();
+ Color aLinecolor = GetLineColor();
+ BOOL bFillcolor = IsFillColor();
+ Color aFillcolor = GetFillColor();
+
+ // draw background
+ Rectangle aRect( GetDragRect() );
+ aRect.nTop += POPUP_DRAGBORDER;
+ aRect.nBottom -= POPUP_DRAGBORDER;
+ aRect.nLeft+=3;
+ aRect.nRight-=3;
+
+ if( mbHighlight )
+ {
+ Erase( aRect );
+ DrawSelectionBackground( aRect, 2, FALSE, TRUE, FALSE );
+ }
+ else
+ {
+ SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
+ SetLineColor();
+ DrawRect( aRect );
+ }
+
+ if( !ToolBox::AlwaysLocked() ) // no grip if toolboxes are locked
+ {
+#ifdef TEAROFF_DASHED
+ // draw single dashed line
+ LineInfo aLineInfo( LINE_DASH );
+ aLineInfo.SetDistance( 4 );
+ aLineInfo.SetDashLen( 12 );
+ aLineInfo.SetDashCount( 1 );
+
+ aRect.nLeft+=2; aRect.nRight-=2;
+
+ aRect.nTop+=2;
+ aRect.nBottom = aRect.nTop;
+ SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() );
+ DrawLine( aRect.TopLeft(), aRect.TopRight(), aLineInfo );
+
+ if( !mbHighlight )
+ {
+ aRect.nTop++; aRect.nBottom++;
+ SetLineColor( GetSettings().GetStyleSettings().GetLightColor() );
+ DrawLine( aRect.TopLeft(), aRect.TopRight(), aLineInfo );
+ }
+
+#else
+ // draw several grip lines
+ SetFillColor( GetSettings().GetStyleSettings().GetShadowColor() );
+ aRect.nTop++;
+ aRect.nBottom = aRect.nTop;
+
+ int width = POPUP_DRAGWIDTH;
+ while( width >= aRect.getWidth() )
+ width -= 4;
+ if( width <= 0 )
+ width = aRect.getWidth();
+ //aRect.nLeft = aRect.nLeft + (aRect.getWidth() - width) / 2;
+ aRect.nLeft = (aRect.nLeft + aRect.nRight - width) / 2;
+ aRect.nRight = aRect.nLeft + width;
+
+ int i=0;
+ while( i< POPUP_DRAGGRIP )
+ {
+ DrawRect( aRect );
+ aRect.nTop+=2;
+ aRect.nBottom+=2;
+ i+=2;
+ }
+#endif
+ }
+
+ if( bLinecolor )
+ SetLineColor( aLinecolor );
+ else
+ SetLineColor();
+ if( bFillcolor )
+ SetFillColor( aFillcolor );
+ else
+ SetFillColor();
+}
+
+void ImplPopupFloatWin::Paint( const Rectangle& )
+{
+ Point aPt;
+ Rectangle aRect( aPt, GetOutputSizePixel() );
+ DrawWallpaper( aRect, Wallpaper( GetSettings().GetStyleSettings().GetFaceGradientColor() ) );
+ DrawBorder();
+ if( hasGrip() )
+ DrawGrip();
+}
+
+void ImplPopupFloatWin::MouseMove( const MouseEvent& rMEvt )
+{
+ Point aMousePos = rMEvt.GetPosPixel();
+
+ if( !ToolBox::AlwaysLocked() ) // no tear off if locking is enabled
+ {
+ if( mbTrackingEnabled && rMEvt.IsLeft() && GetDragRect().IsInside( aMousePos ) )
+ {
+ // start window move
+ mbMoving = TRUE;
+ StartTracking( STARTTRACK_NOKEYCANCEL );
+ return;
+ }
+ if( !mbHighlight && GetDragRect().IsInside( aMousePos ) )
+ {
+ mbHighlight = TRUE;
+ DrawGrip();
+ }
+ if( mbHighlight && ( rMEvt.IsLeaveWindow() || !GetDragRect().IsInside( aMousePos ) ) )
+ {
+ mbHighlight = FALSE;
+ DrawGrip();
+ }
+ }
+}
+
+void ImplPopupFloatWin::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ mbTrackingEnabled = false;
+ FloatingWindow::MouseButtonUp( rMEvt );
+}
+
+void ImplPopupFloatWin::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ Point aMousePos = rMEvt.GetPosPixel();
+ if( GetDragRect().IsInside( aMousePos ) )
+ {
+ // get mouse pos at a static window to have a fixed reference point
+ PointerState aState = GetParent()->GetPointerState();
+ if (ImplHasMirroredGraphics() && IsRTLEnabled())
+ ImplMirrorFramePos(aState.maPos);
+ maTearOffPosition = GetWindow( WINDOW_BORDER )->GetPosPixel();
+ maDelta = aState.maPos - maTearOffPosition;
+ mbTrackingEnabled = true;
+ }
+ else
+ {
+ mbTrackingEnabled = false;
+ }
+}
+
+void ImplPopupFloatWin::Tracking( const TrackingEvent& rTEvt )
+{
+ if( mbMoving )
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ mbMoving = FALSE;
+ EndPopupMode( FLOATWIN_POPUPMODEEND_TEAROFF );
+ }
+ else if ( !rTEvt.GetMouseEvent().IsSynthetic() )
+ {
+ // move the window according to mouse pos
+ PointerState aState = GetParent()->GetPointerState();
+ if (ImplHasMirroredGraphics() && IsRTLEnabled())
+ ImplMirrorFramePos(aState.maPos);
+ maTearOffPosition = aState.maPos - maDelta;
+ GetWindow( WINDOW_BORDER )->SetPosPixel( maTearOffPosition );
+ }
+ }
+}
+
+
+// =======================================================================
+
+ImplDockingWindowWrapper::ImplDockingWindowWrapper( const Window *pWindow )
+{
+ ImplInitData();
+
+ mpDockingWindow = (Window*) pWindow;
+ mpParent = pWindow->GetParent();
+ mbDockable = TRUE;
+ mbLocked = FALSE;
+ mnFloatBits = WB_BORDER | WB_CLOSEABLE | WB_SIZEABLE | (pWindow->GetStyle() & DOCKWIN_FLOATSTYLES);
+ DockingWindow *pDockWin = dynamic_cast< DockingWindow* > ( mpDockingWindow );
+ if( pDockWin )
+ mnFloatBits = pDockWin->GetFloatStyle();
+
+ // must be enabled in Window::Notify to prevent permanent docking during mouse move
+ mbStartDockingEnabled = FALSE;
+}
+
+ImplDockingWindowWrapper::~ImplDockingWindowWrapper()
+{
+ if ( IsFloatingMode() )
+ {
+ GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE );
+ SetFloatingMode( FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplDockingWindowWrapper::ImplStartDocking( const Point& rPos )
+{
+ if ( !mbDockable )
+ return FALSE;
+
+ if( !mbStartDockingEnabled )
+ return FALSE;
+
+ maMouseOff = rPos;
+ maMouseStart = maMouseOff;
+ mbDocking = TRUE;
+ mbLastFloatMode = IsFloatingMode();
+ mbStartFloat = mbLastFloatMode;
+
+ // FloatingBorder berechnen
+ FloatingWindow* pWin;
+ if ( mpFloatWin )
+ pWin = mpFloatWin;
+ else
+ pWin = new ImplDockFloatWin2( mpParent, mnFloatBits, NULL );
+ pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom );
+ if ( !mpFloatWin )
+ delete pWin;
+
+ Point aPos = GetWindow()->ImplOutputToFrame( Point() );
+ Size aSize = GetWindow()->GetOutputSizePixel();
+ mnTrackX = aPos.X();
+ mnTrackY = aPos.Y();
+ mnTrackWidth = aSize.Width();
+ mnTrackHeight = aSize.Height();
+
+ if ( mbLastFloatMode )
+ {
+ maMouseOff.X() += mnDockLeft;
+ maMouseOff.Y() += mnDockTop;
+ mnTrackX -= mnDockLeft;
+ mnTrackY -= mnDockTop;
+ mnTrackWidth += mnDockLeft+mnDockRight;
+ mnTrackHeight += mnDockTop+mnDockBottom;
+ }
+
+ Window *pDockingArea = GetWindow()->GetParent();
+ Window::PointerState aState = pDockingArea->GetPointerState();
+
+ // mouse pos in screen pixels
+ Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos );
+ Point aDockPos = Point( pDockingArea->AbsoluteScreenToOutputPixel( GetWindow()->OutputToAbsoluteScreenPixel( GetWindow()->GetPosPixel() ) ) );
+ Rectangle aDockRect( aDockPos, GetWindow()->GetSizePixel() );
+ StartDocking( aMousePos, aDockRect );
+
+ GetWindow()->ImplUpdateAll();
+ GetWindow()->ImplGetFrameWindow()->ImplUpdateAll();
+
+ GetWindow()->StartTracking( STARTTRACK_KEYMOD );
+ return TRUE;
+}
+
+// =======================================================================
+
+void ImplDockingWindowWrapper::ImplInitData()
+{
+ mpDockingWindow = NULL;
+
+ //GetWindow()->mpWindowImpl->mbDockWin = TRUE; // TODO: must be eliminated
+ mpFloatWin = NULL;
+ mbDockCanceled = FALSE;
+ mbFloatPrevented = FALSE;
+ mbDocking = FALSE;
+ mbPined = FALSE;
+ mbRollUp = FALSE;
+ mbDockBtn = FALSE;
+ mbHideBtn = FALSE;
+ maMaxOutSize = Size( SHRT_MAX, SHRT_MAX );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::Tracking( const TrackingEvent& rTEvt )
+{
+ // used during docking of a currently docked window
+ if ( mbDocking )
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ mbDocking = FALSE;
+ GetWindow()->HideTracking();
+ if ( rTEvt.IsTrackingCanceled() )
+ {
+ mbDockCanceled = TRUE;
+ EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
+ mbDockCanceled = FALSE;
+ }
+ else
+ EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
+ }
+ // Docking only upon non-synthetic MouseEvents
+ else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() )
+ {
+ Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
+ Point aFrameMousePos = GetWindow()->ImplOutputToFrame( aMousePos );
+ Size aFrameSize = GetWindow()->ImplGetFrameWindow()->GetOutputSizePixel();
+ if ( aFrameMousePos.X() < 0 )
+ aFrameMousePos.X() = 0;
+ if ( aFrameMousePos.Y() < 0 )
+ aFrameMousePos.Y() = 0;
+ if ( aFrameMousePos.X() > aFrameSize.Width()-1 )
+ aFrameMousePos.X() = aFrameSize.Width()-1;
+ if ( aFrameMousePos.Y() > aFrameSize.Height()-1 )
+ aFrameMousePos.Y() = aFrameSize.Height()-1;
+ aMousePos = GetWindow()->ImplFrameToOutput( aFrameMousePos );
+ aMousePos.X() -= maMouseOff.X();
+ aMousePos.Y() -= maMouseOff.Y();
+ Point aPos = GetWindow()->ImplOutputToFrame( aMousePos );
+ Rectangle aTrackRect( aPos, Size( mnTrackWidth, mnTrackHeight ) );
+ Rectangle aCompRect = aTrackRect;
+ aPos.X() += maMouseOff.X();
+ aPos.Y() += maMouseOff.Y();
+
+ BOOL bFloatMode = Docking( aPos, aTrackRect );
+
+ mbFloatPrevented = FALSE;
+ if ( mbLastFloatMode != bFloatMode )
+ {
+ if ( bFloatMode )
+ {
+ aTrackRect.Left() -= mnDockLeft;
+ aTrackRect.Top() -= mnDockTop;
+ aTrackRect.Right() += mnDockRight;
+ aTrackRect.Bottom() += mnDockBottom;
+ }
+ else
+ {
+ if ( aCompRect == aTrackRect )
+ {
+ aTrackRect.Left() += mnDockLeft;
+ aTrackRect.Top() += mnDockTop;
+ aTrackRect.Right() -= mnDockRight;
+ aTrackRect.Bottom() -= mnDockBottom;
+ }
+ }
+ mbLastFloatMode = bFloatMode;
+ }
+
+ USHORT nTrackStyle;
+ if ( bFloatMode )
+ nTrackStyle = SHOWTRACK_OBJECT;
+ else
+ nTrackStyle = SHOWTRACK_BIG;
+ Rectangle aShowTrackRect = aTrackRect;
+ aShowTrackRect.SetPos( GetWindow()->ImplFrameToOutput( aShowTrackRect.TopLeft() ) );
+ //if( bFloatMode )
+ GetWindow()->ShowTracking( aShowTrackRect, nTrackStyle );
+ /*else
+ {
+ GetWindow()->HideTracking();
+ Point aPt( GetWindow()->GetParent()->ScreenToOutputPixel( aTrackRect.TopLeft() ) );
+ GetWindow()->SetPosPixel( aPt );
+ }*/
+
+ // Maus-Offset neu berechnen, da Rechteck veraendert werden
+ // konnte
+ maMouseOff.X() = aPos.X() - aTrackRect.Left();
+ maMouseOff.Y() = aPos.Y() - aTrackRect.Top();
+
+ mnTrackX = aTrackRect.Left();
+ mnTrackY = aTrackRect.Top();
+ mnTrackWidth = aTrackRect.GetWidth();
+ mnTrackHeight = aTrackRect.GetHeight();
+ }
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::StartDocking( const Point& rPoint, Rectangle& rRect )
+{
+ DockingData data( rPoint, rRect, IsFloatingMode() );
+
+ GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_STARTDOCKING, &data );
+ mbDocking = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplDockingWindowWrapper::Docking( const Point& rPoint, Rectangle& rRect )
+{
+ DockingData data( rPoint, rRect, IsFloatingMode() );
+
+ GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_DOCKING, &data );
+ rRect = data.maTrackRect;
+ return data.mbFloating;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::EndDocking( const Rectangle& rRect, BOOL bFloatMode )
+{
+ Rectangle aRect( rRect );
+
+ if ( !IsDockingCanceled() )
+ {
+ BOOL bShow = FALSE;
+ if ( bFloatMode != IsFloatingMode() )
+ {
+ GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE );
+ SetFloatingMode( bFloatMode );
+ bShow = TRUE;
+ if ( bFloatMode )
+ {
+ // #i44800# always use outputsize - as in all other places
+ mpFloatWin->SetOutputSizePixel( aRect.GetSize() );
+ mpFloatWin->SetPosPixel( aRect.TopLeft() );
+ }
+ }
+ if ( !bFloatMode )
+ {
+ Point aPos = aRect.TopLeft();
+ aPos = GetWindow()->GetParent()->ScreenToOutputPixel( aPos );
+ GetWindow()->SetPosSizePixel( aPos, aRect.GetSize() );
+ }
+
+ if ( bShow )
+ GetWindow()->Show( TRUE, SHOW_NOFOCUSCHANGE | SHOW_NOACTIVATE );
+ }
+
+ EndDockingData data( aRect, IsFloatingMode(), IsDockingCanceled() );
+ GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_ENDDOCKING, &data );
+
+ mbDocking = FALSE;
+
+ // must be enabled in Window::Notify to prevent permanent docking during mouse move
+ mbStartDockingEnabled = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplDockingWindowWrapper::PrepareToggleFloatingMode()
+{
+ BOOL bFloating = TRUE;
+ GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_PREPARETOGGLEFLOATING, &bFloating );
+ return bFloating;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplDockingWindowWrapper::Close()
+{
+ // TODO: send event
+/*
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE );
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ ImplRemoveDel( &aDelData );
+
+ if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() )
+ return FALSE;
+
+ GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE );
+ */
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::ToggleFloatingMode()
+{
+ // notify dockingwindow/toolbox
+ // note: this must be done *before* notifying the
+ // listeners to have the toolbox in the proper state
+ if( GetWindow()->ImplIsDockingWindow() )
+ ((DockingWindow*) GetWindow())->ToggleFloatingMode();
+
+ // now notify listeners
+ GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_TOGGLEFLOATING );
+
+ // must be enabled in Window::Notify to prevent permanent docking during mouse move
+ mbStartDockingEnabled = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::TitleButtonClick( USHORT nType )
+{
+ if( nType == TITLE_BUTTON_MENU )
+ {
+ ToolBox *pToolBox = dynamic_cast< ToolBox* >( GetWindow() );
+ if( pToolBox )
+ {
+ pToolBox->ExecuteCustomMenu();
+ }
+ }
+ if( nType == TITLE_BUTTON_DOCKING )
+ {
+ SetFloatingMode( !IsFloatingMode() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::Pin()
+{
+ // TODO: send event
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::Roll()
+{
+ // TODO: send event
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::PopupModeEnd()
+{
+ // TODO: send event
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::Resizing( Size& rSize )
+{
+ // TODO: add virtual Resizing() to class Window, so we can get rid of class DockingWindow
+ DockingWindow *pDockingWindow = dynamic_cast< DockingWindow* >( GetWindow() );
+ if( pDockingWindow )
+ pDockingWindow->Resizing( rSize );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::ShowTitleButton( USHORT nButton, BOOL bVisible )
+{
+ if ( mpFloatWin )
+ mpFloatWin->ShowTitleButton( nButton, bVisible );
+ else
+ {
+ if ( nButton == TITLE_BUTTON_DOCKING )
+ mbDockBtn = bVisible;
+ else // if ( nButton == TITLE_BUTTON_HIDE )
+ mbHideBtn = bVisible;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplDockingWindowWrapper::IsTitleButtonVisible( USHORT nButton ) const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->IsTitleButtonVisible( nButton );
+ else
+ {
+ if ( nButton == TITLE_BUTTON_DOCKING )
+ return mbDockBtn;
+ else // if ( nButton == TITLE_BUTTON_HIDE )
+ return mbHideBtn;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::StartPopupMode( ToolBox *pParentToolBox, ULONG nFlags )
+{
+ // do nothing if window is floating
+ if( IsFloatingMode() )
+ return;
+
+ GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ // prepare reparenting
+ Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT );
+ mpOldBorderWin = GetWindow()->GetWindow( WINDOW_BORDER );
+ if( mpOldBorderWin == GetWindow() )
+ mpOldBorderWin = NULL; // no border window found
+
+ // the new parent for popup mode
+ ImplPopupFloatWin* pWin = new ImplPopupFloatWin( mpParent, this, (nFlags & FLOATWIN_POPUPMODE_ALLOWTEAROFF) != 0 );
+
+ pWin->SetPopupModeEndHdl( LINK( this, ImplDockingWindowWrapper, PopupModeEnd ) );
+ pWin->SetText( GetWindow()->GetText() );
+
+ pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() );
+
+ GetWindow()->mpWindowImpl->mpBorderWindow = NULL;
+ GetWindow()->mpWindowImpl->mnLeftBorder = 0;
+ GetWindow()->mpWindowImpl->mnTopBorder = 0;
+ GetWindow()->mpWindowImpl->mnRightBorder = 0;
+ GetWindow()->mpWindowImpl->mnBottomBorder = 0;
+
+ // position toolbox below dragrect
+ GetWindow()->SetPosPixel( pWin->GetToolboxPosition() );
+
+ // reparent borderwindow and window
+ if ( mpOldBorderWin )
+ mpOldBorderWin->SetParent( pWin );
+ GetWindow()->SetParent( pWin );
+
+ // correct border window pointers
+ GetWindow()->mpWindowImpl->mpBorderWindow = pWin;
+ pWin->mpWindowImpl->mpClientWindow = GetWindow();
+ GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
+
+ // set mpFloatWin not until all window positioning is done !!!
+ // (SetPosPixel etc. check for valid mpFloatWin pointer)
+ mpFloatWin = pWin;
+
+ // if the subtoolbar was opened via keyboard make sure that key events
+ // will go into subtoolbar
+ if( pParentToolBox->IsKeyEvent() )
+ nFlags |= FLOATWIN_POPUPMODE_GRABFOCUS;
+
+ mpFloatWin->StartPopupMode( pParentToolBox, nFlags );
+ GetWindow()->Show();
+
+ if( pParentToolBox->IsKeyEvent() )
+ {
+ // send HOME key to subtoolbar in order to select first item
+ KeyEvent aEvent( 0, KeyCode( KEY_HOME ) );
+ mpFloatWin->GetPreferredKeyInputWindow()->KeyInput( aEvent );
+ }
+}
+
+IMPL_LINK( ImplDockingWindowWrapper, PopupModeEnd, void*, EMPTYARG )
+{
+ GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ // set parameter for handler before destroying floating window
+ ImplPopupFloatWin *pPopupFloatWin = (ImplPopupFloatWin*) mpFloatWin;
+ EndPopupModeData aData( pPopupFloatWin->GetTearOffPosition(), mpFloatWin->IsPopupModeTearOff() );
+
+ // before deleting change parent back, so we can delete the floating window alone
+ Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT );
+ GetWindow()->mpWindowImpl->mpBorderWindow = NULL;
+ if ( mpOldBorderWin )
+ {
+ GetWindow()->SetParent( mpOldBorderWin );
+ ((ImplBorderWindow*)mpOldBorderWin)->GetBorder(
+ GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder,
+ GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder );
+ mpOldBorderWin->Resize();
+ }
+ GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin;
+ GetWindow()->SetParent( pRealParent );
+ GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
+
+ delete mpFloatWin;
+ mpFloatWin = NULL;
+
+ // call handler - which will destroy the window and thus the wrapper as well !
+ GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_ENDPOPUPMODE, &aData );
+
+ return 0;
+}
+
+
+BOOL ImplDockingWindowWrapper::IsInPopupMode() const
+{
+ if( GetFloatingWindow() )
+ return GetFloatingWindow()->IsInPopupMode();
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::SetFloatingMode( BOOL bFloatMode )
+{
+ // do nothing if window is docked and locked
+ if( !IsFloatingMode() && IsLocked() )
+ return;
+
+ if ( IsFloatingMode() != bFloatMode )
+ {
+ if ( PrepareToggleFloatingMode() )
+ {
+ BOOL bVisible = GetWindow()->IsVisible();
+
+ if ( bFloatMode )
+ {
+ GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ maDockPos = GetWindow()->GetPosPixel();
+
+ Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT );
+ mpOldBorderWin = GetWindow()->GetWindow( WINDOW_BORDER );
+ if( mpOldBorderWin == mpDockingWindow )
+ mpOldBorderWin = NULL; // no border window found
+
+ ImplDockFloatWin2* pWin =
+ new ImplDockFloatWin2(
+ mpParent,
+ mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ?
+ mnFloatBits | WB_SYSTEMWINDOW
+//#ifdef __USE_OWNERDRAWDECORATION__
+ | WB_OWNERDRAWDECORATION
+//#endif
+ : mnFloatBits,
+ this );
+
+ // reduce the border width for seamless NWF painting
+ // (especially for the toolbar gradient on Windows XP)
+ /*AllSettings aSettings( pWin->GetSettings() );
+ StyleSettings aStyleSettings( aSettings.GetStyleSettings() );
+ aStyleSettings.SetBorderSize( 0 );
+ aSettings.SetStyleSettings( aStyleSettings );
+ pWin->SetSettings( aSettings );*/
+
+// mpFloatWin = pWin;
+
+
+ GetWindow()->mpWindowImpl->mpBorderWindow = NULL;
+ GetWindow()->mpWindowImpl->mnLeftBorder = 0;
+ GetWindow()->mpWindowImpl->mnTopBorder = 0;
+ GetWindow()->mpWindowImpl->mnRightBorder = 0;
+ GetWindow()->mpWindowImpl->mnBottomBorder = 0;
+
+ // Falls Parent zerstoert wird, muessen wir auch vom
+ // BorderWindow den Parent umsetzen
+ if ( mpOldBorderWin )
+ mpOldBorderWin->SetParent( pWin );
+ GetWindow()->SetParent( pWin );
+ pWin->SetPosPixel( Point() );
+
+ GetWindow()->mpWindowImpl->mpBorderWindow = pWin;
+ pWin->mpWindowImpl->mpClientWindow = mpDockingWindow;
+ GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
+
+ pWin->SetText( GetWindow()->GetText() );
+ pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() );
+ pWin->SetPosPixel( maFloatPos );
+ // DockingDaten ans FloatingWindow weiterreichen
+ pWin->ShowTitleButton( TITLE_BUTTON_DOCKING, mbDockBtn );
+ pWin->ShowTitleButton( TITLE_BUTTON_HIDE, mbHideBtn );
+ pWin->SetPin( mbPined );
+ if ( mbRollUp )
+ pWin->RollUp();
+ else
+ pWin->RollDown();
+ pWin->SetRollUpOutputSizePixel( maRollUpOutSize );
+ pWin->SetMinOutputSizePixel( maMinOutSize );
+ pWin->SetMaxOutputSizePixel( maMaxOutSize );
+
+ mpFloatWin = pWin;
+
+ if ( bVisible )
+ GetWindow()->Show( TRUE, SHOW_NOFOCUSCHANGE | SHOW_NOACTIVATE );
+
+ ToggleFloatingMode();
+ }
+ else
+ {
+ GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ // FloatingDaten wird im FloatingWindow speichern
+ maFloatPos = mpFloatWin->GetPosPixel();
+ mbDockBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_DOCKING );
+ mbHideBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_HIDE );
+ mbPined = mpFloatWin->IsPined();
+ mbRollUp = mpFloatWin->IsRollUp();
+ maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel();
+ maMinOutSize = mpFloatWin->GetMinOutputSizePixel();
+ maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel();
+
+ Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT ); //mpWindowImpl->mpRealParent;
+ GetWindow()->mpWindowImpl->mpBorderWindow = NULL;
+ if ( mpOldBorderWin )
+ {
+ GetWindow()->SetParent( mpOldBorderWin );
+ ((ImplBorderWindow*)mpOldBorderWin)->GetBorder(
+ GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder,
+ GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder );
+ mpOldBorderWin->Resize();
+ }
+ GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin;
+ GetWindow()->SetParent( pRealParent );
+ GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
+
+ delete static_cast<ImplDockFloatWin2*>(mpFloatWin);
+ mpFloatWin = NULL;
+ GetWindow()->SetPosPixel( maDockPos );
+
+ if ( bVisible )
+ GetWindow()->Show();
+
+ ToggleFloatingMode();
+
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::SetFloatStyle( WinBits nStyle )
+{
+ mnFloatBits = nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+WinBits ImplDockingWindowWrapper::GetFloatStyle() const
+{
+ return mnFloatBits;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::SetTabStop()
+{
+ GetWindow()->SetStyle( GetWindow()->GetStyle() | (WB_GROUP | WB_TABSTOP) );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+ else
+ GetWindow()->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+Point ImplDockingWindowWrapper::GetPosPixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetPosPixel();
+ else
+ return mpDockingWindow->GetPosPixel();
+}
+
+// -----------------------------------------------------------------------
+
+Size ImplDockingWindowWrapper::GetSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetSizePixel();
+ else
+ return mpDockingWindow->GetSizePixel();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::SetOutputSizePixel( const Size& rNewSize )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetOutputSizePixel( rNewSize );
+ else
+ GetWindow()->SetOutputSizePixel( rNewSize );
+}
+
+// -----------------------------------------------------------------------
+
+Size ImplDockingWindowWrapper::GetOutputSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetOutputSizePixel();
+ else
+ return mpDockingWindow->GetOutputSizePixel();
+}
+
+Point ImplDockingWindowWrapper::GetFloatingPos() const
+{
+ if ( mpFloatWin )
+ {
+ //Rectangle aRect = mpFloatWin->GetWindow( WINDOW_CLIENT)->GetWindowExtentsRelative( mpFloatWin->GetParent() );
+ WindowStateData aData;
+ aData.SetMask( WINDOWSTATE_MASK_POS );
+ mpFloatWin->GetWindowStateData( aData );
+ Point aPos( aData.GetX(), aData.GetY() );
+ aPos = mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
+ return aPos;
+ }
+ else
+ return maFloatPos;
+}
+
+// -----------------------------------------------------------------------
+// old inlines from DockingWindow
+// -----------------------------------------------------------------------
+
+void ImplDockingWindowWrapper::SetPin( BOOL bPin )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetPin( bPin );
+ mbPined = bPin;
+}
+
+BOOL ImplDockingWindowWrapper::IsPined() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->IsPined();
+ return mbPined;
+}
+
+void ImplDockingWindowWrapper::RollUp()
+{
+ if ( mpFloatWin )
+ mpFloatWin->RollUp();
+ mbRollUp = TRUE;
+}
+
+void ImplDockingWindowWrapper::RollDown()
+{
+ if ( mpFloatWin )
+ mpFloatWin->RollDown();
+ mbRollUp = FALSE;
+}
+
+BOOL ImplDockingWindowWrapper::IsRollUp() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->IsRollUp();
+ return mbRollUp;
+}
+
+void ImplDockingWindowWrapper::SetRollUpOutputSizePixel( const Size& rSize )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetRollUpOutputSizePixel( rSize );
+ maRollUpOutSize = rSize;
+}
+
+Size ImplDockingWindowWrapper::GetRollUpOutputSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetRollUpOutputSizePixel();
+ return maRollUpOutSize;
+}
+
+void ImplDockingWindowWrapper::SetMinOutputSizePixel( const Size& rSize )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetMinOutputSizePixel( rSize );
+ maMinOutSize = rSize;
+}
+
+void ImplDockingWindowWrapper::SetMaxOutputSizePixel( const Size& rSize )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetMaxOutputSizePixel( rSize );
+ maMaxOutSize = rSize;
+}
+
+const Size& ImplDockingWindowWrapper::GetMinOutputSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetMinOutputSizePixel();
+ return maMinOutSize;
+}
+
+const Size& ImplDockingWindowWrapper::GetMaxOutputSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetMaxOutputSizePixel();
+ return maMaxOutSize;
+}
+
+void ImplDockingWindowWrapper::SetFloatingPos( const Point& rNewPos )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetPosPixel( rNewPos );
+ else
+ maFloatPos = rNewPos;
+}
+
+BOOL ImplDockingWindowWrapper::IsFloatingMode() const
+{
+ return (mpFloatWin != NULL);
+}
+
+
+void ImplDockingWindowWrapper::SetDragArea( const Rectangle& rRect )
+{
+ maDragArea = rRect;
+}
+
+Rectangle ImplDockingWindowWrapper::GetDragArea() const
+{
+ return maDragArea;
+}
+
+void ImplDockingWindowWrapper::Lock()
+{
+ mbLocked = TRUE;
+ // only toolbars support locking
+ ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() );
+ if( pToolBox )
+ pToolBox->Lock( mbLocked );
+}
+
+void ImplDockingWindowWrapper::Unlock()
+{
+ mbLocked = FALSE;
+ // only toolbars support locking
+ ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() );
+ if( pToolBox )
+ pToolBox->Lock( mbLocked );
+}
+
+BOOL ImplDockingWindowWrapper::IsLocked() const
+{
+ return mbLocked;
+}
diff --git a/vcl/source/window/dockwin.cxx b/vcl/source/window/dockwin.cxx
new file mode 100644
index 000000000000..c8e382bad982
--- /dev/null
+++ b/vcl/source/window/dockwin.cxx
@@ -0,0 +1,1120 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <tools/time.hxx>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/event.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/dockwin.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/window.h>
+#include <vcl/unowrap.hxx>
+#include <vcl/salframe.hxx>
+
+
+
+// =======================================================================
+
+#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_PINABLE | WB_ROLLABLE )
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+
+class DockingWindow::ImplData
+{
+public:
+ ImplData();
+ ~ImplData();
+
+ Window* mpParent;
+ Size maMaxOutSize;
+};
+
+DockingWindow::ImplData::ImplData()
+{
+ mpParent = NULL;
+ maMaxOutSize = Size( SHRT_MAX, SHRT_MAX );
+}
+
+DockingWindow::ImplData::~ImplData()
+{
+}
+
+// -----------------------------------------------------------------------
+
+class ImplDockFloatWin : public FloatingWindow
+{
+private:
+ DockingWindow* mpDockWin;
+ ULONG mnLastTicks;
+ Timer maDockTimer;
+ Point maDockPos;
+ Rectangle maDockRect;
+ BOOL mbInMove;
+ ULONG mnLastUserEvent;
+
+ DECL_LINK( DockingHdl, ImplDockFloatWin* );
+ DECL_LINK( DockTimerHdl, ImplDockFloatWin* );
+public:
+ ImplDockFloatWin( Window* pParent, WinBits nWinBits,
+ DockingWindow* pDockingWin );
+ ~ImplDockFloatWin();
+
+ virtual void Move();
+ virtual void Resize();
+ virtual void TitleButtonClick( USHORT nButton );
+ virtual void Pin();
+ virtual void Roll();
+ virtual void PopupModeEnd();
+ virtual void Resizing( Size& rSize );
+ virtual BOOL Close();
+
+ ULONG GetLastTicks() const { return mnLastTicks; }
+};
+
+
+ImplDockFloatWin::ImplDockFloatWin( Window* pParent, WinBits nWinBits,
+ DockingWindow* pDockingWin ) :
+ FloatingWindow( pParent, nWinBits ),
+ mpDockWin( pDockingWin ),
+ mnLastTicks( Time::GetSystemTicks() ),
+ mbInMove( FALSE ),
+ mnLastUserEvent( 0 )
+{
+ // Daten vom DockingWindow uebernehmen
+ if ( pDockingWin )
+ {
+ SetSettings( pDockingWin->GetSettings() );
+ Enable( pDockingWin->IsEnabled(), FALSE );
+ EnableInput( pDockingWin->IsInputEnabled(), FALSE );
+ AlwaysEnableInput( pDockingWin->IsAlwaysEnableInput(), FALSE );
+ EnableAlwaysOnTop( pDockingWin->IsAlwaysOnTopEnabled() );
+ SetActivateMode( pDockingWin->GetActivateMode() );
+ }
+
+ SetBackground();
+
+ maDockTimer.SetTimeoutHdl( LINK( this, ImplDockFloatWin, DockTimerHdl ) );
+ maDockTimer.SetTimeout( 50 );
+}
+
+// -----------------------------------------------------------------------
+
+ImplDockFloatWin::~ImplDockFloatWin()
+{
+ if( mnLastUserEvent )
+ Application::RemoveUserEvent( mnLastUserEvent );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplDockFloatWin, DockTimerHdl, ImplDockFloatWin*, EMPTYARG )
+{
+ DBG_ASSERT( mpDockWin->IsFloatingMode(), "docktimer called but not floating" );
+
+ maDockTimer.Stop();
+ PointerState aState = GetPointerState();
+
+ if( aState.mnState & KEY_MOD1 )
+ {
+ // i43499 CTRL disables docking now
+ mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
+ mpDockWin->EndDocking( maDockRect, TRUE );
+ if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
+ maDockTimer.Start();
+ }
+ else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
+ {
+ mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
+ mpDockWin->EndDocking( maDockRect, FALSE );
+ }
+ else
+ {
+ mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_BIG | SHOWTRACK_WINDOW );
+ maDockTimer.Start();
+ }
+
+ return 0;
+}
+
+IMPL_LINK( ImplDockFloatWin, DockingHdl, ImplDockFloatWin*, EMPTYARG )
+{
+ PointerState aState = mpDockWin->GetParent()->GetPointerState();
+
+ mnLastUserEvent = 0;
+ if( mpDockWin->IsDockable() &&
+ (Time::GetSystemTicks() - mnLastTicks > 500) &&
+ ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) &&
+ !(aState.mnState & KEY_MOD1) ) // i43499 CTRL disables docking now
+ {
+ maDockPos = Point( mpDockWin->GetParent()->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) );
+ maDockPos = mpDockWin->GetParent()->OutputToScreenPixel( maDockPos ); // sfx expects screen coordinates
+
+ if( ! mpDockWin->IsDocking() )
+ mpDockWin->StartDocking();
+ maDockRect = Rectangle( maDockPos, mpDockWin->GetSizePixel() );
+
+ // mouse pos also in screen pixels
+ Point aMousePos = mpDockWin->GetParent()->OutputToScreenPixel( aState.maPos );
+
+ BOOL bFloatMode = mpDockWin->Docking( aMousePos, maDockRect );
+ if( ! bFloatMode )
+ {
+ mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_OBJECT | SHOWTRACK_WINDOW );
+ DockTimerHdl( this );
+ }
+ else
+ {
+ mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking();
+ maDockTimer.Stop();
+ mpDockWin->EndDocking( maDockRect, TRUE );
+ }
+ }
+ mbInMove = FALSE;
+ return 0;
+}
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin::Move()
+{
+ if( mbInMove )
+ return;
+
+ mbInMove = TRUE;
+ FloatingWindow::Move();
+ mpDockWin->Move();
+
+ /*
+ * note: the window should only dock if
+ * the user releases all mouse buttons. The real problem here
+ * is that we don't get mouse events (at least not on X)
+ * if the mouse is on the decoration. So we have to start an
+ * awkward timer based process that polls the modifier/buttons
+ * to see whether they are in the right condition shortly after the
+ * last Move message.
+ */
+ if( ! mnLastUserEvent )
+ mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin, DockingHdl ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin::Resize()
+{
+ FloatingWindow::Resize();
+ Size aSize( GetSizePixel() );
+ mpDockWin->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), WINDOW_POSSIZE_POSSIZE );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin::TitleButtonClick( USHORT nButton )
+{
+ FloatingWindow::TitleButtonClick( nButton );
+ mpDockWin->TitleButtonClick( nButton );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin::Pin()
+{
+ FloatingWindow::Pin();
+ mpDockWin->Pin();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin::Roll()
+{
+ FloatingWindow::Roll();
+ mpDockWin->Roll();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin::PopupModeEnd()
+{
+ FloatingWindow::PopupModeEnd();
+ mpDockWin->PopupModeEnd();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDockFloatWin::Resizing( Size& rSize )
+{
+ FloatingWindow::Resizing( rSize );
+ mpDockWin->Resizing( rSize );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplDockFloatWin::Close()
+{
+ return mpDockWin->Close();
+}
+
+// =======================================================================
+
+BOOL DockingWindow::ImplStartDocking( const Point& rPos )
+{
+ if ( !mbDockable )
+ return FALSE;
+
+ maMouseOff = rPos;
+ maMouseStart = maMouseOff;
+ mbDocking = TRUE;
+ mbLastFloatMode = IsFloatingMode();
+ mbStartFloat = mbLastFloatMode;
+
+ // FloatingBorder berechnen
+ FloatingWindow* pWin;
+ if ( mpFloatWin )
+ pWin = mpFloatWin;
+ else
+ pWin = new ImplDockFloatWin( mpImplData->mpParent, mnFloatBits, NULL );
+ pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom );
+ if ( !mpFloatWin )
+ delete pWin;
+
+ Point aPos = ImplOutputToFrame( Point() );
+ Size aSize = Window::GetOutputSizePixel();
+ mnTrackX = aPos.X();
+ mnTrackY = aPos.Y();
+ mnTrackWidth = aSize.Width();
+ mnTrackHeight = aSize.Height();
+
+ if ( mbLastFloatMode )
+ {
+ maMouseOff.X() += mnDockLeft;
+ maMouseOff.Y() += mnDockTop;
+ mnTrackX -= mnDockLeft;
+ mnTrackY -= mnDockTop;
+ mnTrackWidth += mnDockLeft+mnDockRight;
+ mnTrackHeight += mnDockTop+mnDockBottom;
+ }
+
+ if ( GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_DOCKING &&
+ !( mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ) ) // no full drag when migrating to system window
+ mbDragFull = TRUE;
+ else
+ {
+ StartDocking();
+ mbDragFull = FALSE;
+ ImplUpdateAll();
+ ImplGetFrameWindow()->ImplUpdateAll();
+ }
+
+ StartTracking( STARTTRACK_KEYMOD );
+ return TRUE;
+}
+
+// =======================================================================
+
+void DockingWindow::ImplInitDockingWindowData()
+{
+ mpImplData = new ImplData;
+ mpWindowImpl->mbDockWin = TRUE;
+
+ mpFloatWin = NULL;
+ mbDockCanceled = FALSE;
+ mbDockPrevented = FALSE;
+ mbFloatPrevented = FALSE;
+ mbDocking = FALSE;
+ mbPined = FALSE;
+ mbRollUp = FALSE;
+ mbDockBtn = FALSE;
+ mbHideBtn = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::ImplInit( Window* pParent, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NODIALOGCONTROL) )
+ nStyle |= WB_DIALOGCONTROL;
+
+ mpImplData->mpParent = pParent;
+ mbDockable = (nStyle & WB_DOCKABLE) != 0;
+ mnFloatBits = WB_BORDER | (nStyle & DOCKWIN_FLOATSTYLES);
+ nStyle &= ~(DOCKWIN_FLOATSTYLES | WB_BORDER);
+ if ( nStyle & WB_DOCKBORDER )
+ nStyle |= WB_BORDER;
+
+ Window::ImplInit( pParent, nStyle, NULL );
+
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::ImplInitSettings()
+{
+ // Hack, damit man auch DockingWindows ohne Hintergrund bauen kann
+ // und noch nicht alles umgestellt ist
+ if ( IsBackground() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ Color aColor;
+ if ( IsControlBackground() )
+ aColor = GetControlBackground();
+ else if ( Window::GetStyle() & WB_3DLOOK )
+ aColor = rStyleSettings.GetFaceColor();
+ else
+ aColor = rStyleSettings.GetWindowColor();
+ SetBackground( aColor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::ImplLoadRes( const ResId& rResId )
+{
+ Window::ImplLoadRes( rResId );
+
+ ULONG nMask = ReadLongRes();
+
+ if ( (RSC_DOCKINGWINDOW_XYMAPMODE | RSC_DOCKINGWINDOW_X |
+ RSC_DOCKINGWINDOW_Y) & nMask )
+ {
+ // Groessenangabe aus der Resource verwenden
+ Point aPos;
+ MapUnit ePosMap = MAP_PIXEL;
+
+ if ( RSC_DOCKINGWINDOW_XYMAPMODE & nMask )
+ ePosMap = (MapUnit)ReadLongRes();
+
+ if ( RSC_DOCKINGWINDOW_X & nMask )
+ {
+ aPos.X() = ReadShortRes();
+ aPos.X() = ImplLogicUnitToPixelX( aPos.X(), ePosMap );
+ }
+
+ if ( RSC_DOCKINGWINDOW_Y & nMask )
+ {
+ aPos.Y() = ReadShortRes();
+ aPos.Y() = ImplLogicUnitToPixelY( aPos.Y(), ePosMap );
+ }
+
+ SetFloatingPos( aPos );
+ }
+
+ if ( nMask & RSC_DOCKINGWINDOW_FLOATING )
+ {
+ if ( (BOOL)ReadShortRes() )
+ SetFloatingMode( TRUE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+DockingWindow::DockingWindow( WindowType nType ) :
+ Window( nType )
+{
+ ImplInitDockingWindowData();
+}
+
+// -----------------------------------------------------------------------
+
+DockingWindow::DockingWindow( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_DOCKINGWINDOW )
+{
+ ImplInitDockingWindowData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+DockingWindow::DockingWindow( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_DOCKINGWINDOW )
+{
+ ImplInitDockingWindowData();
+ rResId.SetRT( RSC_DOCKINGWINDOW );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+DockingWindow::~DockingWindow()
+{
+ if ( IsFloatingMode() )
+ {
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+ SetFloatingMode( FALSE );
+ }
+ delete mpImplData;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::Tracking( const TrackingEvent& rTEvt )
+{
+ if( GetDockingManager()->IsDockable( this ) ) // new docking interface
+ return Window::Tracking( rTEvt );
+
+ if ( mbDocking )
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ mbDocking = FALSE;
+ if ( mbDragFull )
+ {
+ // Bei Abbruch alten Zustand wieder herstellen
+ if ( rTEvt.IsTrackingCanceled() )
+ {
+ StartDocking();
+ Rectangle aRect( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) );
+ EndDocking( aRect, mbStartFloat );
+ }
+ }
+ else
+ {
+ HideTracking();
+ if ( rTEvt.IsTrackingCanceled() )
+ {
+ mbDockCanceled = TRUE;
+ EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
+ mbDockCanceled = FALSE;
+ }
+ else
+ EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
+ }
+ }
+ // Docking nur bei nicht synthetischen MouseEvents
+ else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() )
+ {
+ Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
+ Point aFrameMousePos = ImplOutputToFrame( aMousePos );
+ Size aFrameSize = mpWindowImpl->mpFrameWindow->GetOutputSizePixel();
+ if ( aFrameMousePos.X() < 0 )
+ aFrameMousePos.X() = 0;
+ if ( aFrameMousePos.Y() < 0 )
+ aFrameMousePos.Y() = 0;
+ if ( aFrameMousePos.X() > aFrameSize.Width()-1 )
+ aFrameMousePos.X() = aFrameSize.Width()-1;
+ if ( aFrameMousePos.Y() > aFrameSize.Height()-1 )
+ aFrameMousePos.Y() = aFrameSize.Height()-1;
+ aMousePos = ImplFrameToOutput( aFrameMousePos );
+ aMousePos.X() -= maMouseOff.X();
+ aMousePos.Y() -= maMouseOff.Y();
+ Point aFramePos = ImplOutputToFrame( aMousePos );
+ Rectangle aTrackRect( aFramePos, Size( mnTrackWidth, mnTrackHeight ) );
+ Rectangle aCompRect = aTrackRect;
+ aFramePos.X() += maMouseOff.X();
+ aFramePos.Y() += maMouseOff.Y();
+ if ( mbDragFull )
+ StartDocking();
+ BOOL bFloatMode = Docking( aFramePos, aTrackRect );
+ mbDockPrevented = FALSE;
+ mbFloatPrevented = FALSE;
+ if ( mbLastFloatMode != bFloatMode )
+ {
+ if ( bFloatMode )
+ {
+ aTrackRect.Left() -= mnDockLeft;
+ aTrackRect.Top() -= mnDockTop;
+ aTrackRect.Right() += mnDockRight;
+ aTrackRect.Bottom() += mnDockBottom;
+ }
+ else
+ {
+ if ( aCompRect == aTrackRect )
+ {
+ aTrackRect.Left() += mnDockLeft;
+ aTrackRect.Top() += mnDockTop;
+ aTrackRect.Right() -= mnDockRight;
+ aTrackRect.Bottom() -= mnDockBottom;
+ }
+ }
+ mbLastFloatMode = bFloatMode;
+ }
+ if ( mbDragFull )
+ {
+ Point aPos;
+ Point aOldPos = OutputToScreenPixel( aPos );
+ EndDocking( aTrackRect, mbLastFloatMode );
+ // Wenn der Status bzw. die Position sich
+ // geaendert hat, dann neu ausgeben
+ if ( aOldPos != OutputToScreenPixel( aPos ) )
+ {
+ ImplUpdateAll();
+ ImplGetFrameWindow()->ImplUpdateAll();
+ }
+// EndDocking( aTrackRect, mbLastFloatMode );
+ }
+ else
+ {
+ USHORT nTrackStyle;
+ if ( bFloatMode )
+ nTrackStyle = SHOWTRACK_BIG;
+ else
+ nTrackStyle = SHOWTRACK_OBJECT;
+ Rectangle aShowTrackRect = aTrackRect;
+ aShowTrackRect.SetPos( ImplFrameToOutput( aShowTrackRect.TopLeft() ) );
+ ShowTracking( aShowTrackRect, nTrackStyle );
+
+ // Maus-Offset neu berechnen, da Rechteck veraendert werden
+ // konnte
+ maMouseOff.X() = aFramePos.X() - aTrackRect.Left();
+ maMouseOff.Y() = aFramePos.Y() - aTrackRect.Top();
+ }
+
+ mnTrackX = aTrackRect.Left();
+ mnTrackY = aTrackRect.Top();
+ mnTrackWidth = aTrackRect.GetWidth();
+ mnTrackHeight = aTrackRect.GetHeight();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long DockingWindow::Notify( NotifyEvent& rNEvt )
+{
+ if( GetDockingManager()->IsDockable( this ) ) // new docking interface
+ return Window::Notify( rNEvt );
+
+ if ( mbDockable )
+ {
+ if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN )
+ {
+ const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
+ if ( pMEvt->IsLeft() )
+ {
+ if ( pMEvt->IsMod1() && (pMEvt->GetClicks() == 2) )
+ {
+ SetFloatingMode( !IsFloatingMode() );
+ return TRUE;
+ }
+ else if ( pMEvt->GetClicks() == 1 )
+ {
+ // check if window is floating standalone (IsFloating())
+ // or only partially floating and still docked with one border
+ // ( !mpWindowImpl->mbFrame)
+ if( ! IsFloatingMode() || ! mpFloatWin->mpWindowImpl->mbFrame )
+ {
+ Point aPos = pMEvt->GetPosPixel();
+ Window* pWindow = rNEvt.GetWindow();
+ if ( pWindow != this )
+ {
+ aPos = pWindow->OutputToScreenPixel( aPos );
+ aPos = ScreenToOutputPixel( aPos );
+ }
+ ImplStartDocking( aPos );
+ }
+ return TRUE;
+ }
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ const KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode();
+ if( rKey.GetCode() == KEY_F10 && rKey.GetModifier() &&
+ rKey.IsShift() && rKey.IsMod1() )
+ {
+ SetFloatingMode( !IsFloatingMode() );
+ return TRUE;
+ }
+ }
+ }
+
+ return Window::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::StartDocking()
+{
+ mbDocking = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DockingWindow::Docking( const Point&, Rectangle& )
+{
+ return IsFloatingMode();
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::EndDocking( const Rectangle& rRect, BOOL bFloatMode )
+{
+ if ( !IsDockingCanceled() )
+ {
+ BOOL bShow = FALSE;
+ if ( bFloatMode != IsFloatingMode() )
+ {
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+ SetFloatingMode( bFloatMode );
+ bShow = TRUE;
+ if ( bFloatMode && mpFloatWin )
+ mpFloatWin->SetPosSizePixel( rRect.TopLeft(), rRect.GetSize() );
+ }
+ if ( !bFloatMode )
+ {
+ Point aPos = rRect.TopLeft();
+ aPos = GetParent()->ScreenToOutputPixel( aPos );
+ Window::SetPosSizePixel( aPos, rRect.GetSize() );
+ }
+
+ if ( bShow )
+ Show();
+ }
+ mbDocking = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DockingWindow::PrepareToggleFloatingMode()
+{
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DockingWindow::Close()
+{
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE );
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ ImplRemoveDel( &aDelData );
+
+ if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() )
+ return FALSE;
+
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::ToggleFloatingMode()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::TitleButtonClick( USHORT )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::Pin()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::Roll()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::PopupModeEnd()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::Resizing( Size& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+
+ Window::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+ else
+ Window::DataChanged( rDCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::ShowTitleButton( USHORT nButton, BOOL bVisible )
+{
+ if ( mpFloatWin )
+ mpFloatWin->ShowTitleButton( nButton, bVisible );
+ else
+ {
+ if ( nButton == TITLE_BUTTON_DOCKING )
+ mbDockBtn = bVisible;
+ else /* if ( nButton == TITLE_BUTTON_HIDE ) */
+ mbHideBtn = bVisible;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL DockingWindow::IsTitleButtonVisible( USHORT nButton ) const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->IsTitleButtonVisible( nButton );
+ else
+ {
+ if ( nButton == TITLE_BUTTON_DOCKING )
+ return mbDockBtn;
+ else /* if ( nButton == TITLE_BUTTON_HIDE ) */
+ return mbHideBtn;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::SetFloatingMode( BOOL bFloatMode )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ pWrapper->SetFloatingMode( bFloatMode );
+ return;
+ }
+ if ( IsFloatingMode() != bFloatMode )
+ {
+ if ( PrepareToggleFloatingMode() ) // changes to floating mode can be vetoed
+ {
+ BOOL bVisible = IsVisible();
+
+ if ( bFloatMode )
+ {
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ maDockPos = Window::GetPosPixel();
+
+ Window* pRealParent = mpWindowImpl->mpRealParent;
+ mpOldBorderWin = mpWindowImpl->mpBorderWindow;
+
+ ImplDockFloatWin* pWin =
+ new ImplDockFloatWin(
+ mpImplData->mpParent,
+ mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? mnFloatBits | WB_SYSTEMWINDOW : mnFloatBits,
+ this );
+ mpFloatWin = pWin;
+ mpWindowImpl->mpBorderWindow = NULL;
+ mpWindowImpl->mnLeftBorder = 0;
+ mpWindowImpl->mnTopBorder = 0;
+ mpWindowImpl->mnRightBorder = 0;
+ mpWindowImpl->mnBottomBorder = 0;
+ // Falls Parent zerstoert wird, muessen wir auch vom
+ // BorderWindow den Parent umsetzen
+ if ( mpOldBorderWin )
+ mpOldBorderWin->SetParent( pWin );
+ SetParent( pWin );
+ SetPosPixel( Point() );
+ mpWindowImpl->mpBorderWindow = pWin;
+ pWin->mpWindowImpl->mpClientWindow = this;
+ mpWindowImpl->mpRealParent = pRealParent;
+ pWin->SetText( Window::GetText() );
+ pWin->SetOutputSizePixel( Window::GetSizePixel() );
+ pWin->SetPosPixel( maFloatPos );
+ // DockingDaten ans FloatingWindow weiterreichen
+ pWin->ShowTitleButton( TITLE_BUTTON_DOCKING, mbDockBtn );
+ pWin->ShowTitleButton( TITLE_BUTTON_HIDE, mbHideBtn );
+ pWin->SetPin( mbPined );
+ if ( mbRollUp )
+ pWin->RollUp();
+ else
+ pWin->RollDown();
+ pWin->SetRollUpOutputSizePixel( maRollUpOutSize );
+ pWin->SetMinOutputSizePixel( maMinOutSize );
+ pWin->SetMaxOutputSizePixel( mpImplData->maMaxOutSize );
+
+ ToggleFloatingMode();
+
+ if ( bVisible )
+ Show();
+ }
+ else
+ {
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ // FloatingDaten wird im FloatingWindow speichern
+ maFloatPos = mpFloatWin->GetPosPixel();
+ mbDockBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_DOCKING );
+ mbHideBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_HIDE );
+ mbPined = mpFloatWin->IsPined();
+ mbRollUp = mpFloatWin->IsRollUp();
+ maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel();
+ maMinOutSize = mpFloatWin->GetMinOutputSizePixel();
+ mpImplData->maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel();
+
+ Window* pRealParent = mpWindowImpl->mpRealParent;
+ mpWindowImpl->mpBorderWindow = NULL;
+ if ( mpOldBorderWin )
+ {
+ SetParent( mpOldBorderWin );
+ ((ImplBorderWindow*)mpOldBorderWin)->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ mpOldBorderWin->Resize();
+ }
+ mpWindowImpl->mpBorderWindow = mpOldBorderWin;
+ SetParent( pRealParent );
+ mpWindowImpl->mpRealParent = pRealParent;
+ delete static_cast<ImplDockFloatWin*>(mpFloatWin);
+ mpFloatWin = NULL;
+ SetPosPixel( maDockPos );
+
+ ToggleFloatingMode();
+
+ if ( bVisible )
+ Show();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::SetFloatStyle( WinBits nStyle )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ pWrapper->SetFloatStyle( nStyle );
+ return;
+ }
+
+ mnFloatBits = nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+WinBits DockingWindow::GetFloatStyle() const
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ return pWrapper->GetFloatStyle();
+ }
+
+ return mnFloatBits;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::SetTabStop()
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ pWrapper->SetTabStop();
+ return;
+ }
+
+ mpWindowImpl->mnStyle |= WB_GROUP | WB_TABSTOP;
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ if ( pWrapper->mpFloatWin )
+ pWrapper->mpFloatWin->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+ else
+ Window::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+ return;
+ }
+
+ if ( mpFloatWin )
+ mpFloatWin->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+ else
+ Window::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+Point DockingWindow::GetPosPixel() const
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ if ( pWrapper->mpFloatWin )
+ return pWrapper->mpFloatWin->GetPosPixel();
+ else
+ return Window::GetPosPixel();
+ }
+
+ if ( mpFloatWin )
+ return mpFloatWin->GetPosPixel();
+ else
+ return Window::GetPosPixel();
+}
+
+// -----------------------------------------------------------------------
+
+Size DockingWindow::GetSizePixel() const
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ if ( pWrapper->mpFloatWin )
+ return pWrapper->mpFloatWin->GetSizePixel();
+ else
+ return Window::GetSizePixel();
+ }
+
+ if ( mpFloatWin )
+ return mpFloatWin->GetSizePixel();
+ else
+ return Window::GetSizePixel();
+}
+
+// -----------------------------------------------------------------------
+
+void DockingWindow::SetOutputSizePixel( const Size& rNewSize )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ if ( pWrapper->mpFloatWin )
+ pWrapper->mpFloatWin->SetOutputSizePixel( rNewSize );
+ else
+ Window::SetOutputSizePixel( rNewSize );
+ return;
+ }
+
+ if ( mpFloatWin )
+ mpFloatWin->SetOutputSizePixel( rNewSize );
+ else
+ Window::SetOutputSizePixel( rNewSize );
+}
+
+// -----------------------------------------------------------------------
+
+Size DockingWindow::GetOutputSizePixel() const
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ if ( pWrapper->mpFloatWin )
+ return pWrapper->mpFloatWin->GetOutputSizePixel();
+ else
+ return Window::GetOutputSizePixel();
+ }
+
+ if ( mpFloatWin )
+ return mpFloatWin->GetOutputSizePixel();
+ else
+ return Window::GetOutputSizePixel();
+}
+
+Point DockingWindow::GetFloatingPos() const
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ {
+ if ( pWrapper->mpFloatWin )
+ {
+ WindowStateData aData;
+ aData.SetMask( WINDOWSTATE_MASK_POS );
+ pWrapper->mpFloatWin->GetWindowStateData( aData );
+ Point aPos( aData.GetX(), aData.GetY() );
+ aPos = pWrapper->mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
+ return aPos;
+ }
+ else
+ return maFloatPos;
+ }
+
+ if ( mpFloatWin )
+ {
+ WindowStateData aData;
+ aData.SetMask( WINDOWSTATE_MASK_POS );
+ mpFloatWin->GetWindowStateData( aData );
+ Point aPos( aData.GetX(), aData.GetY() );
+ aPos = mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos );
+ return aPos;
+ }
+ else
+ return maFloatPos;
+}
+
+BOOL DockingWindow::IsFloatingMode() const
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ return pWrapper->IsFloatingMode();
+ else
+ return (mpFloatWin != NULL);
+}
+
+void DockingWindow::SetMaxOutputSizePixel( const Size& rSize )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetMaxOutputSizePixel( rSize );
+ mpImplData->maMaxOutSize = rSize;
+}
+
+const Size& DockingWindow::GetMaxOutputSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetMaxOutputSizePixel();
+ return mpImplData->maMaxOutSize;
+}
diff --git a/vcl/source/window/floatwin.cxx b/vcl/source/window/floatwin.cxx
new file mode 100644
index 000000000000..323bbe3b0d74
--- /dev/null
+++ b/vcl/source/window/floatwin.cxx
@@ -0,0 +1,878 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/event.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/window.h>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/salframe.hxx>
+#include <tools/debug.hxx>
+
+
+// =======================================================================
+
+class FloatingWindow::ImplData
+{
+public:
+ ImplData();
+ ~ImplData();
+
+ ToolBox* mpBox;
+ Rectangle maItemEdgeClipRect; // used to clip the common edge between a toolbar item and the border of this window
+};
+
+FloatingWindow::ImplData::ImplData()
+{
+ mpBox = NULL;
+}
+
+FloatingWindow::ImplData::~ImplData()
+{
+}
+
+Rectangle& FloatingWindow::ImplGetItemEdgeClipRect()
+{
+ return mpImplData->maItemEdgeClipRect;
+}
+
+// =======================================================================
+
+void FloatingWindow::ImplInit( Window* pParent, WinBits nStyle )
+{
+ mpImplData = new ImplData;
+
+ mpWindowImpl->mbFloatWin = TRUE;
+ mbInCleanUp = FALSE;
+ mbGrabFocus = FALSE;
+
+ DBG_ASSERT( pParent, "FloatWindow::FloatingWindow(): - pParent == NULL!" );
+
+ if ( !pParent )
+ pParent = ImplGetSVData()->maWinData.mpAppWin;
+
+ DBG_ASSERT( pParent, "FloatWindow::FloatingWindow(): - pParent == NULL and no AppWindow exists" );
+
+ // no Border, then we dont need a border window
+ if ( !nStyle )
+ {
+ mpWindowImpl->mbOverlapWin = TRUE;
+ nStyle |= WB_DIALOGCONTROL;
+ SystemWindow::ImplInit( pParent, nStyle, NULL );
+ }
+ else
+ {
+ if ( !(nStyle & WB_NODIALOGCONTROL) )
+ nStyle |= WB_DIALOGCONTROL;
+
+ if( nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_CLOSEABLE | WB_STANDALONE)
+ && !(nStyle & WB_OWNERDRAWDECORATION) )
+ {
+ WinBits nFloatWinStyle = nStyle;
+ // #99154# floaters are not closeable by default anymore, eg fullscreen floater
+ // nFloatWinStyle |= WB_CLOSEABLE;
+ mpWindowImpl->mbFrame = TRUE;
+ mpWindowImpl->mbOverlapWin = TRUE;
+ SystemWindow::ImplInit( pParent, nFloatWinStyle & ~WB_BORDER, NULL );
+ }
+ else
+ {
+ ImplBorderWindow* pBorderWin;
+ USHORT nBorderStyle = BORDERWINDOW_STYLE_BORDER | BORDERWINDOW_STYLE_FLOAT;
+
+ if( nStyle & WB_OWNERDRAWDECORATION ) nBorderStyle |= BORDERWINDOW_STYLE_FRAME;
+ else nBorderStyle |= BORDERWINDOW_STYLE_OVERLAP;
+
+ if ( (nStyle & WB_SYSTEMWINDOW) && !(nStyle & (WB_MOVEABLE | WB_SIZEABLE)) )
+ {
+ nBorderStyle |= BORDERWINDOW_STYLE_FRAME;
+ nStyle |= WB_CLOSEABLE; // make undecorated floaters closeable
+ }
+ pBorderWin = new ImplBorderWindow( pParent, nStyle, nBorderStyle );
+ SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL );
+ pBorderWin->mpWindowImpl->mpClientWindow = this;
+ pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ pBorderWin->SetDisplayActive( TRUE );
+ mpWindowImpl->mpBorderWindow = pBorderWin;
+ mpWindowImpl->mpRealParent = pParent;
+ }
+ }
+ SetActivateMode( 0 );
+
+ mpNextFloat = NULL;
+ mpFirstPopupModeWin = NULL;
+ mnPostId = 0;
+ mnTitle = (nStyle & WB_MOVEABLE) ? FLOATWIN_TITLE_NORMAL : FLOATWIN_TITLE_NONE;
+ mnOldTitle = mnTitle;
+ mnPopupModeFlags = 0;
+ mbInPopupMode = FALSE;
+ mbPopupMode = FALSE;
+ mbPopupModeCanceled = FALSE;
+ mbPopupModeTearOff = FALSE;
+ mbMouseDown = FALSE;
+
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::ImplInitSettings()
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ Color aColor;
+ if ( IsControlBackground() )
+ aColor = GetControlBackground();
+ else if ( Window::GetStyle() & WB_3DLOOK )
+ aColor = rStyleSettings.GetFaceColor();
+ else
+ aColor = rStyleSettings.GetWindowColor();
+ SetBackground( aColor );
+}
+
+// =======================================================================
+
+FloatingWindow::FloatingWindow( Window* pParent, WinBits nStyle ) :
+ SystemWindow( WINDOW_FLOATINGWINDOW )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+FloatingWindow::FloatingWindow( Window* pParent, const ResId& rResId ) :
+ SystemWindow( WINDOW_FLOATINGWINDOW )
+{
+ rResId.SetRT( RSC_FLOATINGWINDOW );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::ImplLoadRes( const ResId& rResId )
+{
+ SystemWindow::ImplLoadRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if ( (RSC_FLOATINGWINDOW_WHMAPMODE | RSC_FLOATINGWINDOW_WIDTH |
+ RSC_FLOATINGWINDOW_HEIGHT) & nObjMask )
+ {
+ // Groessenangabe aus der Resource verwenden
+ Size aSize;
+ MapUnit eSizeMap = MAP_PIXEL;
+
+ if ( RSC_FLOATINGWINDOW_WHMAPMODE & nObjMask )
+ eSizeMap = (MapUnit) ReadShortRes();
+ if ( RSC_FLOATINGWINDOW_WIDTH & nObjMask )
+ aSize.Width() = ReadShortRes();
+ if ( RSC_FLOATINGWINDOW_HEIGHT & nObjMask )
+ aSize.Height() = ReadShortRes();
+
+ SetRollUpOutputSizePixel( LogicToPixel( aSize, eSizeMap ) );
+ }
+
+ if (nObjMask & RSC_FLOATINGWINDOW_ZOOMIN )
+ {
+ if ( ReadShortRes() )
+ RollUp();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+FloatingWindow::~FloatingWindow()
+{
+ if( mbPopupModeCanceled )
+ // indicates that ESC key was pressed
+ // will be handled in Window::ImplGrabFocus()
+ SetDialogControlFlags( GetDialogControlFlags() | WINDOW_DLGCTRL_FLOATWIN_POPUPMODEEND_CANCEL );
+
+ if ( IsInPopupMode() )
+ EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL | FLOATWIN_POPUPMODEEND_DONTCALLHDL );
+
+ if ( mnPostId )
+ Application::RemoveUserEvent( mnPostId );
+
+ delete mpImplData;
+}
+
+// -----------------------------------------------------------------------
+
+Point FloatingWindow::CalcFloatingPosition( Window* pWindow, const Rectangle& rRect, ULONG nFlags, USHORT& rArrangeIndex )
+{
+ return ImplCalcPos( pWindow, rRect, nFlags, rArrangeIndex );
+}
+
+// -----------------------------------------------------------------------
+
+Point FloatingWindow::ImplCalcPos( Window* pWindow,
+ const Rectangle& rRect, ULONG nFlags,
+ USHORT& rArrangeIndex )
+{
+ // Fenster-Position ermitteln
+ Point aPos;
+ Size aSize = pWindow->GetSizePixel();
+ Rectangle aScreenRect = pWindow->ImplGetFrameWindow()->GetDesktopRectPixel();
+ FloatingWindow *pFloatingWindow = dynamic_cast<FloatingWindow*>( pWindow );
+
+ // convert....
+ Window* pW = pWindow;
+ if ( pW->mpWindowImpl->mpRealParent )
+ pW = pW->mpWindowImpl->mpRealParent;
+
+ Rectangle normRect( rRect ); // rRect is already relative to top-level window
+ normRect.SetPos( pW->ScreenToOutputPixel( normRect.TopLeft() ) );
+
+ BOOL bRTL = Application::GetSettings().GetLayoutRTL();
+
+ Rectangle devRect( pW->OutputToAbsoluteScreenPixel( normRect.TopLeft() ),
+ pW->OutputToAbsoluteScreenPixel( normRect.BottomRight() ) );
+
+ Rectangle devRectRTL( devRect );
+ if( bRTL )
+ // create a rect that can be compared to desktop coordinates
+ devRectRTL = pW->ImplOutputToUnmirroredAbsoluteScreenPixel( normRect );
+ if( Application::GetScreenCount() > 1 && ! Application::IsMultiDisplay() )
+ aScreenRect = Application::GetScreenPosSizePixel(
+ Application::GetBestScreen( bRTL ? devRectRTL : devRect ) );
+
+
+ USHORT nArrangeAry[5];
+ USHORT nArrangeIndex;
+ BOOL bBreak;
+ Point e1,e2; // the common edge between the item rect and the floating window
+
+ if ( nFlags & FLOATWIN_POPUPMODE_LEFT )
+ {
+ nArrangeAry[0] = FLOATWIN_POPUPMODE_LEFT;
+ nArrangeAry[1] = FLOATWIN_POPUPMODE_RIGHT;
+ nArrangeAry[2] = FLOATWIN_POPUPMODE_UP;
+ nArrangeAry[3] = FLOATWIN_POPUPMODE_DOWN;
+ nArrangeAry[4] = FLOATWIN_POPUPMODE_LEFT;
+ }
+ else if ( nFlags & FLOATWIN_POPUPMODE_RIGHT )
+ {
+ nArrangeAry[0] = FLOATWIN_POPUPMODE_RIGHT;
+ nArrangeAry[1] = FLOATWIN_POPUPMODE_LEFT;
+ nArrangeAry[2] = FLOATWIN_POPUPMODE_UP;
+ nArrangeAry[3] = FLOATWIN_POPUPMODE_DOWN;
+ nArrangeAry[4] = FLOATWIN_POPUPMODE_RIGHT;
+ }
+ else if ( nFlags & FLOATWIN_POPUPMODE_UP )
+ {
+ nArrangeAry[0] = FLOATWIN_POPUPMODE_UP;
+ nArrangeAry[1] = FLOATWIN_POPUPMODE_DOWN;
+ nArrangeAry[2] = FLOATWIN_POPUPMODE_RIGHT;
+ nArrangeAry[3] = FLOATWIN_POPUPMODE_LEFT;
+ nArrangeAry[4] = FLOATWIN_POPUPMODE_UP;
+ }
+ else
+ {
+ nArrangeAry[0] = FLOATWIN_POPUPMODE_DOWN;
+ nArrangeAry[1] = FLOATWIN_POPUPMODE_UP;
+ nArrangeAry[2] = FLOATWIN_POPUPMODE_RIGHT;
+ nArrangeAry[3] = FLOATWIN_POPUPMODE_LEFT;
+ nArrangeAry[4] = FLOATWIN_POPUPMODE_DOWN;
+ }
+ if ( nFlags & FLOATWIN_POPUPMODE_NOAUTOARRANGE )
+ nArrangeIndex = 4;
+ else
+ nArrangeIndex = 0;
+
+ for ( ; nArrangeIndex < 5; nArrangeIndex++ )
+ {
+ bBreak = TRUE;
+ switch ( nArrangeAry[nArrangeIndex] )
+ {
+
+ case FLOATWIN_POPUPMODE_LEFT:
+ aPos.X() = devRect.Left()-aSize.Width()+1;
+ aPos.Y() = devRect.Top();
+ aPos.Y() -= pWindow->mpWindowImpl->mnTopBorder;
+ if( bRTL ) // --- RTL --- we're comparing screen coordinates here
+ {
+ if( (devRectRTL.Right()+aSize.Width()) > aScreenRect.Right() )
+ bBreak = FALSE;
+ }
+ else
+ {
+ if ( aPos.X() < aScreenRect.Left() )
+ bBreak = FALSE;
+ }
+ if( bBreak )
+ {
+ e1 = devRect.TopLeft();
+ e2 = devRect.BottomLeft();
+ // set non-zero width
+ e2.X()++;
+ // don't clip corners
+ e1.Y()++;
+ e2.Y()--;
+ }
+ break;
+ case FLOATWIN_POPUPMODE_RIGHT:
+ aPos = devRect.TopRight();
+ aPos.Y() -= pWindow->mpWindowImpl->mnTopBorder;
+ if( bRTL ) // --- RTL --- we're comparing screen coordinates here
+ {
+ if( (devRectRTL.Left() - aSize.Width()) < aScreenRect.Left() )
+ bBreak = FALSE;
+ }
+ else
+ {
+ if ( aPos.X()+aSize.Width() > aScreenRect.Right() )
+ bBreak = FALSE;
+ }
+ if( bBreak )
+ {
+ e1 = devRect.TopRight();
+ e2 = devRect.BottomRight();
+ // set non-zero width
+ e2.X()++;
+ // don't clip corners
+ e1.Y()++;
+ e2.Y()--;
+ }
+ break;
+ case FLOATWIN_POPUPMODE_UP:
+ aPos.X() = devRect.Left();
+ aPos.Y() = devRect.Top()-aSize.Height()+1;
+ if ( aPos.Y() < aScreenRect.Top() )
+ bBreak = FALSE;
+ if( bBreak )
+ {
+ e1 = devRect.TopLeft();
+ e2 = devRect.TopRight();
+ // set non-zero height
+ e2.Y()++;
+ // don't clip corners
+ e1.X()++;
+ e2.X()--;
+ }
+ break;
+ case FLOATWIN_POPUPMODE_DOWN:
+ aPos = devRect.BottomLeft();
+ if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() )
+ bBreak = FALSE;
+ if( bBreak )
+ {
+ e1 = devRect.BottomLeft();
+ e2 = devRect.BottomRight();
+ // set non-zero height
+ e2.Y()++;
+ // don't clip corners
+ e1.X()++;
+ e2.X()--;
+ }
+ break;
+ }
+
+ // Evt. noch anpassen
+ if ( bBreak && !(nFlags & FLOATWIN_POPUPMODE_NOAUTOARRANGE) )
+ {
+ if ( (nArrangeAry[nArrangeIndex] == FLOATWIN_POPUPMODE_LEFT) ||
+ (nArrangeAry[nArrangeIndex] == FLOATWIN_POPUPMODE_RIGHT) )
+ {
+ if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() )
+ {
+ aPos.Y() = devRect.Bottom()-aSize.Height()+1;
+ if ( aPos.Y() < aScreenRect.Top() )
+ aPos.Y() = aScreenRect.Top();
+ }
+ }
+ else
+ {
+ if( bRTL ) // --- RTL --- we're comparing screen coordinates here
+ {
+ if( devRectRTL.Right()-aSize.Width()+1 < aScreenRect.Left() )
+ aPos.X() -= aScreenRect.Left() - devRectRTL.Right() + aSize.Width() - 1;
+ else if( aPos.X() + aSize.Width() > aScreenRect.Right() )
+ {
+ aPos.X() -= aSize.Width()-2; // popup to left instead
+ aPos.Y() -= 2;
+ }
+ }
+ else if ( aPos.X()+aSize.Width() > aScreenRect.Right() )
+ {
+ aPos.X() = devRect.Right()-aSize.Width()+1;
+ if ( aPos.X() < aScreenRect.Left() )
+ aPos.X() = aScreenRect.Left();
+ }
+ }
+ }
+
+ if ( bBreak )
+ break;
+ }
+ if ( nArrangeIndex > 4 )
+ nArrangeIndex = 4;
+
+ rArrangeIndex = nArrangeIndex;
+
+ aPos = pW->AbsoluteScreenToOutputPixel( aPos );
+
+ // store a cliprect that can be used to clip the common edge of the itemrect and the floating window
+ if( pFloatingWindow )
+ {
+ pFloatingWindow->mpImplData->maItemEdgeClipRect =
+ Rectangle( e1, e2 );
+ }
+
+ // caller expects cordinates relative to top-level win
+ return pW->OutputToScreenPixel( aPos );
+}
+
+// -----------------------------------------------------------------------
+
+FloatingWindow* FloatingWindow::ImplFloatHitTest( Window* pReference, const Point& rPos, USHORT& rHitTest )
+{
+ FloatingWindow* pWin = this;
+
+ Point aAbsolute( rPos );
+
+ // compare coordinates in absolute screen coordinates
+ if( pReference->ImplHasMirroredGraphics() )
+ {
+ if(!pReference->IsRTLEnabled() )
+ // --- RTL --- re-mirror back to get device coordiantes
+ pReference->ImplReMirror( aAbsolute );
+
+ Rectangle aRect( pReference->ScreenToOutputPixel(aAbsolute), Size(1,1) ) ;
+ aRect = pReference->ImplOutputToUnmirroredAbsoluteScreenPixel( aRect );
+ aAbsolute = aRect.TopLeft();
+ }
+ else
+ aAbsolute = Point( pReference->OutputToAbsoluteScreenPixel(
+ pReference->ScreenToOutputPixel(rPos) ) );
+
+ do
+ {
+ // compute the floating window's size in absolute screen coordinates
+
+ // use the border window to have the exact position
+ Window *pBorderWin = pWin->GetWindow( WINDOW_BORDER );
+
+ Point aPt; // the top-left corner in output coordinates ie (0,0)
+ Rectangle devRect( pBorderWin->ImplOutputToUnmirroredAbsoluteScreenPixel( Rectangle( aPt, pBorderWin->GetSizePixel()) ) ) ;
+ if ( devRect.IsInside( aAbsolute ) )
+ {
+ rHitTest = IMPL_FLOATWIN_HITTEST_WINDOW;
+ return pWin;
+ }
+
+ // test, if mouse is in rectangle, (this is typically the rect of the active
+ // toolbox item or similar)
+ // note: maFloatRect is set in FloatingWindow::StartPopupMode() and
+ // is already in absolute device coordinates
+ if ( pWin->maFloatRect.IsInside( aAbsolute ) )
+ {
+ rHitTest = IMPL_FLOATWIN_HITTEST_RECT;
+ return pWin;
+ }
+
+ pWin = pWin->mpNextFloat;
+ }
+ while ( pWin );
+
+ rHitTest = IMPL_FLOATWIN_HITTEST_OUTSIDE;
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+FloatingWindow* FloatingWindow::ImplFindLastLevelFloat()
+{
+ FloatingWindow* pWin = this;
+ FloatingWindow* pLastFoundWin = pWin;
+
+ do
+ {
+ if ( pWin->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NEWLEVEL )
+ pLastFoundWin = pWin;
+
+ pWin = pWin->mpNextFloat;
+ }
+ while ( pWin );
+
+ return pLastFoundWin;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL FloatingWindow::ImplIsFloatPopupModeWindow( const Window* pWindow )
+{
+ FloatingWindow* pWin = this;
+
+ do
+ {
+ if ( pWin->mpFirstPopupModeWin == pWindow )
+ return TRUE;
+
+ pWin = pWin->mpNextFloat;
+ }
+ while ( pWin );
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( FloatingWindow, ImplEndPopupModeHdl, void*, EMPTYARG )
+{
+ mnPostId = 0;
+ mnPopupModeFlags = 0;
+ mbPopupMode = FALSE;
+ PopupModeEnd();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+long FloatingWindow::Notify( NotifyEvent& rNEvt )
+{
+ // Zuerst Basisklasse rufen wegen TabSteuerung
+ long nRet = SystemWindow::Notify( rNEvt );
+ if ( !nRet )
+ {
+ if ( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
+ KeyCode aKeyCode = pKEvt->GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+
+ if ( (nKeyCode == KEY_ESCAPE) && (GetStyle() & WB_CLOSEABLE) )
+ {
+ Close();
+ return TRUE;
+ }
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::StateChanged( StateChangedType nType )
+{
+ SystemWindow::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ SystemWindow::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::ImplCallPopupModeEnd()
+{
+ // PopupMode wurde beendet
+ mbInPopupMode = FALSE;
+
+ // Handler asyncron rufen
+ if ( !mnPostId )
+ Application::PostUserEvent( mnPostId, LINK( this, FloatingWindow, ImplEndPopupModeHdl ) );
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::PopupModeEnd()
+{
+ maPopupModeEndHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::SetTitleType( USHORT nTitle )
+{
+ if ( (mnTitle != nTitle) && mpWindowImpl->mpBorderWindow )
+ {
+ mnTitle = nTitle;
+ Size aOutSize = GetOutputSizePixel();
+ USHORT nTitleStyle;
+ if ( nTitle == FLOATWIN_TITLE_NORMAL )
+ nTitleStyle = BORDERWINDOW_TITLE_SMALL;
+ else if ( nTitle == FLOATWIN_TITLE_TEAROFF )
+ nTitleStyle = BORDERWINDOW_TITLE_TEAROFF;
+ else // nTitle == FLOATWIN_TITLE_NONE
+ nTitleStyle = BORDERWINDOW_TITLE_NONE;
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetTitleType( nTitleStyle, aOutSize );
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::StartPopupMode( const Rectangle& rRect, ULONG nFlags )
+{
+ // avoid flickering
+ if ( IsVisible() )
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ if ( IsRollUp() )
+ RollDown();
+
+ // remove title
+ mnOldTitle = mnTitle;
+ if ( nFlags & FLOATWIN_POPUPMODE_ALLOWTEAROFF )
+ SetTitleType( FLOATWIN_TITLE_TEAROFF );
+ else
+ SetTitleType( FLOATWIN_TITLE_NONE );
+
+ // avoid close on focus change for decorated floating windows only
+ if( mpWindowImpl->mbFrame && (GetStyle() & WB_MOVEABLE) )
+ nFlags |= FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE;
+
+ // #102010# For debugging Accessibility
+ static const char* pEnv = getenv("SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
+ if( pEnv && *pEnv )
+ nFlags |= FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE;
+
+ // compute window position according to flags and arrangement
+ USHORT nArrangeIndex;
+ SetPosPixel( ImplCalcPos( this, rRect, nFlags, nArrangeIndex ) );
+
+ // set data and display window
+ // convert maFloatRect to absolute device coordinates
+ // so they can be compared across different frames
+ // !!! rRect is expected to be in screen coordinates of the parent frame window !!!
+ maFloatRect = rRect;
+ if( GetParent()->ImplHasMirroredGraphics() )
+ {
+ maFloatRect.SetPos( GetParent()->ScreenToOutputPixel( rRect.TopLeft() ) );
+ maFloatRect = GetParent()->ImplOutputToUnmirroredAbsoluteScreenPixel( maFloatRect );
+ }
+ else
+ maFloatRect.SetPos( GetParent()->OutputToAbsoluteScreenPixel( GetParent()->ScreenToOutputPixel( rRect.TopLeft() ) ) );
+
+ maFloatRect.Left() -= 2;
+ maFloatRect.Top() -= 2;
+ maFloatRect.Right() += 2;
+ maFloatRect.Bottom() += 2;
+ mnPopupModeFlags = nFlags;
+ mbInPopupMode = TRUE;
+ mbPopupMode = TRUE;
+ mbPopupModeCanceled = FALSE;
+ mbPopupModeTearOff = FALSE;
+ mbMouseDown = FALSE;
+
+ mbOldSaveBackMode = IsSaveBackgroundEnabled();
+ EnableSaveBackground();
+
+ // add FloatingWindow to list of windows that are in popup mode
+ ImplSVData* pSVData = ImplGetSVData();
+ mpNextFloat = pSVData->maWinData.mpFirstFloat;
+ pSVData->maWinData.mpFirstFloat = this;
+ if( nFlags & FLOATWIN_POPUPMODE_GRABFOCUS )
+ {
+ // force key input even without focus (useful for menues)
+ mbGrabFocus = TRUE;
+ }
+ Show( TRUE, SHOW_NOACTIVATE );
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::StartPopupMode( ToolBox* pBox, ULONG nFlags )
+{
+ // get selected button
+ USHORT nItemId = pBox->GetDownItemId();
+ if ( !nItemId )
+ return;
+
+ mpImplData->mpBox = pBox;
+ pBox->ImplFloatControl( TRUE, this );
+
+ // retrieve some data from the ToolBox
+ Rectangle aRect = pBox->GetItemRect( nItemId );
+ Point aPos;
+ // convert to parent's screen coordinates
+ aPos = GetParent()->OutputToScreenPixel( GetParent()->AbsoluteScreenToOutputPixel( pBox->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) ) );
+ aRect.SetPos( aPos );
+
+ nFlags |=
+ FLOATWIN_POPUPMODE_NOFOCUSCLOSE |
+// FLOATWIN_POPUPMODE_NOMOUSECLOSE |
+ FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE |
+// FLOATWIN_POPUPMODE_NOMOUSERECTCLOSE | // #105968# floating toolboxes should close when clicked in (parent's) float rect
+ FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE;
+// | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE;
+
+/*
+ * FLOATWIN_POPUPMODE_NOKEYCLOSE |
+ * don't set since it disables closing floaters with escape
+ */
+
+ // Flags fuer Positionierung bestimmen
+ if ( !(nFlags & (FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_UP |
+ FLOATWIN_POPUPMODE_LEFT | FLOATWIN_POPUPMODE_RIGHT |
+ FLOATWIN_POPUPMODE_NOAUTOARRANGE)) )
+ {
+ if ( pBox->IsHorizontal() )
+ nFlags |= FLOATWIN_POPUPMODE_DOWN;
+ else
+ nFlags |= FLOATWIN_POPUPMODE_RIGHT;
+ }
+
+ // FloatingModus starten
+ StartPopupMode( aRect, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::ImplEndPopupMode( USHORT nFlags, ULONG nFocusId )
+{
+ if ( !mbInPopupMode )
+ return;
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ mbInCleanUp = TRUE; // prevent killing this window due to focus change while working with it
+
+ // Bei allen nachfolgenden PopupMode-Fenster den Modus auch beenden
+ while ( pSVData->maWinData.mpFirstFloat && pSVData->maWinData.mpFirstFloat != this )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL );
+
+
+ // Fenster aus der Liste austragen
+ pSVData->maWinData.mpFirstFloat = mpNextFloat;
+ mpNextFloat = NULL;
+
+ ULONG nPopupModeFlags = mnPopupModeFlags;
+
+ // Wenn nicht abgerissen wurde, dann Fenster wieder Hiden
+ if ( !(nFlags & FLOATWIN_POPUPMODEEND_TEAROFF) ||
+ !(nPopupModeFlags & FLOATWIN_POPUPMODE_ALLOWTEAROFF) )
+ {
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ // Focus evt. auf ein entsprechendes FloatingWindow weiterschalten
+ if ( nFocusId )
+ Window::EndSaveFocus( nFocusId );
+ else if ( pSVData->maWinData.mpFocusWin && pSVData->maWinData.mpFirstFloat &&
+ ImplIsWindowOrChild( pSVData->maWinData.mpFocusWin ) )
+ pSVData->maWinData.mpFirstFloat->GrabFocus();
+ mbPopupModeTearOff = FALSE;
+ }
+ else
+ {
+ mbPopupModeTearOff = TRUE;
+ if ( nFocusId )
+ Window::EndSaveFocus( nFocusId, FALSE );
+ }
+ EnableSaveBackground( mbOldSaveBackMode );
+
+ mbPopupModeCanceled = (nFlags & FLOATWIN_POPUPMODEEND_CANCEL) != 0;
+
+ // Gegebenenfalls den Title wieder herstellen
+ SetTitleType( mnOldTitle );
+
+ // ToolBox wieder auf normal schalten
+ if ( mpImplData->mpBox )
+ {
+ mpImplData->mpBox->ImplFloatControl( FALSE, this );
+ mpImplData->mpBox = NULL;
+ }
+
+ // Je nach Parameter den PopupModeEnd-Handler rufen
+ if ( !(nFlags & FLOATWIN_POPUPMODEEND_DONTCALLHDL) )
+ ImplCallPopupModeEnd();
+
+ // Je nach Parameter die restlichen Fenster auch noch schliessen
+ if ( nFlags & FLOATWIN_POPUPMODEEND_CLOSEALL )
+ {
+ if ( !(nPopupModeFlags & FLOATWIN_POPUPMODE_NEWLEVEL) )
+ {
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ }
+ }
+
+ mbInCleanUp = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::EndPopupMode( USHORT nFlags )
+{
+ ImplEndPopupMode( nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::AddPopupModeWindow( Window* pWindow )
+{
+ // !!! bisher erst 1 Fenster und noch keine Liste
+ mpFirstPopupModeWin = pWindow;
+}
+
+// -----------------------------------------------------------------------
+
+void FloatingWindow::RemovePopupModeWindow( Window* pWindow )
+{
+ // !!! bisher erst 1 Fenster und noch keine Liste
+ if ( mpFirstPopupModeWin == pWindow )
+ mpFirstPopupModeWin = NULL;
+}
+
diff --git a/vcl/source/window/introwin.cxx b/vcl/source/window/introwin.cxx
new file mode 100644
index 000000000000..03f88adc3566
--- /dev/null
+++ b/vcl/source/window/introwin.cxx
@@ -0,0 +1,88 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salframe.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/wrkwin.hxx>
+
+#include <vcl/bitmap.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/introwin.hxx>
+
+
+
+
+// =======================================================================
+
+void IntroWindow::ImplInitIntroWindowData()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpIntroWindow = this;
+}
+
+// -----------------------------------------------------------------------
+
+IntroWindow::IntroWindow( ) :
+ WorkWindow( WINDOW_INTROWINDOW )
+{
+ ImplInitIntroWindowData();
+ WorkWindow::ImplInit( 0, WB_INTROWIN, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+IntroWindow::~IntroWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->mpIntroWindow == this )
+ pSVData->mpIntroWindow = NULL;
+}
+
+void IntroWindow::SetBackgroundBitmap( const Bitmap& rBitmap )
+{
+ if( ! rBitmap.IsEmpty() )
+ {
+ SalBitmap* pBmp = rBitmap.ImplGetImpBitmap()->ImplGetSalBitmap();
+ ImplGetFrame()->SetBackgroundBitmap( pBmp );
+ }
+}
+
+void IntroWindow::SetBackgroundBitmap( const BitmapEx& rBitmapEx )
+{
+ if( ! rBitmapEx.IsEmpty() )
+ {
+ SalBitmap* pBmp = rBitmapEx.ImplGetBitmapImpBitmap()->ImplGetSalBitmap();
+ ImplGetFrame()->SetBackgroundBitmap( pBmp );
+ }
+}
diff --git a/vcl/source/window/javachild.cxx b/vcl/source/window/javachild.cxx
new file mode 100644
index 000000000000..2cd18b897ff5
--- /dev/null
+++ b/vcl/source/window/javachild.cxx
@@ -0,0 +1,207 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+
+#ifdef SOLAR_JAVA
+#include <jni.h>
+#endif
+#include <comphelper/processfactory.hxx>
+
+#include <vcl/unohelp.hxx>
+#include <rtl/process.h>
+#include <rtl/ref.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+#include <com/sun/star/java/XJavaVM.hpp>
+#include <com/sun/star/java/XJavaThreadRegister_11.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salinst.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/window.hxx>
+#include <vcl/salobj.hxx>
+#include <vcl/javachild.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/sysdata.hxx>
+
+using namespace ::com::sun::star;
+
+// -------------------
+// - JavaChildWindow -
+// -------------------
+
+JavaChildWindow::JavaChildWindow( Window* pParent, WinBits nStyle ) :
+ SystemChildWindow( pParent, nStyle )
+{
+}
+
+// -----------------------------------------------------------------------
+
+JavaChildWindow::JavaChildWindow( Window* pParent, const ResId& rResId ) :
+ SystemChildWindow( pParent, rResId )
+{
+}
+
+// -----------------------------------------------------------------------
+
+JavaChildWindow::~JavaChildWindow()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void JavaChildWindow::implTestJavaException( void* pEnv )
+{
+#ifdef SOLAR_JAVA
+ JNIEnv* pJavaEnv = reinterpret_cast< JNIEnv* >( pEnv );
+ jthrowable jtThrowable = pJavaEnv->ExceptionOccurred();
+
+ if( jtThrowable )
+ { // is it a java exception ?
+#if OSL_DEBUG_LEVEL > 1
+ pJavaEnv->ExceptionDescribe();
+#endif // OSL_DEBUG_LEVEL > 1
+ pJavaEnv->ExceptionClear();
+
+ jclass jcThrowable = pJavaEnv->FindClass("java/lang/Throwable");
+ jmethodID jmThrowable_getMessage = pJavaEnv->GetMethodID(jcThrowable, "getMessage", "()Ljava/lang/String;");
+ jstring jsMessage = (jstring) pJavaEnv->CallObjectMethod(jtThrowable, jmThrowable_getMessage);
+ ::rtl::OUString ouMessage;
+
+ if(jsMessage)
+ {
+ const jchar * jcMessage = pJavaEnv->GetStringChars(jsMessage, NULL);
+ ouMessage = ::rtl::OUString(jcMessage);
+ pJavaEnv->ReleaseStringChars(jsMessage, jcMessage);
+ }
+
+ throw uno::RuntimeException(ouMessage, uno::Reference<uno::XInterface>());
+ }
+#endif // SOLAR_JAVA
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr JavaChildWindow::getParentWindowHandleForJava()
+{
+ sal_IntPtr nRet = 0;
+
+#if defined WNT
+ nRet = reinterpret_cast< sal_IntPtr >( GetSystemData()->hWnd );
+#elif defined QUARTZ
+ // FIXME: this is wrong
+ nRet = reinterpret_cast< sal_IntPtr >( GetSystemData()->pView );
+#elif defined UNX
+#ifdef SOLAR_JAVA
+ uno::Reference< lang::XMultiServiceFactory > xFactory( vcl::unohelper::GetMultiServiceFactory() );
+
+ if( xFactory.is() && ( GetSystemData()->aWindow > 0 ) )
+ {
+ try
+ {
+ ::rtl::Reference< ::jvmaccess::VirtualMachine > xVM;
+ uno::Reference< java::XJavaVM > xJavaVM( xFactory->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.java.JavaVirtualMachine") ) ), uno::UNO_QUERY );
+ uno::Sequence< sal_Int8 > aProcessID( 17 );
+
+ rtl_getGlobalProcessId( (sal_uInt8*) aProcessID.getArray() );
+ aProcessID[ 16 ] = 0;
+ OSL_ENSURE(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *), "Pointer cannot be represented as sal_Int64");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >( static_cast< jvmaccess::VirtualMachine * >(0));
+ xJavaVM->getJavaVM(aProcessID) >>= nPointer;
+ xVM = reinterpret_cast< jvmaccess::VirtualMachine * >(nPointer);
+
+ if( xVM.is() )
+ {
+ try
+ {
+ ::jvmaccess::VirtualMachine::AttachGuard aVMAttachGuard( xVM );
+ JNIEnv* pEnv = aVMAttachGuard.getEnvironment();
+
+ jclass jcToolkit = pEnv->FindClass("java/awt/Toolkit");
+ implTestJavaException(pEnv);
+
+ jmethodID jmToolkit_getDefaultToolkit = pEnv->GetStaticMethodID( jcToolkit, "getDefaultToolkit", "()Ljava/awt/Toolkit;" );
+ implTestJavaException(pEnv);
+
+ pEnv->CallStaticObjectMethod(jcToolkit, jmToolkit_getDefaultToolkit);
+ implTestJavaException(pEnv);
+
+ jclass jcMotifAppletViewer = pEnv->FindClass("sun/plugin/navig/motif/MotifAppletViewer");
+ if( pEnv->ExceptionOccurred() )
+ {
+ pEnv->ExceptionClear();
+
+ jcMotifAppletViewer = pEnv->FindClass( "sun/plugin/viewer/MNetscapePluginContext");
+ implTestJavaException(pEnv);
+ }
+
+ jclass jcClassLoader = pEnv->FindClass("java/lang/ClassLoader");
+ implTestJavaException(pEnv);
+
+ jmethodID jmClassLoader_loadLibrary = pEnv->GetStaticMethodID( jcClassLoader, "loadLibrary", "(Ljava/lang/Class;Ljava/lang/String;Z)V");
+ implTestJavaException(pEnv);
+
+ jstring jsplugin = pEnv->NewStringUTF("javaplugin_jni");
+ implTestJavaException(pEnv);
+
+ pEnv->CallStaticVoidMethod(jcClassLoader, jmClassLoader_loadLibrary, jcMotifAppletViewer, jsplugin, JNI_FALSE);
+ implTestJavaException(pEnv);
+
+ jmethodID jmMotifAppletViewer_getWidget = pEnv->GetStaticMethodID( jcMotifAppletViewer, "getWidget", "(IIIII)I" );
+ implTestJavaException(pEnv);
+
+ const Size aSize( GetOutputSizePixel() );
+ jint ji_widget = pEnv->CallStaticIntMethod( jcMotifAppletViewer, jmMotifAppletViewer_getWidget,
+ GetSystemData()->aWindow, 0, 0, aSize.Width(), aSize.Height() );
+ implTestJavaException(pEnv);
+
+ nRet = static_cast< sal_IntPtr >( ji_widget );
+ }
+ catch( uno::RuntimeException& )
+ {
+ }
+
+ if( !nRet )
+ nRet = static_cast< sal_IntPtr >( GetSystemData()->aWindow );
+ }
+ }
+ catch( ... )
+ {
+ }
+ }
+#endif // SOLAR_JAVA
+#else // WNT || QUARTZ || UNX
+ // TBD
+#endif
+
+ return nRet;
+}
diff --git a/vcl/source/window/keycod.cxx b/vcl/source/window/keycod.cxx
new file mode 100644
index 000000000000..bcc5536fd028
--- /dev/null
+++ b/vcl/source/window/keycod.cxx
@@ -0,0 +1,160 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salinst.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/window.hxx>
+#ifndef _SV_KEYCOD_HXX
+#include <vcl/keycod.hxx>
+#endif
+
+#ifndef _RC_H
+#include <tools/rc.h>
+#endif
+
+
+
+// =======================================================================
+static USHORT aImplKeyFuncTab[(KEYFUNC_FRONT+1)*4] =
+{
+ 0, 0, 0, 0, // KEYFUNC_DONTKNOW
+ KEY_N | KEY_MOD1, 0, 0, 0, // KEYFUNC_NEW
+ KEY_O | KEY_MOD1, KEY_OPEN, 0, 0, // KEYFUNC_OPEN
+ KEY_S | KEY_MOD1, 0, 0, 0, // KEYFUNC_SAVE
+ 0, 0, 0, 0, // KEYFUNC_SAVEAS
+ KEY_P | KEY_MOD1, 0, 0, 0, // KEYFUNC_PRINT
+ KEY_W | KEY_MOD1, KEY_F4 | KEY_MOD1, 0, 0, // KEYFUNC_CLOSE
+ KEY_Q | KEY_MOD1, KEY_F4 | KEY_MOD2, 0, 0, // KEYFUNC_QUIT
+ KEY_X | KEY_MOD1, KEY_DELETE | KEY_SHIFT, KEY_CUT, 0, // KEYFUNC_CUT
+ KEY_C | KEY_MOD1, KEY_INSERT | KEY_MOD1, KEY_COPY, 0, // KEYFUNC_COPY
+ KEY_V | KEY_MOD1, KEY_INSERT | KEY_SHIFT, KEY_PASTE, 0, // KEYFUNC_PASTE
+ KEY_Z | KEY_MOD1, KEY_BACKSPACE | KEY_MOD2, KEY_UNDO, 0, // KEYFUNC_UNDO
+ 0, 0, 0, 0, // KEYFUNC_REDO
+ KEY_DELETE, 0, 0, 0, // KEYFUNC_DELETE
+ KEY_REPEAT, 0, 0, 0, // KEYFUNC_REPEAT
+ KEY_F | KEY_MOD1, KEY_FIND, 0, 0, // KEYFUNC_FIND
+ KEY_F | KEY_SHIFT | KEY_MOD1, KEY_SHIFT | KEY_FIND, 0, 0, // KEYFUNC_FINDBACKWARD
+ KEY_RETURN | KEY_MOD2, 0, 0, 0, // KEYFUNC_PROPERTIES
+ 0, 0, 0, 0 // KEYFUNC_FRONT
+};
+
+// -----------------------------------------------------------------------
+
+void ImplGetKeyCode( KeyFuncType eFunc, USHORT& rCode1, USHORT& rCode2, USHORT& rCode3, USHORT& rCode4 )
+{
+ USHORT nIndex = (USHORT)eFunc;
+ nIndex *= 4;
+ rCode1 = aImplKeyFuncTab[nIndex];
+ rCode2 = aImplKeyFuncTab[nIndex+1];
+ rCode3 = aImplKeyFuncTab[nIndex+2];
+ rCode4 = aImplKeyFuncTab[nIndex+3];
+}
+
+// =======================================================================
+
+KeyCode::KeyCode( KeyFuncType eFunction )
+{
+ USHORT nDummy;
+ ImplGetKeyCode( eFunction, nCode, nDummy, nDummy, nDummy );
+ eFunc = eFunction;
+}
+
+// -----------------------------------------------------------------------
+
+KeyCode::KeyCode( const ResId& rResId )
+{
+ rResId.SetRT( RSC_KEYCODE );
+
+ ResMgr* pResMgr = rResId.GetResMgr();
+ if ( pResMgr && pResMgr->GetResource( rResId ) )
+ {
+ pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
+
+ ULONG nKeyCode = pResMgr->ReadLong();
+ ULONG nModifier = pResMgr->ReadLong();
+ ULONG nKeyFunc = pResMgr->ReadLong();
+
+ eFunc = (KeyFuncType)nKeyFunc;
+ if ( eFunc != KEYFUNC_DONTKNOW )
+ {
+ USHORT nDummy;
+ ImplGetKeyCode( eFunc, nCode, nDummy, nDummy, nDummy );
+ }
+ else
+ nCode = sal::static_int_cast<USHORT>(nKeyCode | nModifier);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString KeyCode::GetName( Window* pWindow ) const
+{
+ if ( !pWindow )
+ pWindow = ImplGetDefaultWindow();
+ return pWindow ? pWindow->ImplGetFrame()->GetKeyName( GetFullCode() ) : XubString();
+}
+
+// -----------------------------------------------------------------------
+
+XubString KeyCode::GetSymbolName( const XubString& rFontName, Window* pWindow ) const
+{
+ if ( !pWindow )
+ pWindow = ImplGetDefaultWindow();
+ return pWindow ? pWindow->ImplGetFrame()->GetSymbolKeyName( rFontName, GetFullCode() ) : XubString();
+}
+
+// -----------------------------------------------------------------------
+
+KeyFuncType KeyCode::GetFunction() const
+{
+ if ( eFunc != KEYFUNC_DONTKNOW )
+ return eFunc;
+
+ USHORT nCompCode = GetModifier() | GetCode();
+ if ( nCompCode )
+ {
+ for ( USHORT i = (USHORT)KEYFUNC_NEW; i < (USHORT)KEYFUNC_FRONT; i++ )
+ {
+ USHORT nKeyCode1;
+ USHORT nKeyCode2;
+ USHORT nKeyCode3;
+ USHORT nKeyCode4;
+ ImplGetKeyCode( (KeyFuncType)i, nKeyCode1, nKeyCode2, nKeyCode3, nKeyCode4 );
+ if ( (nCompCode == nKeyCode1) || (nCompCode == nKeyCode2) || (nCompCode == nKeyCode3) || (nCompCode == nKeyCode4) )
+ return (KeyFuncType)i;
+ }
+ }
+
+ return KEYFUNC_DONTKNOW;
+}
diff --git a/vcl/source/window/keyevent.cxx b/vcl/source/window/keyevent.cxx
new file mode 100644
index 000000000000..f4011b9be16e
--- /dev/null
+++ b/vcl/source/window/keyevent.cxx
@@ -0,0 +1,116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <com/sun/star/awt/KeyEvent.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <tools/debug.hxx>
+#include <vcl/event.hxx>
+
+KeyEvent::KeyEvent (const KeyEvent& rKeyEvent) :
+ maKeyCode (rKeyEvent.maKeyCode),
+ mnRepeat (rKeyEvent.mnRepeat),
+ mnCharCode(rKeyEvent.mnCharCode)
+{}
+
+/** inits this vcl KeyEvent with all settings from the given awt event **/
+KeyEvent::KeyEvent( const ::com::sun::star::awt::KeyEvent& rEvent )
+{
+ maKeyCode = KeyCode(
+ rEvent.KeyCode,
+ (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::SHIFT) != 0,
+ (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD1) != 0,
+ (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD2) != 0,
+ (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD3) != 0);
+ mnRepeat = 0;
+ mnCharCode = rEvent.KeyChar;
+}
+
+/** fills out the given awt KeyEvent with all settings from this vcl event **/
+void KeyEvent::InitKeyEvent( ::com::sun::star::awt::KeyEvent& rEvent ) const
+{
+ rEvent.Modifiers = 0;
+ if( GetKeyCode().IsShift() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::SHIFT;
+ if( GetKeyCode().IsMod1() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD1;
+ if( GetKeyCode().IsMod2() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD2;
+ if( GetKeyCode().IsMod3() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD3;
+
+ rEvent.KeyCode = GetKeyCode().GetCode();
+ rEvent.KeyChar = GetCharCode();
+ rEvent.KeyFunc = sal::static_int_cast< sal_Int16 >(GetKeyCode().GetFunction());
+}
+
+KeyEvent KeyEvent::LogicalTextDirectionality (TextDirectionality eMode) const
+{
+ KeyEvent aClone(*this);
+
+ USHORT nCode = maKeyCode.GetCode();
+ USHORT nMod = maKeyCode.GetAllModifier();
+
+ switch (eMode)
+ {
+ case TextDirectionality_RightToLeft_TopToBottom:
+ switch (nCode)
+ {
+ case KEY_LEFT: aClone.maKeyCode = KeyCode(KEY_RIGHT, nMod); break;
+ case KEY_RIGHT: aClone.maKeyCode = KeyCode(KEY_LEFT, nMod); break;
+ }
+ break;
+
+ case TextDirectionality_TopToBottom_RightToLeft:
+ switch (nCode)
+ {
+ case KEY_DOWN: aClone.maKeyCode = KeyCode(KEY_RIGHT, nMod); break;
+ case KEY_UP: aClone.maKeyCode = KeyCode(KEY_LEFT, nMod); break;
+ case KEY_LEFT: aClone.maKeyCode = KeyCode(KEY_DOWN, nMod); break;
+ case KEY_RIGHT: aClone.maKeyCode = KeyCode(KEY_UP, nMod); break;
+ }
+ break;
+
+ case TextDirectionality_LeftToRight_TopToBottom:
+ /* do nothing */
+ break;
+ }
+
+ return aClone;
+}
+
+
+// -------------------------------------------------------
+
+const Point& HelpEvent::GetMousePosPixel() const
+{
+ //DBG_ASSERT( !mbKeyboardActivated, "Keyboard help has no mouse position !");
+ return maPos;
+}
+
diff --git a/vcl/source/window/makefile.mk b/vcl/source/window/makefile.mk
new file mode 100644
index 000000000000..82ce26f8e78e
--- /dev/null
+++ b/vcl/source/window/makefile.mk
@@ -0,0 +1,104 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=win
+ENABLE_EXCEPTIONS=TRUE
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= \
+ $(SLO)$/arrange.obj \
+ $(SLO)$/abstdlg.obj \
+ $(SLO)$/accel.obj \
+ $(SLO)$/accmgr.obj \
+ $(SLO)$/brdwin.obj \
+ $(SLO)$/btndlg.obj \
+ $(SLO)$/cmdevt.obj \
+ $(SLO)$/cursor.obj \
+ $(SLO)$/decoview.obj \
+ $(SLO)$/dialog.obj \
+ $(SLO)$/dlgctrl.obj \
+ $(SLO)$/dndevdis.obj \
+ $(SLO)$/dndlcon.obj \
+ $(SLO)$/dockingarea.obj \
+ $(SLO)$/dockmgr.obj \
+ $(SLO)$/dockwin.obj \
+ $(SLO)$/floatwin.obj \
+ $(SLO)$/introwin.obj \
+ $(SLO)$/keycod.obj \
+ $(SLO)$/keyevent.obj \
+ $(SLO)$/mouseevent.obj \
+ $(SLO)$/menu.obj \
+ $(SLO)$/mnemonic.obj \
+ $(SLO)$/mnemonicengine.obj \
+ $(SLO)$/msgbox.obj \
+ $(SLO)$/popupmenuwindow.obj \
+ $(SLO)$/scrwnd.obj \
+ $(SLO)$/printdlg.obj \
+ $(SLO)$/seleng.obj \
+ $(SLO)$/split.obj \
+ $(SLO)$/splitwin.obj \
+ $(SLO)$/status.obj \
+ $(SLO)$/syschild.obj \
+ $(SLO)$/javachild.obj \
+ $(SLO)$/syswin.obj \
+ $(SLO)$/tabdlg.obj \
+ $(SLO)$/tabpage.obj \
+ $(SLO)$/taskpanelist.obj \
+ $(SLO)$/toolbox.obj \
+ $(SLO)$/toolbox2.obj \
+ $(SLO)$/window.obj \
+ $(SLO)$/winproc.obj \
+ $(SLO)$/window2.obj \
+ $(SLO)$/window3.obj \
+ $(SLO)$/wrkwin.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
+$(INCCOM)$/cuilib.hxx: makefile.mk
+.IF "$(GUI)"=="UNX"
+ @$(RM) $@
+ @echo \#define DLL_NAME \"libcui$(DLLPOSTFIX)$(DLLPOST)\" >$@
+.ELSE
+ @echo $(EMQ)#define DLL_NAME $(EMQ)"cui$(DLLPOSTFIX)$(DLLPOST)$(EMQ)" >$@
+.ENDIF
+
+$(SLO)$/abstdlg.obj : $(INCCOM)$/cuilib.hxx
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
new file mode 100644
index 000000000000..fa6d9972d32a
--- /dev/null
+++ b/vcl/source/window/menu.cxx
@@ -0,0 +1,6106 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "svsys.h"
+#include "vcl/salinst.hxx"
+#include "tools/list.hxx"
+#include "tools/debug.hxx"
+#include "tools/diagnose_ex.h"
+#include "vcl/svdata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/mnemonic.hxx"
+#include "vcl/image.hxx"
+#include "vcl/event.hxx"
+#include "vcl/help.hxx"
+#include "vcl/svids.hrc"
+#include "vcl/floatwin.hxx"
+#include "vcl/wrkwin.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/sound.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/bitmap.hxx"
+#include "tools/rc.h"
+#include "vcl/menu.hxx"
+#include "vcl/button.hxx"
+#include "vcl/gradient.hxx"
+#include "vcl/i18nhelp.hxx"
+#include "vcl/taskpanelist.hxx"
+#include "vcl/window.h"
+#include "vcl/controllayout.hxx"
+#include "vcl/toolbox.hxx"
+#include "tools/stream.hxx"
+#include "vcl/salmenu.hxx"
+#include "vcl/salframe.hxx"
+#include "vcl/dockingarea.hxx"
+
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <vcl/unowrap.hxx>
+
+#include <vcl/unohelp.hxx>
+#include <vcl/configsettings.hxx>
+
+#include "vcl/lazydelete.hxx"
+
+#include <map>
+
+namespace vcl
+{
+
+struct MenuLayoutData : public ControlLayoutData
+{
+ std::vector< USHORT > m_aLineItemIds;
+ std::vector< USHORT > m_aLineItemPositions;
+ std::map< USHORT, Rectangle > m_aVisibleItemBoundRects;
+};
+
+}
+
+using namespace ::com::sun::star;
+using namespace vcl;
+
+DBG_NAME( Menu )
+
+#define ITEMPOS_INVALID 0xFFFF
+
+#define EXTRASPACEY 2
+#define EXTRAITEMHEIGHT 4
+
+// document closer
+#define IID_DOCUMENTCLOSE 1
+
+#ifdef OS2
+
+#include <xwphook.h>
+
+// return TRUE if hilite should be executed: left mouse button down
+// or xwp mouse hook enabled
+static BOOL ImplHilite( const MouseEvent& rMEvt )
+{
+ static BOOL init = FALSE;
+ static HOOKCONFIG hc;
+
+ // read XWP settings at program startup
+ if (init == FALSE) {
+ BOOL rc;
+ ULONG cb = sizeof(HOOKCONFIG);
+ memset(&hc, 0, sizeof(HOOKCONFIG));
+ rc = PrfQueryProfileData( HINI_USER, INIAPP_XWPHOOK, INIKEY_HOOK_CONFIG,
+ &hc, &cb);
+ init = TRUE;
+ }
+ // check mouse left button
+ if (rMEvt.GetButtons() == MOUSE_LEFT)
+ return TRUE;
+ // return xwp flag
+ return hc.fSlidingMenus;
+}
+
+#endif
+
+static BOOL ImplAccelDisabled()
+{
+ // display of accelerator strings may be suppressed via configuration
+ static int nAccelDisabled = -1;
+
+ if( nAccelDisabled == -1 )
+ {
+ rtl::OUString aStr =
+ vcl::SettingsConfigItem::get()->
+ getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Menu" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuppressAccelerators" ) ) );
+ nAccelDisabled = aStr.equalsIgnoreAsciiCaseAscii( "true" ) ? 1 : 0;
+ }
+ return (nAccelDisabled == 1) ? TRUE : FALSE;
+}
+
+struct MenuItemData
+{
+ USHORT nId; // SV Id
+ MenuItemType eType; // MenuItem-Type
+ MenuItemBits nBits; // MenuItem-Bits
+ Menu* pSubMenu; // Pointer auf das SubMenu
+ Menu* pAutoSubMenu; // Pointer auf SubMenu aus Resource
+ XubString aText; // Menu-Text
+ XubString aHelpText; // Help-String
+ XubString aTipHelpText; // TipHelp-String (eg, expanded filenames)
+ XubString aCommandStr; // CommandString
+ XubString aHelpCommandStr; // Help command string (to reference external help)
+ ULONG nHelpId; // Help-Id
+ ULONG nUserValue; // User value
+ Image aImage; // Image
+ KeyCode aAccelKey; // Accelerator-Key
+ BOOL bChecked; // Checked
+ BOOL bEnabled; // Enabled
+ BOOL bVisible; // Visible (note: this flag will not override MENU_FLAG_HIDEDISABLEDENTRIES when true)
+ BOOL bIsTemporary; // Temporary inserted ('No selection possible')
+ BOOL bMirrorMode;
+ long nItemImageAngle;
+ Size aSz; // nur temporaer gueltig
+ XubString aAccessibleName; // accessible name
+ XubString aAccessibleDescription; // accessible description
+
+ SalMenuItem* pSalMenuItem; // access to native menu
+
+ MenuItemData() :
+ pSalMenuItem ( NULL )
+ {}
+ MenuItemData( const XubString& rStr, const Image& rImage ) :
+ aText( rStr ),
+ aImage( rImage ),
+ pSalMenuItem ( NULL )
+ {}
+ ~MenuItemData();
+ bool HasCheck()
+ {
+ return bChecked || ( nBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) );
+ }
+};
+
+MenuItemData::~MenuItemData()
+{
+ if( pAutoSubMenu )
+ {
+ ((PopupMenu*)pAutoSubMenu)->pRefAutoSubMenu = NULL;
+ delete pAutoSubMenu;
+ pAutoSubMenu = NULL;
+ }
+ if( pSalMenuItem )
+ ImplGetSVData()->mpDefInst->DestroyMenuItem( pSalMenuItem );
+}
+
+class MenuItemList : public List
+{
+private:
+ uno::Reference< i18n::XCharacterClassification > xCharClass;
+
+
+public:
+ MenuItemList() : List( 16, 4 ) {}
+ ~MenuItemList();
+
+ MenuItemData* Insert( USHORT nId, MenuItemType eType, MenuItemBits nBits,
+ const XubString& rStr, const Image& rImage,
+ Menu* pMenu, USHORT nPos );
+ void InsertSeparator( USHORT nPos );
+ void Remove( USHORT nPos );
+
+
+ MenuItemData* GetData( USHORT nSVId, USHORT& rPos ) const;
+ MenuItemData* GetData( USHORT nSVId ) const
+ { USHORT nTemp; return GetData( nSVId, nTemp ); }
+ MenuItemData* GetDataFromPos( ULONG nPos ) const
+ { return (MenuItemData*)List::GetObject( nPos ); }
+
+ MenuItemData* SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const;
+ USHORT GetItemCount( xub_Unicode cSelectChar ) const;
+ USHORT GetItemCount( KeyCode aKeyCode ) const;
+
+ uno::Reference< i18n::XCharacterClassification > GetCharClass() const;
+};
+
+
+
+MenuItemList::~MenuItemList()
+{
+ for ( ULONG n = Count(); n; )
+ {
+ MenuItemData* pData = GetDataFromPos( --n );
+ delete pData;
+ }
+}
+
+MenuItemData* MenuItemList::Insert( USHORT nId, MenuItemType eType,
+ MenuItemBits nBits,
+ const XubString& rStr, const Image& rImage,
+ Menu* pMenu, USHORT nPos )
+{
+ MenuItemData* pData = new MenuItemData( rStr, rImage );
+ pData->nId = nId;
+ pData->eType = eType;
+ pData->nBits = nBits;
+ pData->pSubMenu = NULL;
+ pData->pAutoSubMenu = NULL;
+ pData->nHelpId = 0;
+ pData->nUserValue = 0;
+ pData->bChecked = FALSE;
+ pData->bEnabled = TRUE;
+ pData->bVisible = TRUE;
+ pData->bIsTemporary = FALSE;
+ pData->bMirrorMode = FALSE;
+ pData->nItemImageAngle = 0;
+
+ SalItemParams aSalMIData;
+ aSalMIData.nId = nId;
+ aSalMIData.eType = eType;
+ aSalMIData.nBits = nBits;
+ aSalMIData.pMenu = pMenu;
+ aSalMIData.aText = rStr;
+ aSalMIData.aImage = rImage;
+
+ // Native-support: returns NULL if not supported
+ pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
+
+ List::Insert( (void*)pData, nPos );
+ return pData;
+}
+
+void MenuItemList::InsertSeparator( USHORT nPos )
+{
+ MenuItemData* pData = new MenuItemData;
+ pData->nId = 0;
+ pData->eType = MENUITEM_SEPARATOR;
+ pData->nBits = 0;
+ pData->pSubMenu = NULL;
+ pData->pAutoSubMenu = NULL;
+ pData->nHelpId = 0;
+ pData->nUserValue = 0;
+ pData->bChecked = FALSE;
+ pData->bEnabled = TRUE;
+ pData->bVisible = TRUE;
+ pData->bIsTemporary = FALSE;
+ pData->bMirrorMode = FALSE;
+ pData->nItemImageAngle = 0;
+
+ SalItemParams aSalMIData;
+ aSalMIData.nId = 0;
+ aSalMIData.eType = MENUITEM_SEPARATOR;
+ aSalMIData.nBits = 0;
+ aSalMIData.pMenu = NULL;
+ aSalMIData.aText = XubString();
+ aSalMIData.aImage = Image();
+
+ // Native-support: returns NULL if not supported
+ pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData );
+
+ List::Insert( (void*)pData, nPos );
+}
+
+void MenuItemList::Remove( USHORT nPos )
+{
+ MenuItemData* pData = (MenuItemData*)List::Remove( (ULONG)nPos );
+ if ( pData )
+ delete pData;
+}
+
+MenuItemData* MenuItemList::GetData( USHORT nSVId, USHORT& rPos ) const
+{
+ rPos = 0;
+ MenuItemData* pData = (MenuItemData*)GetObject( rPos );
+ while ( pData )
+ {
+ if ( pData->nId == nSVId )
+ return pData;
+
+ rPos++;
+ pData = (MenuItemData*)GetObject( rPos );
+ }
+
+ return NULL;
+}
+
+MenuItemData* MenuItemList::SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const
+{
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ USHORT nListCount = (USHORT)Count();
+
+ // try character code first
+ nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
+ if( nDuplicates )
+ {
+ for ( rPos = 0; rPos < nListCount; rPos++)
+ {
+ MenuItemData* pData = GetDataFromPos( rPos );
+ if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
+ {
+ if( nDuplicates > 1 && rPos == nCurrentPos )
+ continue; // select next entry with the same mnemonic
+ else
+ return pData;
+ }
+ }
+ }
+
+ // nothing found, try keycode instead
+ nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
+
+ if( nDuplicates )
+ {
+ char ascii = 0;
+ if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
+ ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
+
+ for ( rPos = 0; rPos < nListCount; rPos++)
+ {
+ MenuItemData* pData = GetDataFromPos( rPos );
+ if ( pData->bEnabled )
+ {
+ USHORT n = pData->aText.Search( '~' );
+ if ( n != STRING_NOTFOUND )
+ {
+ KeyCode mnKeyCode;
+ xub_Unicode mnUnicode = pData->aText.GetChar(n+1);
+ Window* pDefWindow = ImplGetDefaultWindow();
+ if( (pDefWindow && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( mnUnicode, Application::GetSettings().GetUILanguage(), mnKeyCode )
+ && aKeyCode.GetCode() == mnKeyCode.GetCode())
+ || (ascii && rI18nHelper.MatchMnemonic( pData->aText, ascii ) ) )
+
+ {
+ if( nDuplicates > 1 && rPos == nCurrentPos )
+ continue; // select next entry with the same mnemonic
+ else
+ return pData;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+USHORT MenuItemList::GetItemCount( xub_Unicode cSelectChar ) const
+{
+ // returns number of entries with same mnemonic
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ USHORT nItems = 0, nPos;
+ for ( nPos = (USHORT)Count(); nPos; )
+ {
+ MenuItemData* pData = GetDataFromPos( --nPos );
+ if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
+ nItems++;
+ }
+
+ return nItems;
+}
+
+USHORT MenuItemList::GetItemCount( KeyCode aKeyCode ) const
+{
+ // returns number of entries with same mnemonic
+ // uses key codes instead of character codes
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+ char ascii = 0;
+ if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
+ ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
+
+ USHORT nItems = 0, nPos;
+ for ( nPos = (USHORT)Count(); nPos; )
+ {
+ MenuItemData* pData = GetDataFromPos( --nPos );
+ if ( pData->bEnabled )
+ {
+ USHORT n = pData->aText.Search( '~' );
+ if ( n != STRING_NOTFOUND )
+ {
+ KeyCode mnKeyCode;
+ // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
+ // so we have working shortcuts when ascii mnemonics are used
+ Window* pDefWindow = ImplGetDefaultWindow();
+ if( (pDefWindow && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText.GetChar(n+1), Application::GetSettings().GetUILanguage(), mnKeyCode )
+ && aKeyCode.GetCode() == mnKeyCode.GetCode())
+ || ( ascii && rI18nHelper.MatchMnemonic( pData->aText, ascii ) ) )
+ nItems++;
+ }
+ }
+ }
+
+ return nItems;
+}
+
+uno::Reference< i18n::XCharacterClassification > MenuItemList::GetCharClass() const
+{
+ if ( !xCharClass.is() )
+ ((MenuItemList*)this)->xCharClass = vcl::unohelper::CreateCharacterClassification();
+ return xCharClass;
+}
+
+
+
+// ----------------------
+// - MenuFloatingWindow -
+// ----------------------
+
+class MenuFloatingWindow : public FloatingWindow
+{
+ friend void Menu::ImplFillLayoutData() const;
+ friend Menu::~Menu();
+
+private:
+ Menu* pMenu;
+ PopupMenu* pActivePopup;
+ Timer aHighlightChangedTimer;
+ Timer aSubmenuCloseTimer;
+ Timer aScrollTimer;
+ ULONG nSaveFocusId;
+// long nStartY;
+ USHORT nHighlightedItem; // gehighlightetes/selektiertes Item
+ USHORT nMBDownPos;
+ USHORT nScrollerHeight;
+ USHORT nFirstEntry;
+ USHORT nBorder;
+ USHORT nPosInParent;
+ BOOL bInExecute;
+
+ BOOL bScrollMenu;
+ BOOL bScrollUp;
+ BOOL bScrollDown;
+ BOOL bIgnoreFirstMove;
+ BOOL bKeyInput;
+
+ DECL_LINK( PopupEnd, FloatingWindow* );
+ DECL_LINK( HighlightChanged, Timer* );
+ DECL_LINK( SubmenuClose, Timer* );
+ DECL_LINK( AutoScroll, Timer* );
+ DECL_LINK( ShowHideListener, VclWindowEvent* );
+
+ void StateChanged( StateChangedType nType );
+ void DataChanged( const DataChangedEvent& rDCEvt );
+protected:
+ Region ImplCalcClipRegion( BOOL bIncludeLogo = TRUE ) const;
+ void ImplInitClipRegion();
+ void ImplDrawScroller( BOOL bUp );
+ using Window::ImplScroll;
+ void ImplScroll( const Point& rMousePos );
+ void ImplScroll( BOOL bUp );
+ void ImplCursorUpDown( BOOL bUp, BOOL bHomeEnd = FALSE );
+ void ImplHighlightItem( const MouseEvent& rMEvt, BOOL bMBDown );
+ long ImplGetStartY() const;
+ Rectangle ImplGetItemRect( USHORT nPos );
+
+public:
+ MenuFloatingWindow( Menu* pMenu, Window* pParent, WinBits nStyle );
+ ~MenuFloatingWindow();
+
+ void doShutdown();
+
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvent );
+ virtual void Command( const CommandEvent& rCEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void Resize();
+
+ void SetFocusId( ULONG nId ) { nSaveFocusId = nId; }
+ ULONG GetFocusId() const { return nSaveFocusId; }
+
+ void EnableScrollMenu( BOOL b );
+ BOOL IsScrollMenu() const { return bScrollMenu; }
+ USHORT GetScrollerHeight() const { return nScrollerHeight; }
+
+ void Execute();
+ void StopExecute( ULONG nFocusId = 0 );
+ void EndExecute();
+ void EndExecute( USHORT nSelectId );
+
+ PopupMenu* GetActivePopup() const { return pActivePopup; }
+ void KillActivePopup( PopupMenu* pThisOnly = NULL );
+
+ void HighlightItem( USHORT nPos, BOOL bHighlight );
+ void ChangeHighlightItem( USHORT n, BOOL bStartPopupTimer );
+ USHORT GetHighlightedItem() const { return nHighlightedItem; }
+
+ void SetPosInParent( USHORT nPos ) { nPosInParent = nPos; }
+ USHORT GetPosInParent() const { return nPosInParent; }
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+};
+
+// To get the transparent mouse-over look, the closer is actually a toolbox
+// overload DataChange to handle style changes correctly
+class DecoToolBox : public ToolBox
+{
+ long lastSize;
+ Size maMinSize;
+
+ using Window::ImplInit;
+public:
+ DecoToolBox( Window* pParent, WinBits nStyle = 0 );
+ DecoToolBox( Window* pParent, const ResId& rResId );
+ void ImplInit();
+
+ void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void SetImages( long nMaxHeight = 0, bool bForce = false );
+
+ void calcMinSize();
+ Size getMinSize();
+
+ Image maImage;
+ Image maImageHC;
+};
+
+DecoToolBox::DecoToolBox( Window* pParent, WinBits nStyle ) :
+ ToolBox( pParent, nStyle )
+{
+ ImplInit();
+}
+DecoToolBox::DecoToolBox( Window* pParent, const ResId& rResId ) :
+ ToolBox( pParent, rResId )
+{
+ ImplInit();
+}
+
+void DecoToolBox::ImplInit()
+{
+ lastSize = -1;
+ calcMinSize();
+}
+
+void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( rDCEvt.GetFlags() & SETTINGS_STYLE )
+ {
+ calcMinSize();
+ SetBackground();
+ SetImages( 0, true);
+ }
+}
+
+void DecoToolBox::calcMinSize()
+{
+ ToolBox aTbx( GetParent() );
+ if( GetItemCount() == 0 )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+
+ Bitmap aBitmap;
+ if( pResMgr )
+ aBitmap = Bitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
+ aTbx.InsertItem( IID_DOCUMENTCLOSE, Image( aBitmap ) );
+ }
+ else
+ {
+ USHORT nItems = GetItemCount();
+ for( USHORT i = 0; i < nItems; i++ )
+ {
+ USHORT nId = GetItemId( i );
+ aTbx.InsertItem( nId, GetItemImage( nId ) );
+ }
+ }
+ aTbx.SetOutStyle( TOOLBOX_STYLE_FLAT );
+ maMinSize = aTbx.CalcWindowSizePixel();
+}
+
+Size DecoToolBox::getMinSize()
+{
+ return maMinSize;
+}
+
+void DecoToolBox::SetImages( long nMaxHeight, bool bForce )
+{
+ long border = getMinSize().Height() - maImage.GetSizePixel().Height();
+
+ if( !nMaxHeight && lastSize != -1 )
+ nMaxHeight = lastSize + border; // don't change anything if called with 0
+
+ if( nMaxHeight < getMinSize().Height() )
+ nMaxHeight = getMinSize().Height();
+
+ if( (lastSize != nMaxHeight - border) || bForce )
+ {
+ lastSize = nMaxHeight - border;
+
+ Color aEraseColor( 255, 255, 255, 255 );
+ BitmapEx aBmpExDst( maImage.GetBitmapEx() );
+ BitmapEx aBmpExSrc( GetSettings().GetStyleSettings().GetHighContrastMode() ?
+ maImageHC.GetBitmapEx() : aBmpExDst );
+
+ aEraseColor.SetTransparency( 255 );
+ aBmpExDst.Erase( aEraseColor );
+ aBmpExDst.SetSizePixel( Size( lastSize, lastSize ) );
+
+ Rectangle aSrcRect( Point(0,0), maImage.GetSizePixel() );
+ Rectangle aDestRect( Point((lastSize - maImage.GetSizePixel().Width())/2,
+ (lastSize - maImage.GetSizePixel().Height())/2 ),
+ maImage.GetSizePixel() );
+
+
+ aBmpExDst.CopyPixel( aDestRect, aSrcRect, &aBmpExSrc );
+ SetItemImage( IID_DOCUMENTCLOSE, Image( aBmpExDst ) );
+ }
+}
+
+
+// Eine Basicklasse fuer beide (wegen pActivePopup, Timer, ...) waere nett,
+// aber dann musste eine 'Container'-Klasse gemacht werden, da von
+// unterschiedlichen Windows abgeleitet...
+// In den meisten Funktionen muessen dann sowieso Sonderbehandlungen fuer
+// MenuBar, PopupMenu gemacht werden, also doch zwei verschiedene Klassen.
+
+class MenuBarWindow : public Window
+{
+ friend class MenuBar;
+ friend class Menu;
+
+private:
+ struct AddButtonEntry
+ {
+ USHORT m_nId;
+ Link m_aSelectLink;
+ Link m_aHighlightLink;
+
+ AddButtonEntry() : m_nId( 0 ) {}
+ };
+
+ Menu* pMenu;
+ PopupMenu* pActivePopup;
+ USHORT nHighlightedItem;
+ ULONG nSaveFocusId;
+ BOOL mbAutoPopup;
+ BOOL bIgnoreFirstMove;
+ BOOL bStayActive;
+
+ DecoToolBox aCloser;
+ PushButton aFloatBtn;
+ PushButton aHideBtn;
+
+ std::map< USHORT, AddButtonEntry > m_aAddButtons;
+
+ void HighlightItem( USHORT nPos, BOOL bHighlight );
+ void ChangeHighlightItem( USHORT n, BOOL bSelectPopupEntry, BOOL bAllowRestoreFocus = TRUE, BOOL bDefaultToDocument = TRUE );
+
+ USHORT ImplFindEntry( const Point& rMousePos ) const;
+ void ImplCreatePopup( BOOL bPreSelectFirst );
+ BOOL ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu = TRUE );
+ Rectangle ImplGetItemRect( USHORT nPos );
+
+ void ImplInitStyleSettings();
+
+ DECL_LINK( CloserHdl, PushButton* );
+ DECL_LINK( FloatHdl, PushButton* );
+ DECL_LINK( HideHdl, PushButton* );
+ DECL_LINK( ToolboxEventHdl, VclWindowEvent* );
+ DECL_LINK( ShowHideListener, VclWindowEvent* );
+
+ void StateChanged( StateChangedType nType );
+ void DataChanged( const DataChangedEvent& rDCEvt );
+ void LoseFocus();
+ void GetFocus();
+
+public:
+ MenuBarWindow( Window* pParent );
+ ~MenuBarWindow();
+
+ void ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide );
+
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvent );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+
+ void SetFocusId( ULONG nId ) { nSaveFocusId = nId; }
+ ULONG GetFocusId() const { return nSaveFocusId; }
+
+ void SetMenu( MenuBar* pMenu );
+ void KillActivePopup();
+ PopupMenu* GetActivePopup() const { return pActivePopup; }
+ void PopupClosed( Menu* pMenu );
+ USHORT GetHighlightedItem() const { return nHighlightedItem; }
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+
+ void SetAutoPopup( BOOL bAuto ) { mbAutoPopup = bAuto; }
+ void ImplLayoutChanged();
+ Size MinCloseButtonSize();
+
+ // add an arbitrary button to the menubar (will appear next to closer)
+ USHORT AddMenuBarButton( const Image&, const Link&, const String&, USHORT nPos );
+ void SetMenuBarButtonHighlightHdl( USHORT nId, const Link& );
+ Rectangle GetMenuBarButtonRectPixel( USHORT nId );
+ void RemoveMenuBarButton( USHORT nId );
+ bool HandleMenuButtonEvent( USHORT i_nButtonId );
+};
+
+static void ImplAddNWFSeparator( Window *pThis, const MenubarValue& rMenubarValue )
+{
+ // add a separator if
+ // - we have an adjacent docking area
+ // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
+ if( rMenubarValue.maTopDockingAreaHeight && !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB )
+ {
+ // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
+
+ pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetSeparatorColor() );
+ Point aPt;
+ Rectangle aRect( aPt, pThis->GetOutputSizePixel() );
+ pThis->DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ }
+}
+
+static void ImplSetMenuItemData( MenuItemData* pData )
+{
+ // Daten umsetzen
+ if ( !pData->aImage )
+ pData->eType = MENUITEM_STRING;
+ else if ( !pData->aText.Len() )
+ pData->eType = MENUITEM_IMAGE;
+ else
+ pData->eType = MENUITEM_STRINGIMAGE;
+}
+
+static ULONG ImplChangeTipTimeout( ULONG nTimeout, Window *pWindow )
+{
+ AllSettings aAllSettings( pWindow->GetSettings() );
+ HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() );
+ ULONG nRet = aHelpSettings.GetTipTimeout();
+ aHelpSettings.SetTipTimeout( nTimeout );
+ aAllSettings.SetHelpSettings( aHelpSettings );
+ pWindow->SetSettings( aAllSettings );
+ return nRet;
+}
+
+static BOOL ImplHandleHelpEvent( Window* pMenuWindow, Menu* pMenu, USHORT nHighlightedItem, const HelpEvent& rHEvt, const Rectangle &rHighlightRect )
+{
+ if( ! pMenu )
+ return FALSE;
+
+ BOOL bDone = FALSE;
+ USHORT nId = 0;
+
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ MenuItemData* pItemData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
+ if ( pItemData )
+ nId = pItemData->nId;
+ }
+
+ if ( ( rHEvt.GetMode() & HELPMODE_BALLOON ) && pMenuWindow )
+ {
+ Point aPos;
+ if( rHEvt.KeyboardActivated() )
+ aPos = rHighlightRect.Center();
+ else
+ aPos = rHEvt.GetMousePosPixel();
+
+ Rectangle aRect( aPos, Size() );
+ if( pMenu->GetHelpText( nId ).Len() )
+ Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) );
+ else
+ {
+ // give user a chance to read the full filename
+ ULONG oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
+ // call always, even when strlen==0 to correctly remove tip
+ Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
+ ImplChangeTipTimeout( oldTimeout, pMenuWindow );
+ }
+ bDone = TRUE;
+ }
+ else if ( ( rHEvt.GetMode() & HELPMODE_QUICK ) && pMenuWindow )
+ {
+ Point aPos = rHEvt.GetMousePosPixel();
+ Rectangle aRect( aPos, Size() );
+ // give user a chance to read the full filename
+ ULONG oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow );
+ // call always, even when strlen==0 to correctly remove tip
+ Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) );
+ ImplChangeTipTimeout( oldTimeout, pMenuWindow );
+ bDone = TRUE;
+ }
+ else if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
+ {
+ // Ist eine Hilfe in die Applikation selektiert
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ // Ist eine ID vorhanden, dann Hilfe mit der ID aufrufen, sonst
+ // den Hilfe-Index
+ String aCommand = pMenu->GetItemCommand( nId );
+ ULONG nHelpId = pMenu->GetHelpId( nId );
+
+ if ( aCommand.Len() )
+ pHelp->Start( aCommand, NULL );
+ else if ( nHelpId )
+ pHelp->Start( nHelpId, NULL );
+ else
+ pHelp->Start( OOO_HELP_INDEX, NULL );
+ }
+ bDone = TRUE;
+ }
+ return bDone;
+}
+
+static int ImplGetTopDockingAreaHeight( Window *pWindow )
+{
+ // find docking area that is top aligned and return its height
+ // note: dockingareas are direct children of the SystemWindow
+ int height=0;
+ BOOL bDone = FALSE;
+ if( pWindow->ImplGetFrameWindow() )
+ {
+ Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild;
+ while( pWin && !bDone )
+ {
+ if( pWin->IsSystemWindow() )
+ {
+ pWin = pWin->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild;
+ while( pWin && !bDone )
+ {
+ DockingAreaWindow *pDockingArea = dynamic_cast< DockingAreaWindow* >( pWin );
+ if( pDockingArea && pDockingArea->GetAlign() == WINDOWALIGN_TOP )
+ {
+ bDone = TRUE;
+ if( pDockingArea->IsVisible() )
+ height = pDockingArea->GetOutputSizePixel().Height();
+ }
+ else
+ pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
+ }
+
+ }
+ else
+ pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext;
+ }
+ }
+ return height;
+}
+
+Menu::Menu()
+{
+ DBG_CTOR( Menu, NULL );
+ bIsMenuBar = FALSE;
+ ImplInit();
+}
+
+// this constructor makes sure we're creating the native menu
+// with the correct type (ie, MenuBar vs. PopupMenu)
+Menu::Menu( BOOL bMenubar )
+{
+ DBG_CTOR( Menu, NULL );
+ bIsMenuBar = bMenubar;
+ ImplInit();
+}
+
+Menu::~Menu()
+{
+ DBG_DTOR( Menu, NULL );
+
+ vcl::LazyDeletor<Menu>::Undelete( this );
+
+ ImplCallEventListeners( VCLEVENT_OBJECT_DYING, ITEMPOS_INVALID );
+
+ // at the window free the reference to the accessible component
+ // and make sure the MenuFloatingWindow knows about our destruction
+ if ( pWindow )
+ {
+ MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
+ if( pFloat->pMenu == this )
+ pFloat->pMenu = NULL;
+ pWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
+ }
+
+ // dispose accessible components
+ if ( mxAccessible.is() )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComponent( mxAccessible, ::com::sun::star::uno::UNO_QUERY );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+
+ if ( nEventId )
+ Application::RemoveUserEvent( nEventId );
+
+ // Notify deletion of this menu
+ ImplMenuDelData* pDelData = mpFirstDel;
+ while ( pDelData )
+ {
+ pDelData->mpMenu = NULL;
+ pDelData = pDelData->mpNext;
+ }
+
+ bKilled = TRUE;
+
+ delete pItemList;
+ delete pLogo;
+ delete mpLayoutData;
+
+ // Native-support: destroy SalMenu
+ ImplSetSalMenu( NULL );
+}
+
+void Menu::doLazyDelete()
+{
+ vcl::LazyDeletor<Menu>::Delete( this );
+}
+
+void Menu::ImplInit()
+{
+ mnHighlightedItemPos = ITEMPOS_INVALID;
+ mpSalMenu = NULL;
+ nMenuFlags = 0;
+ nDefaultItem = 0;
+ //bIsMenuBar = FALSE; // this is now set in the ctor, must not be changed here!!!
+ nSelectedId = 0;
+ pItemList = new MenuItemList;
+ pLogo = NULL;
+ pStartedFrom = NULL;
+ pWindow = NULL;
+ nEventId = 0;
+ bCanceled = FALSE;
+ bInCallback = FALSE;
+ bKilled = FALSE;
+ mpLayoutData = NULL;
+ mpFirstDel = NULL; // Dtor notification list
+ // Native-support: returns NULL if not supported
+ mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu( bIsMenuBar );
+}
+
+Menu* Menu::ImplGetStartedFrom() const
+{
+ return pStartedFrom;
+}
+
+void Menu::ImplLoadRes( const ResId& rResId )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( ! pMgr )
+ return;
+
+ rResId.SetRT( RSC_MENU );
+ GetRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if( nObjMask & RSC_MENU_ITEMS )
+ {
+ ULONG nObjFollows = ReadLongRes();
+ // MenuItems einfuegen
+ for( ULONG i = 0; i < nObjFollows; i++ )
+ {
+ InsertItem( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ }
+
+ if( nObjMask & RSC_MENU_TEXT )
+ {
+ if( bIsMenuBar ) // Kein Titel im Menubar
+ ReadStringRes();
+ else
+ aTitleText = ReadStringRes();
+ }
+ if( nObjMask & RSC_MENU_DEFAULTITEMID )
+ SetDefaultItem( sal::static_int_cast<USHORT>(ReadLongRes()) );
+}
+
+void Menu::CreateAutoMnemonics()
+{
+ MnemonicGenerator aMnemonicGenerator;
+ ULONG n;
+ for ( n = 0; n < pItemList->Count(); n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos(n);
+ if ( ! (pData->nBits & MIB_NOSELECT ) )
+ aMnemonicGenerator.RegisterMnemonic( pData->aText );
+ }
+ for ( n = 0; n < pItemList->Count(); n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos(n);
+ if ( ! (pData->nBits & MIB_NOSELECT ) )
+ aMnemonicGenerator.CreateMnemonic( pData->aText );
+ }
+}
+
+void Menu::Activate()
+{
+ bInCallback = TRUE;
+
+ ImplMenuDelData aDelData( this );
+
+ ImplCallEventListeners( VCLEVENT_MENU_ACTIVATE, ITEMPOS_INVALID );
+
+ if( !aDelData.isDeleted() )
+ {
+ if ( !aActivateHdl.Call( this ) )
+ {
+ if( !aDelData.isDeleted() )
+ {
+ Menu* pStartMenu = ImplGetStartMenu();
+ if ( pStartMenu && ( pStartMenu != this ) )
+ {
+ pStartMenu->bInCallback = TRUE;
+ // MT 11/01: Call EventListener here? I don't know...
+ pStartMenu->aActivateHdl.Call( this );
+ pStartMenu->bInCallback = FALSE;
+ }
+ }
+ }
+ bInCallback = FALSE;
+ }
+}
+
+void Menu::Deactivate()
+{
+ for ( USHORT n = (USHORT)pItemList->Count(); n; )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( --n );
+ if ( pData->bIsTemporary )
+ pItemList->Remove( n );
+ }
+
+ bInCallback = TRUE;
+
+ ImplMenuDelData aDelData( this );
+
+ Menu* pStartMenu = ImplGetStartMenu();
+ ImplCallEventListeners( VCLEVENT_MENU_DEACTIVATE, ITEMPOS_INVALID );
+
+ if( !aDelData.isDeleted() )
+ {
+ if ( !aDeactivateHdl.Call( this ) )
+ {
+ if( !aDelData.isDeleted() )
+ {
+ if ( pStartMenu && ( pStartMenu != this ) )
+ {
+ pStartMenu->bInCallback = TRUE;
+ pStartMenu->aDeactivateHdl.Call( this );
+ pStartMenu->bInCallback = FALSE;
+ }
+ }
+ }
+ }
+
+ if( !aDelData.isDeleted() )
+ {
+ bInCallback = FALSE;
+
+ if ( this == pStartMenu )
+ GetpApp()->HideHelpStatusText();
+ }
+}
+
+void Menu::Highlight()
+{
+ ImplMenuDelData aDelData( this );
+
+ Menu* pStartMenu = ImplGetStartMenu();
+ if ( !aHighlightHdl.Call( this ) && !aDelData.isDeleted() )
+ {
+ if ( pStartMenu && ( pStartMenu != this ) )
+ pStartMenu->aHighlightHdl.Call( this );
+ }
+
+ if ( !aDelData.isDeleted() && GetCurItemId() )
+ GetpApp()->ShowHelpStatusText( GetHelpText( GetCurItemId() ) );
+}
+
+void Menu::ImplSelect()
+{
+ MenuItemData* pData = GetItemList()->GetData( nSelectedId );
+ if ( pData && (pData->nBits & MIB_AUTOCHECK) )
+ {
+ BOOL bChecked = IsItemChecked( nSelectedId );
+ if ( pData->nBits & MIB_RADIOCHECK )
+ {
+ if ( !bChecked )
+ CheckItem( nSelectedId, TRUE );
+ }
+ else
+ CheckItem( nSelectedId, !bChecked );
+ }
+
+ // Select rufen
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mpActivePopupMenu = NULL; // Falls neues Execute im Select()
+ Application::PostUserEvent( nEventId, LINK( this, Menu, ImplCallSelect ) );
+}
+
+void Menu::Select()
+{
+ ImplMenuDelData aDelData( this );
+
+ ImplCallEventListeners( VCLEVENT_MENU_SELECT, GetItemPos( GetCurItemId() ) );
+ if ( !aDelData.isDeleted() && !aSelectHdl.Call( this ) )
+ {
+ if( !aDelData.isDeleted() )
+ {
+ Menu* pStartMenu = ImplGetStartMenu();
+ if ( pStartMenu && ( pStartMenu != this ) )
+ {
+ pStartMenu->nSelectedId = nSelectedId;
+ pStartMenu->aSelectHdl.Call( this );
+ }
+ }
+ }
+}
+
+void Menu::ImplSelectWithStart( Menu* pSMenu )
+{
+ Menu* pOldStartedFrom = pStartedFrom;
+ pStartedFrom = pSMenu;
+ Menu* pOldStartedStarted = pOldStartedFrom ? pOldStartedFrom->pStartedFrom : NULL;
+ Select();
+ if( pOldStartedFrom )
+ pOldStartedFrom->pStartedFrom = pOldStartedStarted;
+ pStartedFrom = pOldStartedFrom;
+}
+
+void Menu::RequestHelp( const HelpEvent& )
+{
+}
+
+void Menu::ImplCallEventListeners( ULONG nEvent, USHORT nPos )
+{
+ ImplMenuDelData aDelData( this );
+
+ VclMenuEvent aEvent( this, nEvent, nPos );
+
+ // This is needed by atk accessibility bridge
+ if ( nEvent == VCLEVENT_MENU_HIGHLIGHT )
+ {
+ ImplGetSVData()->mpApp->ImplCallEventListeners( &aEvent );
+ }
+
+ if ( !aDelData.isDeleted() && !maEventListeners.empty() )
+ maEventListeners.Call( &aEvent );
+
+ if( !aDelData.isDeleted() )
+ {
+ Menu* pMenu = this;
+ while ( pMenu )
+ {
+ if ( !maChildEventListeners.empty() )
+ maChildEventListeners.Call( &aEvent );
+
+ if( aDelData.isDeleted() )
+ break;
+
+ pMenu = ( pMenu->pStartedFrom != pMenu ) ? pMenu->pStartedFrom : NULL;
+ }
+ }
+}
+
+void Menu::AddEventListener( const Link& rEventListener )
+{
+ maEventListeners.push_back( rEventListener );
+}
+
+void Menu::RemoveEventListener( const Link& rEventListener )
+{
+ maEventListeners.remove( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+
+//void Menu::AddChildEventListener( const Link& rEventListener )
+//{
+// mpDummy4_WindowChildEventListeners->push_back( rEventListener );
+//}
+
+// -----------------------------------------------------------------------
+
+//void Menu::RemoveChildEventListener( const Link& rEventListener )
+//{
+// mpDummy4_WindowChildEventListeners->remove( rEventListener );
+//}
+
+void Menu::InsertItem( USHORT nItemId, const XubString& rStr, MenuItemBits nItemBits, USHORT nPos )
+{
+ DBG_ASSERT( nItemId, "Menu::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == MENU_ITEM_NOTFOUND,
+ "Menu::InsertItem(): ItemId already exists" );
+
+ // if Position > ItemCount, append
+ if ( nPos >= (USHORT)pItemList->Count() )
+ nPos = MENU_APPEND;
+
+ // put Item in MenuItemList
+ MenuItemData* pData = pItemList->Insert( nItemId, MENUITEM_STRING,
+ nItemBits, rStr, Image(), this, nPos );
+
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
+
+ Window* pWin = ImplGetWindow();
+ delete mpLayoutData, mpLayoutData = NULL;
+ if ( pWin )
+ {
+ ImplCalcSize( pWin );
+ if ( pWin->IsVisible() )
+ pWin->Invalidate();
+ }
+ ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
+}
+
+void Menu::InsertItem( USHORT nItemId, const Image& rImage,
+ MenuItemBits nItemBits, USHORT nPos )
+{
+ InsertItem( nItemId, ImplGetSVEmptyStr(), nItemBits, nPos );
+ SetItemImage( nItemId, rImage );
+}
+
+void Menu::InsertItem( USHORT nItemId,
+ const XubString& rStr, const Image& rImage,
+ MenuItemBits nItemBits, USHORT nPos )
+{
+ InsertItem( nItemId, rStr, nItemBits, nPos );
+ SetItemImage( nItemId, rImage );
+}
+
+void Menu::InsertItem( const ResId& rResId, USHORT nPos )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( ! pMgr )
+ return;
+
+ ULONG nObjMask;
+
+ GetRes( rResId.SetRT( RSC_MENUITEM ) );
+ nObjMask = ReadLongRes();
+
+ BOOL bSep = FALSE;
+ if ( nObjMask & RSC_MENUITEM_SEPARATOR )
+ bSep = (BOOL)ReadShortRes();
+
+ USHORT nItemId = 1;
+ if ( nObjMask & RSC_MENUITEM_ID )
+ nItemId = sal::static_int_cast<USHORT>(ReadLongRes());
+
+ MenuItemBits nStatus = 0;
+ if ( nObjMask & RSC_MENUITEM_STATUS )
+ nStatus = sal::static_int_cast<MenuItemBits>(ReadLongRes());
+
+ String aText;
+ if ( nObjMask & RSC_MENUITEM_TEXT )
+ aText = ReadStringRes();
+
+ // Item erzeugen
+ if ( nObjMask & RSC_MENUITEM_BITMAP )
+ {
+ if ( !bSep )
+ {
+ Bitmap aBmp( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
+ if ( aText.Len() )
+ InsertItem( nItemId, aText, aBmp, nStatus, nPos );
+ else
+ InsertItem( nItemId, aBmp, nStatus, nPos );
+ }
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ else if ( !bSep )
+ InsertItem( nItemId, aText, nStatus, nPos );
+ if ( bSep )
+ InsertSeparator( nPos );
+
+ String aHelpText;
+ if ( nObjMask & RSC_MENUITEM_HELPTEXT )
+ {
+ aHelpText = ReadStringRes();
+ if( !bSep )
+ SetHelpText( nItemId, aHelpText );
+ }
+
+ ULONG nHelpId = 0;
+ if ( nObjMask & RSC_MENUITEM_HELPID )
+ {
+ nHelpId = ReadLongRes();
+ if ( !bSep )
+ SetHelpId( nItemId, nHelpId );
+ }
+
+ if( !bSep /* && SvHelpSettings::HelpText( aHelpText, nHelpId ) */ )
+ SetHelpText( nItemId, aHelpText );
+
+ if ( nObjMask & RSC_MENUITEM_KEYCODE )
+ {
+ if ( !bSep )
+ SetAccelKey( nItemId, KeyCode( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ if( nObjMask & RSC_MENUITEM_CHECKED )
+ {
+ if ( !bSep )
+ CheckItem( nItemId, (BOOL)ReadShortRes() );
+ }
+ if ( nObjMask & RSC_MENUITEM_DISABLE )
+ {
+ if ( !bSep )
+ EnableItem( nItemId, !(BOOL)ReadShortRes() );
+ }
+ if ( nObjMask & RSC_MENUITEM_COMMAND )
+ {
+ String aCommandStr = ReadStringRes();
+ if ( !bSep )
+ SetItemCommand( nItemId, aCommandStr );
+ }
+ if ( nObjMask & RSC_MENUITEM_MENU )
+ {
+ if ( !bSep )
+ {
+ MenuItemData* pData = GetItemList()->GetData( nItemId );
+ if ( pData )
+ {
+ PopupMenu* pSubMenu = new PopupMenu( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
+ pData->pAutoSubMenu = pSubMenu;
+ // #111060# keep track of this pointer, may be it will be deleted from outside
+ pSubMenu->pRefAutoSubMenu = &pData->pAutoSubMenu;
+ SetPopupMenu( nItemId, pSubMenu );
+ }
+ }
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+ delete mpLayoutData, mpLayoutData = NULL;
+}
+
+void Menu::InsertSeparator( USHORT nPos )
+{
+ // do nothing if its a menu bar
+ if ( bIsMenuBar )
+ return;
+
+ // if position > ItemCount, append
+ if ( nPos >= (USHORT)pItemList->Count() )
+ nPos = MENU_APPEND;
+
+ // put separator in item list
+ pItemList->InsertSeparator( nPos );
+
+ // update native menu
+ USHORT itemPos = nPos != MENU_APPEND ? nPos : (USHORT)pItemList->Count() - 1;
+ MenuItemData *pData = pItemList->GetDataFromPos( itemPos );
+ if( ImplGetSalMenu() && pData && pData->pSalMenuItem )
+ ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos );
+
+ delete mpLayoutData, mpLayoutData = NULL;
+
+ ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos );
+}
+
+void Menu::RemoveItem( USHORT nPos )
+{
+ BOOL bRemove = FALSE;
+
+ if ( nPos < GetItemCount() )
+ {
+ // update native menu
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->RemoveItem( nPos );
+
+ pItemList->Remove( nPos );
+ bRemove = TRUE;
+ }
+
+ Window* pWin = ImplGetWindow();
+ if ( pWin )
+ {
+ ImplCalcSize( pWin );
+ if ( pWin->IsVisible() )
+ pWin->Invalidate();
+ }
+ delete mpLayoutData, mpLayoutData = NULL;
+
+ if ( bRemove )
+ ImplCallEventListeners( VCLEVENT_MENU_REMOVEITEM, nPos );
+}
+
+void ImplCopyItem( Menu* pThis, const Menu& rMenu, USHORT nPos, USHORT nNewPos,
+ USHORT nMode = 0 )
+{
+ MenuItemType eType = rMenu.GetItemType( nPos );
+
+ if ( eType == MENUITEM_DONTKNOW )
+ return;
+
+ if ( eType == MENUITEM_SEPARATOR )
+ pThis->InsertSeparator( nNewPos );
+ else
+ {
+ USHORT nId = rMenu.GetItemId( nPos );
+
+ DBG_ASSERT( pThis->GetItemPos( nId ) == MENU_ITEM_NOTFOUND,
+ "Menu::CopyItem(): ItemId already exists" );
+
+ MenuItemData* pData = rMenu.GetItemList()->GetData( nId );
+
+ if ( eType == MENUITEM_STRINGIMAGE )
+ pThis->InsertItem( nId, pData->aText, pData->aImage, pData->nBits, nNewPos );
+ else if ( eType == MENUITEM_STRING )
+ pThis->InsertItem( nId, pData->aText, pData->nBits, nNewPos );
+ else
+ pThis->InsertItem( nId, pData->aImage, pData->nBits, nNewPos );
+
+ if ( rMenu.IsItemChecked( nId ) )
+ pThis->CheckItem( nId, TRUE );
+ if ( !rMenu.IsItemEnabled( nId ) )
+ pThis->EnableItem( nId, FALSE );
+ pThis->SetHelpId( nId, pData->nHelpId );
+ pThis->SetHelpText( nId, pData->aHelpText );
+ pThis->SetAccelKey( nId, pData->aAccelKey );
+ pThis->SetItemCommand( nId, pData->aCommandStr );
+ pThis->SetHelpCommand( nId, pData->aHelpCommandStr );
+
+ PopupMenu* pSubMenu = rMenu.GetPopupMenu( nId );
+ if ( pSubMenu )
+ {
+ // AutoKopie anlegen
+ if ( nMode == 1 )
+ {
+ PopupMenu* pNewMenu = new PopupMenu( *pSubMenu );
+ pThis->SetPopupMenu( nId, pNewMenu );
+// SetAutoMenu( pThis, nId, pNewMenu );
+ }
+ else
+ pThis->SetPopupMenu( nId, pSubMenu );
+ }
+ }
+}
+
+void Menu::CopyItem( const Menu& rMenu, USHORT nPos, USHORT nNewPos )
+{
+ ImplCopyItem( this, rMenu, nPos, nNewPos );
+}
+
+void Menu::Clear()
+{
+ for ( USHORT i = GetItemCount(); i; i-- )
+ RemoveItem( 0 );
+}
+
+USHORT Menu::GetItemCount() const
+{
+ return (USHORT)pItemList->Count();
+}
+
+USHORT Menu::ImplGetVisibleItemCount() const
+{
+ USHORT nItems = 0;
+ for ( USHORT n = (USHORT)pItemList->Count(); n; )
+ {
+ if ( ImplIsVisible( --n ) )
+ nItems++;
+ }
+ return nItems;
+}
+
+USHORT Menu::ImplGetFirstVisible() const
+{
+ for ( USHORT n = 0; n < pItemList->Count(); n++ )
+ {
+ if ( ImplIsVisible( n ) )
+ return n;
+ }
+ return ITEMPOS_INVALID;
+}
+
+USHORT Menu::ImplGetPrevVisible( USHORT nPos ) const
+{
+ for ( USHORT n = nPos; n; )
+ {
+ if ( n && ImplIsVisible( --n ) )
+ return n;
+ }
+ return ITEMPOS_INVALID;
+}
+
+USHORT Menu::ImplGetNextVisible( USHORT nPos ) const
+{
+ for ( USHORT n = nPos+1; n < pItemList->Count(); n++ )
+ {
+ if ( ImplIsVisible( n ) )
+ return n;
+ }
+ return ITEMPOS_INVALID;
+}
+
+USHORT Menu::GetItemId( USHORT nPos ) const
+{
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+
+ if ( pData )
+ return pData->nId;
+ else
+ return 0;
+}
+
+USHORT Menu::GetItemPos( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ return nPos;
+ else
+ return MENU_ITEM_NOTFOUND;
+}
+
+MenuItemType Menu::GetItemType( USHORT nPos ) const
+{
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+
+ if ( pData )
+ return pData->eType;
+ else
+ return MENUITEM_DONTKNOW;
+}
+
+USHORT Menu::GetCurItemId() const
+{
+ return nSelectedId;
+}
+
+void Menu::SetItemBits( USHORT nItemId, MenuItemBits nBits )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if ( pData )
+ pData->nBits = nBits;
+}
+
+MenuItemBits Menu::GetItemBits( USHORT nItemId ) const
+{
+ MenuItemBits nBits = 0;
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if ( pData )
+ nBits = pData->nBits;
+ return nBits;
+}
+
+void Menu::SetUserValue( USHORT nItemId, ULONG nValue )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if ( pData )
+ pData->nUserValue = nValue;
+}
+
+ULONG Menu::GetUserValue( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ return pData ? pData->nUserValue : 0;
+}
+
+void Menu::SetPopupMenu( USHORT nItemId, PopupMenu* pMenu )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ // Item does not exist -> return NULL
+ if ( !pData )
+ return;
+
+ // same menu, nothing to do
+ if ( (PopupMenu*)pData->pSubMenu == pMenu )
+ return;
+
+ // data exchange
+ pData->pSubMenu = pMenu;
+
+ // #112023# Make sure pStartedFrom does not point to invalid (old) data
+ if ( pData->pSubMenu )
+ pData->pSubMenu->pStartedFrom = 0;
+
+ // set native submenu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ {
+ if( pMenu )
+ ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, pMenu->ImplGetSalMenu(), nPos );
+ else
+ ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, NULL, nPos );
+ }
+
+ ImplCallEventListeners( VCLEVENT_MENU_SUBMENUCHANGED, nPos );
+}
+
+PopupMenu* Menu::GetPopupMenu( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return (PopupMenu*)(pData->pSubMenu);
+ else
+ return NULL;
+}
+
+void Menu::SetAccelKey( USHORT nItemId, const KeyCode& rKeyCode )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return;
+
+ if ( pData->aAccelKey == rKeyCode )
+ return;
+
+ pData->aAccelKey = rKeyCode;
+
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem, rKeyCode, rKeyCode.GetName() );
+}
+
+KeyCode Menu::GetAccelKey( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aAccelKey;
+ else
+ return KeyCode();
+}
+
+KeyEvent Menu::GetActivationKey( USHORT nItemId ) const
+{
+ KeyEvent aRet;
+ MenuItemData* pData = pItemList->GetData( nItemId );
+ if( pData )
+ {
+ USHORT nPos = pData->aText.Search( '~' );
+ if( nPos != STRING_NOTFOUND && nPos < pData->aText.Len()-1 )
+ {
+ USHORT nCode = 0;
+ sal_Unicode cAccel = pData->aText.GetChar( nPos+1 );
+ if( cAccel >= 'a' && cAccel <= 'z' )
+ nCode = KEY_A + (cAccel-'a');
+ else if( cAccel >= 'A' && cAccel <= 'Z' )
+ nCode = KEY_A + (cAccel-'A');
+ else if( cAccel >= '0' && cAccel <= '9' )
+ nCode = KEY_0 + (cAccel-'0');
+ if(nCode )
+ aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) );
+ }
+
+ }
+ return aRet;
+}
+
+void Menu::CheckItem( USHORT nItemId, BOOL bCheck )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData || pData->bChecked == bCheck )
+ return;
+
+ // Wenn RadioCheck, dann vorherigen unchecken
+ if ( bCheck && (pData->nBits & MIB_AUTOCHECK) &&
+ (pData->nBits & MIB_RADIOCHECK) )
+ {
+ MenuItemData* pGroupData;
+ USHORT nGroupPos;
+ USHORT nItemCount = GetItemCount();
+ BOOL bFound = FALSE;
+
+ nGroupPos = nPos;
+ while ( nGroupPos )
+ {
+ pGroupData = pItemList->GetDataFromPos( nGroupPos-1 );
+ if ( pGroupData->nBits & MIB_RADIOCHECK )
+ {
+ if ( IsItemChecked( pGroupData->nId ) )
+ {
+ CheckItem( pGroupData->nId, FALSE );
+ bFound = TRUE;
+ break;
+ }
+ }
+ else
+ break;
+ nGroupPos--;
+ }
+
+ if ( !bFound )
+ {
+ nGroupPos = nPos+1;
+ while ( nGroupPos < nItemCount )
+ {
+ pGroupData = pItemList->GetDataFromPos( nGroupPos );
+ if ( pGroupData->nBits & MIB_RADIOCHECK )
+ {
+ if ( IsItemChecked( pGroupData->nId ) )
+ {
+ CheckItem( pGroupData->nId, FALSE );
+ break;
+ }
+ }
+ else
+ break;
+ nGroupPos++;
+ }
+ }
+ }
+
+ pData->bChecked = bCheck;
+
+ // update native menu
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->CheckItem( nPos, bCheck );
+
+ ImplCallEventListeners( bCheck ? VCLEVENT_MENU_ITEMCHECKED : VCLEVENT_MENU_ITEMUNCHECKED, nPos );
+}
+
+BOOL Menu::IsItemChecked( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return FALSE;
+
+ return pData->bChecked;
+}
+
+void Menu::EnableItem( USHORT nItemId, BOOL bEnable )
+{
+ USHORT nPos;
+ MenuItemData* pItemData = pItemList->GetData( nItemId, nPos );
+
+ if ( pItemData && ( pItemData->bEnabled != bEnable ) )
+ {
+ pItemData->bEnabled = bEnable;
+
+ Window* pWin = ImplGetWindow();
+ if ( pWin && pWin->IsVisible() )
+ {
+ DBG_ASSERT( bIsMenuBar, "Menu::EnableItem - Popup visible!" );
+ long nX = 0;
+ ULONG nCount = pItemList->Count();
+ for ( ULONG n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ pWin->Invalidate( Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) );
+ break;
+ }
+ nX += pData->aSz.Width();
+ }
+ }
+ // update native menu
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->EnableItem( nPos, bEnable );
+
+ ImplCallEventListeners( bEnable ? VCLEVENT_MENU_ENABLE : VCLEVENT_MENU_DISABLE, nPos );
+ }
+}
+
+BOOL Menu::IsItemEnabled( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return FALSE;
+
+ return pData->bEnabled;
+}
+
+void Menu::ShowItem( USHORT nItemId, BOOL bVisible )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ DBG_ASSERT( !bIsMenuBar, "Menu::ShowItem - ignored for menu bar entries!" );
+ if ( !bIsMenuBar && pData && ( pData->bVisible != bVisible ) )
+ {
+ Window* pWin = ImplGetWindow();
+ if ( pWin && pWin->IsVisible() )
+ {
+ DBG_ASSERT( 0, "Menu::ShowItem - ignored for visible popups!" );
+ return;
+ }
+ pData->bVisible = bVisible;
+
+ // update native menu
+ // as long as there is no support to hide native menu entries, we just disable them
+ // TODO: add support to show/hide native menu entries
+ if( ImplGetSalMenu() )
+ ImplGetSalMenu()->EnableItem( nPos, bVisible );
+ }
+}
+
+void Menu::SetItemText( USHORT nItemId, const XubString& rStr )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return;
+
+ if ( !rStr.Equals( pData->aText ) )
+ {
+ pData->aText = rStr;
+ ImplSetMenuItemData( pData );
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem, rStr );
+
+ Window* pWin = ImplGetWindow();
+ delete mpLayoutData, mpLayoutData = NULL;
+ if ( pWin && IsMenuBar() )
+ {
+ ImplCalcSize( pWin );
+ if ( pWin->IsVisible() )
+ pWin->Invalidate();
+ }
+
+ ImplCallEventListeners( VCLEVENT_MENU_ITEMTEXTCHANGED, nPos );
+ }
+}
+
+XubString Menu::GetItemText( USHORT nItemId ) const
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ return pData->aText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetItemImage( USHORT nItemId, const Image& rImage )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( !pData )
+ return;
+
+ pData->aImage = rImage;
+ ImplSetMenuItemData( pData );
+
+ // update native menu
+ if( ImplGetSalMenu() && pData->pSalMenuItem )
+ ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem, rImage );
+}
+
+static inline Image ImplRotImage( const Image& rImage, long nAngle10 )
+{
+ Image aRet;
+ BitmapEx aBmpEx( rImage.GetBitmapEx() );
+
+ aBmpEx.Rotate( nAngle10, COL_WHITE );
+
+ return Image( aBmpEx );
+}
+
+void Menu::SetItemImageAngle( USHORT nItemId, long nAngle10 )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ {
+ long nDeltaAngle = (nAngle10 - pData->nItemImageAngle) % 3600;
+ while( nDeltaAngle < 0 )
+ nDeltaAngle += 3600;
+
+ pData->nItemImageAngle = nAngle10;
+ if( nDeltaAngle && !!pData->aImage )
+ pData->aImage = ImplRotImage( pData->aImage, nDeltaAngle );
+ }
+}
+
+static inline Image ImplMirrorImage( const Image& rImage )
+{
+ Image aRet;
+ BitmapEx aBmpEx( rImage.GetBitmapEx() );
+
+ aBmpEx.Mirror( BMP_MIRROR_HORZ );
+
+ return Image( aBmpEx );
+}
+
+void Menu::SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData )
+ {
+ if( ( pData->bMirrorMode && ! bMirror ) ||
+ ( ! pData->bMirrorMode && bMirror )
+ )
+ {
+ pData->bMirrorMode = bMirror ? true : false;
+ if( !!pData->aImage )
+ pData->aImage = ImplMirrorImage( pData->aImage );
+ }
+ }
+}
+
+Image Menu::GetItemImage( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aImage;
+ else
+ return Image();
+}
+
+long Menu::GetItemImageAngle( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->nItemImageAngle;
+ else
+ return 0;
+}
+
+BOOL Menu::GetItemImageMirrorMode( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->bMirrorMode;
+ else
+ return FALSE;
+}
+
+void Menu::SetItemCommand( USHORT nItemId, const String& rCommand )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aCommandStr = rCommand;
+}
+
+const XubString& Menu::GetItemCommand( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aCommandStr;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetHelpCommand( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aHelpCommandStr = rStr;
+}
+
+const XubString& Menu::GetHelpCommand( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aHelpCommandStr;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetHelpText( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aHelpText = rStr;
+}
+
+const XubString& Menu::ImplGetHelpText( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ {
+ if ( !pData->aHelpText.Len() &&
+ (( pData->nHelpId ) || ( pData->aCommandStr.Len() )))
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if ( pData->aCommandStr.Len() )
+ pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, NULL );
+
+ if( !pData->aHelpText.Len() && pData->nHelpId )
+ pData->aHelpText = pHelp->GetHelpText( pData->nHelpId, NULL );
+ }
+ }
+
+ return pData->aHelpText;
+ }
+ else
+ return ImplGetSVEmptyStr();
+}
+
+const XubString& Menu::GetHelpText( USHORT nItemId ) const
+{
+ return ImplGetHelpText( nItemId );
+}
+
+void Menu::SetTipHelpText( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aTipHelpText = rStr;
+}
+
+const XubString& Menu::GetTipHelpText( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aTipHelpText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetHelpId( USHORT nItemId, ULONG nHelpId )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->nHelpId = nHelpId;
+}
+
+ULONG Menu::GetHelpId( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->nHelpId;
+ else
+ return 0;
+}
+
+Menu& Menu::operator=( const Menu& rMenu )
+{
+ // Aufraeumen
+ Clear();
+
+ // Items kopieren
+ USHORT nCount = rMenu.GetItemCount();
+ for ( USHORT i = 0; i < nCount; i++ )
+ ImplCopyItem( this, rMenu, i, MENU_APPEND, 1 );
+
+ nDefaultItem = rMenu.nDefaultItem;
+ aActivateHdl = rMenu.aActivateHdl;
+ aDeactivateHdl = rMenu.aDeactivateHdl;
+ aHighlightHdl = rMenu.aHighlightHdl;
+ aSelectHdl = rMenu.aSelectHdl;
+ aTitleText = rMenu.aTitleText;
+ bIsMenuBar = rMenu.bIsMenuBar;
+
+ return *this;
+}
+
+BOOL Menu::ImplIsVisible( USHORT nPos ) const
+{
+ BOOL bVisible = TRUE;
+
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+ // check general visibility first
+ if( pData && !pData->bVisible )
+ bVisible = FALSE;
+
+ if ( bVisible && pData && pData->eType == MENUITEM_SEPARATOR )
+ {
+ if( nPos == 0 ) // no separator should be shown at the very beginning
+ bVisible = FALSE;
+ else
+ {
+ // always avoid adjacent separators
+ USHORT nCount = (USHORT) pItemList->Count();
+ USHORT n;
+ MenuItemData* pNextData = NULL;
+ // search next visible item
+ for( n = nPos + 1; n < nCount; n++ )
+ {
+ pNextData = pItemList->GetDataFromPos( n );
+ if( pNextData && pNextData->bVisible )
+ {
+ if( pNextData->eType == MENUITEM_SEPARATOR || ImplIsVisible(n) )
+ break;
+ }
+ }
+ if( n == nCount ) // no next visible item
+ bVisible = FALSE;
+ // check for separator
+ if( pNextData && pNextData->bVisible && pNextData->eType == MENUITEM_SEPARATOR )
+ bVisible = FALSE;
+
+ if( bVisible )
+ {
+ for( n = nPos; n > 0; n-- )
+ {
+ pNextData = pItemList->GetDataFromPos( n-1 );
+ if( pNextData && pNextData->bVisible )
+ {
+ if( pNextData->eType != MENUITEM_SEPARATOR && ImplIsVisible(n-1) )
+ break;
+ }
+ }
+ if( n == 0 ) // no previous visible item
+ bVisible = FALSE;
+ }
+ }
+ }
+
+ // Fuer den Menubar nicht erlaubt, weil ich nicht mitbekomme
+ // ob dadurch ein Eintrag verschwindet oder wieder da ist.
+ if ( bVisible && !bIsMenuBar && ( nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES ) &&
+ !( nMenuFlags & MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES ) )
+ {
+ if( !pData ) // e.g. nPos == ITEMPOS_INVALID
+ bVisible = FALSE;
+ else if ( pData->eType != MENUITEM_SEPARATOR ) // separators handled above
+ {
+ // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( TRUE ) );
+ bVisible = pData->bEnabled; // SubMenus nicht pruefen, weil sie ggf. erst im Activate() gefuellt werden.
+ }
+ }
+
+ return bVisible;
+}
+
+BOOL Menu::IsItemVisible( USHORT nItemId ) const
+{
+ return IsMenuVisible() && ImplIsVisible( GetItemPos( nItemId ) );
+}
+
+BOOL Menu::IsItemPosVisible( USHORT nItemPos ) const
+{
+ return IsMenuVisible() && ImplIsVisible( nItemPos );
+}
+
+BOOL Menu::IsMenuVisible() const
+{
+ return pWindow && pWindow->IsReallyVisible();
+}
+
+BOOL Menu::ImplIsSelectable( USHORT nPos ) const
+{
+ BOOL bSelectable = TRUE;
+
+ MenuItemData* pData = pItemList->GetDataFromPos( nPos );
+ // check general visibility first
+ if ( pData && ( pData->nBits & MIB_NOSELECT ) )
+ bSelectable = FALSE;
+
+ return bSelectable;
+}
+
+void Menu::SelectItem( USHORT nItemId )
+{
+ if( bIsMenuBar )
+ static_cast<MenuBar*>(this)->SelectEntry( nItemId );
+ else
+ static_cast<PopupMenu*>(this)->SelectEntry( nItemId );
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Menu::GetAccessible()
+{
+ // Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets
+ // overwritten and may contain a disposed object when the initial menubar gets set again. So use the
+ // mxAccessible member only for sub menus.
+ if ( pStartedFrom )
+ {
+ for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i )
+ {
+ sal_uInt16 nItemId = pStartedFrom->GetItemId( i );
+ if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xParent = pStartedFrom->GetAccessible();
+ if ( xParent.is() )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if ( xParentContext.is() )
+ return xParentContext->getAccessibleChild( i );
+ }
+ }
+ }
+ }
+ else if ( !mxAccessible.is() )
+ {
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
+ if ( pWrapper )
+ mxAccessible = pWrapper->CreateAccessible( this, bIsMenuBar );
+ }
+
+ return mxAccessible;
+}
+
+void Menu::SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible )
+{
+ mxAccessible = rxAccessible;
+}
+
+long Menu::ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) const
+{
+ rMaxWidth = rCheckHeight = rRadioHeight = 0;
+
+ if( ! bIsMenuBar )
+ {
+ ImplControlValue aVal;
+ Rectangle aNativeBounds;
+ Rectangle aNativeContent;
+ Point tmp( 0, 0 );
+ Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) );
+ if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) )
+ {
+ if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
+ ControlPart(PART_MENU_ITEM_CHECK_MARK),
+ aCtrlRegion,
+ ControlState(CTRL_STATE_ENABLED),
+ aVal,
+ OUString(),
+ aNativeBounds,
+ aNativeContent )
+ )
+ {
+ rCheckHeight = aNativeBounds.GetHeight();
+ rMaxWidth = aNativeContent.GetWidth();
+ }
+ }
+ if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) )
+ {
+ if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP),
+ ControlPart(PART_MENU_ITEM_RADIO_MARK),
+ aCtrlRegion,
+ ControlState(CTRL_STATE_ENABLED),
+ aVal,
+ OUString(),
+ aNativeBounds,
+ aNativeContent )
+ )
+ {
+ rRadioHeight = aNativeBounds.GetHeight();
+ rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth());
+ }
+ }
+ }
+ return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void Menu::ImplAddDel( ImplMenuDelData& rDel )
+{
+ DBG_ASSERT( !rDel.mpMenu, "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !" );
+ if( !rDel.mpMenu )
+ {
+ rDel.mpMenu = this;
+ rDel.mpNext = mpFirstDel;
+ mpFirstDel = &rDel;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Menu::ImplRemoveDel( ImplMenuDelData& rDel )
+{
+ rDel.mpMenu = NULL;
+ if ( mpFirstDel == &rDel )
+ {
+ mpFirstDel = rDel.mpNext;
+ }
+ else
+ {
+ ImplMenuDelData* pData = mpFirstDel;
+ while ( pData && (pData->mpNext != &rDel) )
+ pData = pData->mpNext;
+
+ DBG_ASSERT( pData, "Menu::ImplRemoveDel(): ImplMenuDelData not registered !" );
+ if( pData )
+ pData->mpNext = rDel.mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size Menu::ImplCalcSize( Window* pWin )
+{
+ // | Checked| Image| Text| Accel/Popup|
+
+ // Fuer Symbole: nFontHeight x nFontHeight
+ long nFontHeight = pWin->GetTextHeight();
+ long nExtra = nFontHeight/4;
+
+
+ Size aSz;
+ Size aMaxImgSz;
+ long nMaxWidth = 0;
+ long nMinMenuItemHeight = nFontHeight;
+ long nCheckHeight = 0, nRadioHeight = 0;
+ long nCheckWidth = 0, nMaxCheckWidth = 0;
+ long nMax = ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
+ if( nMax > nMinMenuItemHeight )
+ nMinMenuItemHeight = nMax;
+
+ // When no native rendering of the checkbox & no image in the menu, we
+ // have to add some extra space even in the MENU_FLAG_SHOWCHECKIMAGES case
+ bool bSpaceForCheckbox = ( nMax == 0 );
+
+ const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
+ if ( rSettings.GetUseImagesInMenus() )
+ {
+ nMinMenuItemHeight = 16;
+ for ( USHORT i = (USHORT)pItemList->Count(); i; )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( --i );
+ if ( ImplIsVisible( i ) && (( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE )))
+ {
+ // we have an icon, don't add the extra space
+ bSpaceForCheckbox = false;
+
+ Size aImgSz = pData->aImage.GetSizePixel();
+ if ( aImgSz.Height() > aMaxImgSz.Height() )
+ aMaxImgSz.Height() = aImgSz.Height();
+ if ( aImgSz.Height() > nMinMenuItemHeight )
+ nMinMenuItemHeight = aImgSz.Height();
+ break;
+ }
+ }
+ }
+
+ for ( USHORT n = (USHORT)pItemList->Count(); n; )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( --n );
+
+ pData->aSz.Height() = 0;
+ pData->aSz.Width() = 0;
+
+ if ( ImplIsVisible( n ) )
+ {
+ long nWidth = 0;
+
+ // Separator
+ if ( !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
+ {
+ DBG_ASSERT( !bIsMenuBar, "Separator in MenuBar ?! " );
+ pData->aSz.Height() = 4;
+ }
+
+ // Image:
+ if ( !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ {
+ Size aImgSz = pData->aImage.GetSizePixel();
+ aImgSz.Height() += 4; // add a border for native marks
+ aImgSz.Width() += 4; // add a border for native marks
+ if ( aImgSz.Width() > aMaxImgSz.Width() )
+ aMaxImgSz.Width() = aImgSz.Width();
+ if ( aImgSz.Height() > aMaxImgSz.Height() )
+ aMaxImgSz.Height() = aImgSz.Height();
+ if ( aImgSz.Height() > pData->aSz.Height() )
+ pData->aSz.Height() = aImgSz.Height();
+ }
+
+ // Check Buttons:
+ if ( !bIsMenuBar && pData->HasCheck() )
+ {
+ nCheckWidth = nMaxCheckWidth;
+ if ( ( nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES ) || bSpaceForCheckbox )
+ {
+ // checks / images take the same place
+ if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ nWidth += nCheckWidth + nExtra * 2;
+ }
+ }
+
+ // Text:
+ if ( (pData->eType == MENUITEM_STRING) || (pData->eType == MENUITEM_STRINGIMAGE) )
+ {
+ long nTextWidth = pWin->GetCtrlTextWidth( pData->aText );
+ long nTextHeight = pWin->GetTextHeight();
+
+// if ( nTextHeight > pData->aSz.Height() )
+// pData->aSz.Height() = nTextHeight;
+
+ if ( bIsMenuBar )
+ {
+ if ( nTextHeight > pData->aSz.Height() )
+ pData->aSz.Height() = nTextHeight;
+
+ pData->aSz.Width() = nTextWidth + 4*nExtra;
+ aSz.Width() += pData->aSz.Width();
+ }
+ else
+ pData->aSz.Height() = Max( Max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight );
+
+ nWidth += nTextWidth;
+ }
+
+ // Accel
+ if ( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
+ {
+ String aName = pData->aAccelKey.GetName();
+ long nAccWidth = pWin->GetTextWidth( aName );
+ nAccWidth += nExtra;
+ nWidth += nAccWidth;
+ }
+
+ // SubMenu?
+ if ( !bIsMenuBar && pData->pSubMenu )
+ {
+ if ( nFontHeight > nWidth )
+ nWidth += nFontHeight;
+
+ pData->aSz.Height() = Max( Max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight );
+ }
+
+ pData->aSz.Height() += EXTRAITEMHEIGHT; // Etwas mehr Abstand:
+
+ if ( !bIsMenuBar )
+ aSz.Height() += (long)pData->aSz.Height();
+
+ if ( nWidth > nMaxWidth )
+ nMaxWidth = nWidth;
+
+ }
+ }
+
+ if ( !bIsMenuBar )
+ {
+ USHORT gfxExtra = (USHORT) Max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text
+ nCheckPos = (USHORT)nExtra;
+ if ( ( nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES ) || bSpaceForCheckbox )
+ {
+ long nImgOrChkWidth = 0;
+ nImagePos = nCheckPos;
+ if( nMax > 0 ) // NWF case
+ nImgOrChkWidth = nMax + nExtra;
+ else // non NWF case
+ nImgOrChkWidth = nFontHeight/2 + gfxExtra;
+ nImgOrChkWidth = Max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra );
+ nTextPos = (USHORT)(nImagePos + nImgOrChkWidth);
+ }
+ else
+ {
+ nImagePos = nCheckPos;
+ nTextPos = (USHORT)(nImagePos + Max( aMaxImgSz.Width(), nCheckWidth ));
+ }
+ nTextPos = nTextPos + gfxExtra;
+
+ aSz.Width() = nTextPos + nMaxWidth + nExtra;
+ aSz.Width() += 4*nExtra; // a _little_ more ...
+
+ int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
+ aSz.Width() += 2*nOuterSpace;
+ aSz.Height() += 2*nOuterSpace;
+ }
+ else
+ {
+ nTextPos = (USHORT)(2*nExtra);
+ aSz.Height() = nFontHeight+6;
+
+ // get menubar height from native methods if supported
+ if( pWindow->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aVal;
+ Rectangle aNativeBounds;
+ Rectangle aNativeContent;
+ Point tmp( 0, 0 );
+ Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
+ if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR),
+ ControlPart(PART_ENTIRE_CONTROL),
+ aCtrlRegion,
+ ControlState(CTRL_STATE_ENABLED),
+ aVal,
+ OUString(),
+ aNativeBounds,
+ aNativeContent )
+ )
+ {
+ int nNativeHeight = aNativeBounds.GetHeight();
+ if( nNativeHeight > aSz.Height() )
+ aSz.Height() = nNativeHeight;
+ }
+ }
+
+ // account for the size of the close button, which actually is a toolbox
+ // due to NWF this is variable
+ long nCloserHeight = ((MenuBarWindow*) pWindow)->MinCloseButtonSize().Height();
+ if( aSz.Height() < nCloserHeight )
+ aSz.Height() = nCloserHeight;
+ }
+
+ if ( pLogo )
+ aSz.Width() += pLogo->aBitmap.GetSizePixel().Width();
+
+ return aSz;
+}
+
+static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight )
+{
+ BOOL bNativeOk = FALSE;
+ if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
+ {
+ ImplControlValue aControlValue;
+ Rectangle aCtrlRegion( i_rRect );
+ ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
+
+ aControlValue.setTristateVal( BUTTONVALUE_ON );
+
+ bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
+ aCtrlRegion, nState, aControlValue,
+ rtl::OUString() );
+ }
+
+ if( ! bNativeOk )
+ {
+ const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings();
+ Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
+ i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, TRUE, FALSE, 2, NULL, &aColor );
+ }
+}
+
+void Menu::ImplPaint( Window* pWin, USHORT nBorder, long nStartY, MenuItemData* pThisItemOnly, BOOL bHighlighted, bool bLayout ) const
+{
+ // Fuer Symbole: nFontHeight x nFontHeight
+ long nFontHeight = pWin->GetTextHeight();
+ long nExtra = nFontHeight/4;
+
+ long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0;
+ ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth );
+
+ DecorationView aDecoView( pWin );
+ const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
+
+ Point aTopLeft, aTmpPos;
+
+ if ( pLogo )
+ aTopLeft.X() = pLogo->aBitmap.GetSizePixel().Width();
+
+ int nOuterSpace = 0;
+ if( !bIsMenuBar )
+ {
+ nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
+ aTopLeft.X() += nOuterSpace;
+ aTopLeft.Y() += nOuterSpace;
+ }
+
+ Size aOutSz = pWin->GetOutputSizePixel();
+ USHORT nCount = (USHORT)pItemList->Count();
+ if( bLayout )
+ mpLayoutData->m_aVisibleItemBoundRects.clear();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ if ( ImplIsVisible( n ) && ( !pThisItemOnly || ( pData == pThisItemOnly ) ) )
+ {
+ if ( pThisItemOnly && bHighlighted )
+ pWin->SetTextColor( rSettings.GetMenuHighlightTextColor() );
+
+ Point aPos( aTopLeft );
+ aPos.Y() += nBorder;
+ aPos.Y() += nStartY;
+
+ if ( aPos.Y() >= 0 )
+ {
+ long nTextOffsetY = ((pData->aSz.Height()-nFontHeight)/2);
+ if( bIsMenuBar )
+ nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2;
+ USHORT nTextStyle = 0;
+ USHORT nSymbolStyle = 0;
+ USHORT nImageStyle = 0;
+ // SubMenus ohne Items werden nicht mehr disablte dargestellt,
+ // wenn keine Items enthalten sind, da die Anwendung selber
+ // darauf achten muss. Ansonsten gibt es Faelle, wo beim
+ // asyncronen laden die Eintraege disablte dargestellt werden.
+ if ( !pData->bEnabled )
+ {
+ nTextStyle |= TEXT_DRAW_DISABLE;
+ nSymbolStyle |= SYMBOL_DRAW_DISABLE;
+ nImageStyle |= IMAGE_DRAW_DISABLE;
+ }
+
+ // Separator
+ if ( !bLayout && !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) )
+ {
+ aTmpPos.Y() = aPos.Y() + ((pData->aSz.Height()-2)/2);
+ aTmpPos.X() = aPos.X() + 2 + nOuterSpace;
+ pWin->SetLineColor( rSettings.GetShadowColor() );
+ pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
+ aTmpPos.Y()++;
+ pWin->SetLineColor( rSettings.GetLightColor() );
+ pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) );
+ pWin->SetLineColor();
+ }
+
+ Rectangle aOuterCheckRect( Point( aPos.X()+nCheckPos, aPos.Y() ), Size( pData->aSz.Height(), pData->aSz.Height() ) );
+ aOuterCheckRect.Left() += 1;
+ aOuterCheckRect.Right() -= 1;
+ aOuterCheckRect.Top() += 1;
+ aOuterCheckRect.Bottom() -= 1;
+
+ // CheckMark
+ if ( !bLayout && !bIsMenuBar && pData->HasCheck() )
+ {
+ // draw selection transparent marker if checked
+ // onto that either a checkmark or the item image
+ // will be painted
+ // however do not do this if native checks will be painted since
+ // the selection color too often does not fit the theme's check and/or radio
+
+ if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ {
+ if ( pWin->IsNativeControlSupported( CTRL_MENU_POPUP,
+ (pData->nBits & MIB_RADIOCHECK)
+ ? PART_MENU_ITEM_CHECK_MARK
+ : PART_MENU_ITEM_RADIO_MARK ) )
+ {
+ ControlPart nPart = ((pData->nBits & MIB_RADIOCHECK)
+ ? PART_MENU_ITEM_RADIO_MARK
+ : PART_MENU_ITEM_CHECK_MARK);
+
+ ControlState nState = 0;
+
+ if ( pData->bChecked )
+ nState |= CTRL_STATE_PRESSED;
+
+ if ( pData->bEnabled )
+ nState |= CTRL_STATE_ENABLED;
+
+ if ( bHighlighted )
+ nState |= CTRL_STATE_SELECTED;
+
+ long nCtrlHeight = (pData->nBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight;
+ aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2;
+ aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2;
+
+ Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) );
+ pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart,
+ aCheckRect,
+ nState,
+ ImplControlValue(),
+ OUString() );
+ }
+ else if ( pData->bChecked ) // by default do nothing for unchecked items
+ {
+ ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
+
+ SymbolType eSymbol;
+ Size aSymbolSize;
+ if ( pData->nBits & MIB_RADIOCHECK )
+ {
+ eSymbol = SYMBOL_RADIOCHECKMARK;
+ aSymbolSize = Size( nFontHeight/2, nFontHeight/2 );
+ }
+ else
+ {
+ eSymbol = SYMBOL_CHECKMARK;
+ aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 );
+ }
+ aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2;
+ aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2;
+ Rectangle aRect( aTmpPos, aSymbolSize );
+ aDecoView.DrawSymbol( aRect, eSymbol, pWin->GetTextColor(), nSymbolStyle );
+ }
+ }
+ }
+
+ // Image:
+ if ( !bLayout && !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) )
+ {
+ // Don't render an image for a check thing
+ if ((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pData->HasCheck() )
+ {
+ if( pData->bChecked )
+ ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted );
+ aTmpPos = aOuterCheckRect.TopLeft();
+ aTmpPos.X() += (aOuterCheckRect.GetWidth()-pData->aImage.GetSizePixel().Width())/2;
+ aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pData->aImage.GetSizePixel().Height())/2;
+ pWin->DrawImage( aTmpPos, pData->aImage, nImageStyle );
+ }
+ }
+
+ // Text:
+ if ( ( pData->eType == MENUITEM_STRING ) || ( pData->eType == MENUITEM_STRINGIMAGE ) )
+ {
+ aTmpPos.X() = aPos.X() + nTextPos;
+ aTmpPos.Y() = aPos.Y();
+ aTmpPos.Y() += nTextOffsetY;
+ USHORT nStyle = nTextStyle|TEXT_DRAW_MNEMONIC;
+ if ( pData->bIsTemporary )
+ nStyle |= TEXT_DRAW_DISABLE;
+ MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL;
+ if( bLayout )
+ {
+ mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.Len() );
+ mpLayoutData->m_aLineItemIds.push_back( pData->nId );
+ mpLayoutData->m_aLineItemPositions.push_back( n );
+ }
+ // #i47946# with NWF painted menus the background is transparent
+ // since DrawCtrlText can depend on the background (e.g. for
+ // TEXT_DRAW_DISABLE), temporarily set a background which
+ // hopefully matches the NWF background since it is read
+ // from the system style settings
+ bool bSetTmpBackground = !pWin->IsBackground() && pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL );
+ if( bSetTmpBackground )
+ {
+ Color aBg = bIsMenuBar ?
+ pWin->GetSettings().GetStyleSettings().GetMenuBarColor() :
+ pWin->GetSettings().GetStyleSettings().GetMenuColor();
+ pWin->SetBackground( Wallpaper( aBg ) );
+ }
+ pWin->DrawCtrlText( aTmpPos, pData->aText, 0, pData->aText.Len(), nStyle, pVector, pDisplayText );
+ if( bSetTmpBackground )
+ pWin->SetBackground();
+ }
+
+ // Accel
+ if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() )
+ {
+ XubString aAccText = pData->aAccelKey.GetName();
+ aTmpPos.X() = aOutSz.Width() - pWin->GetTextWidth( aAccText );
+ aTmpPos.X() -= 4*nExtra;
+
+ aTmpPos.X() -= nOuterSpace;
+ aTmpPos.Y() = aPos.Y();
+ aTmpPos.Y() += nTextOffsetY;
+ pWin->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle );
+ }
+
+ // SubMenu?
+ if ( !bLayout && !bIsMenuBar && pData->pSubMenu )
+ {
+ aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace;
+ aTmpPos.Y() = aPos.Y();
+ aTmpPos.Y() += nExtra/2;
+ aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 );
+ if ( pData->nBits & MIB_POPUPSELECT )
+ {
+ pWin->SetTextColor( rSettings.GetMenuTextColor() );
+ Point aTmpPos2( aPos );
+ aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4;
+ aDecoView.DrawFrame(
+ Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP );
+ }
+ aDecoView.DrawSymbol(
+ Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ),
+ SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle );
+// if ( pData->nBits & MIB_POPUPSELECT )
+// {
+// aTmpPos.Y() += nFontHeight/2 ;
+// pWin->SetLineColor( rSettings.GetShadowColor() );
+// pWin->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
+// pWin->SetLineColor( rSettings.GetLightColor() );
+// aTmpPos.Y()++;
+// pWin->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) );
+// pWin->SetLineColor();
+// }
+ }
+
+ if ( pThisItemOnly && bHighlighted )
+ {
+ // This restores the normal menu or menu bar text
+ // color for when it is no longer highlighted.
+ if ( bIsMenuBar )
+ pWin->SetTextColor( rSettings.GetMenuBarTextColor() );
+ else
+ pWin->SetTextColor( rSettings.GetMenuTextColor() );
+ }
+ }
+ if( bLayout )
+ {
+ if ( !bIsMenuBar )
+ mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, Size( aOutSz.Width(), pData->aSz.Height() ) );
+ else
+ mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, pData->aSz );
+ }
+ }
+
+ if ( !bIsMenuBar )
+ {
+ aTopLeft.Y() += pData->aSz.Height();
+ }
+ else
+ {
+ aTopLeft.X() += pData->aSz.Width();
+ }
+ }
+
+ if ( !bLayout && !pThisItemOnly && pLogo )
+ {
+ Size aLogoSz = pLogo->aBitmap.GetSizePixel();
+
+ Rectangle aRect( Point( 0, 0 ), Point( aLogoSz.Width()-1, aOutSz.Height() ) );
+ if ( pWin->GetColorCount() >= 256 )
+ {
+ Gradient aGrad( GRADIENT_LINEAR, pLogo->aStartColor, pLogo->aEndColor );
+ aGrad.SetAngle( 1800 );
+ aGrad.SetBorder( 15 );
+ pWin->DrawGradient( aRect, aGrad );
+ }
+ else
+ {
+ pWin->SetFillColor( pLogo->aStartColor );
+ pWin->DrawRect( aRect );
+ }
+
+ Point aLogoPos( 0, aOutSz.Height() - aLogoSz.Height() );
+ pLogo->aBitmap.Draw( pWin, aLogoPos );
+ }
+}
+
+Menu* Menu::ImplGetStartMenu()
+{
+ Menu* pStart = this;
+ while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) )
+ pStart = pStart->pStartedFrom;
+ return pStart;
+}
+
+void Menu::ImplCallHighlight( USHORT nHighlightedItem )
+{
+ ImplMenuDelData aDelData( this );
+
+ nSelectedId = 0;
+ MenuItemData* pData = pItemList->GetDataFromPos( nHighlightedItem );
+ if ( pData )
+ nSelectedId = pData->nId;
+ ImplCallEventListeners( VCLEVENT_MENU_HIGHLIGHT, GetItemPos( GetCurItemId() ) );
+
+ if( !aDelData.isDeleted() )
+ {
+ Highlight();
+ nSelectedId = 0;
+ }
+}
+
+IMPL_LINK( Menu, ImplCallSelect, Menu*, EMPTYARG )
+{
+ nEventId = 0;
+ Select();
+ return 0;
+}
+
+Menu* Menu::ImplFindSelectMenu()
+{
+ Menu* pSelMenu = nEventId ? this : NULL;
+
+ for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; )
+ {
+ MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
+
+ if ( pData->pSubMenu )
+ pSelMenu = pData->pSubMenu->ImplFindSelectMenu();
+ }
+
+ return pSelMenu;
+}
+
+Menu* Menu::ImplFindMenu( USHORT nItemId )
+{
+ Menu* pSelMenu = NULL;
+
+ for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; )
+ {
+ MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
+
+ if( pData->nId == nItemId )
+ pSelMenu = this;
+ else if ( pData->pSubMenu )
+ pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId );
+ }
+
+ return pSelMenu;
+}
+
+void Menu::RemoveDisabledEntries( BOOL bCheckPopups, BOOL bRemoveEmptyPopups )
+{
+ for ( USHORT n = 0; n < GetItemCount(); n++ )
+ {
+ BOOL bRemove = FALSE;
+ MenuItemData* pItem = pItemList->GetDataFromPos( n );
+ if ( pItem->eType == MENUITEM_SEPARATOR )
+ {
+ if ( !n || ( GetItemType( n-1 ) == MENUITEM_SEPARATOR ) )
+ bRemove = TRUE;
+ }
+ else
+ bRemove = !pItem->bEnabled;
+
+ if ( bCheckPopups && pItem->pSubMenu )
+ {
+ pItem->pSubMenu->RemoveDisabledEntries( TRUE );
+ if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() )
+ bRemove = TRUE;
+ }
+
+ if ( bRemove )
+ RemoveItem( n-- );
+ }
+
+ if ( GetItemCount() )
+ {
+ USHORT nLast = GetItemCount() - 1;
+ MenuItemData* pItem = pItemList->GetDataFromPos( nLast );
+ if ( pItem->eType == MENUITEM_SEPARATOR )
+ RemoveItem( nLast );
+ }
+ delete mpLayoutData, mpLayoutData = NULL;
+}
+
+BOOL Menu::HasValidEntries( BOOL bCheckPopups )
+{
+ BOOL bValidEntries = FALSE;
+ USHORT nCount = GetItemCount();
+ for ( USHORT n = 0; !bValidEntries && ( n < nCount ); n++ )
+ {
+ MenuItemData* pItem = pItemList->GetDataFromPos( n );
+ if ( pItem->bEnabled && ( pItem->eType != MENUITEM_SEPARATOR ) )
+ {
+ if ( bCheckPopups && pItem->pSubMenu )
+ bValidEntries = pItem->pSubMenu->HasValidEntries( TRUE );
+ else
+ bValidEntries = TRUE;
+ }
+ }
+ return bValidEntries;
+}
+
+void Menu::SetLogo( const MenuLogo& rLogo )
+{
+ delete pLogo;
+ pLogo = new MenuLogo( rLogo );
+}
+
+void Menu::SetLogo()
+{
+ delete pLogo;
+ pLogo = NULL;
+}
+
+MenuLogo Menu::GetLogo() const
+{
+ MenuLogo aLogo;
+ if ( pLogo )
+ aLogo = *pLogo;
+ return aLogo;
+}
+
+void Menu::ImplKillLayoutData() const
+{
+ delete mpLayoutData, mpLayoutData = NULL;
+}
+
+void Menu::ImplFillLayoutData() const
+{
+ if( pWindow && pWindow->IsReallyVisible() )
+ {
+ mpLayoutData = new MenuLayoutData();
+ if( bIsMenuBar )
+ {
+ ImplPaint( pWindow, 0, 0, 0, FALSE, true );
+ }
+ else
+ {
+ MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow;
+ ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, FALSE, true );
+ }
+ }
+}
+
+String Menu::GetDisplayText() const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ return mpLayoutData ? mpLayoutData->m_aDisplayText : String();
+}
+
+Rectangle Menu::GetCharacterBounds( USHORT nItemID, long nIndex ) const
+{
+ long nItemIndex = -1;
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData )
+ {
+ for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
+ {
+ if( mpLayoutData->m_aLineItemIds[i] == nItemID )
+ {
+ nItemIndex = mpLayoutData->m_aLineIndices[i];
+ break;
+ }
+ }
+ }
+ return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle();
+}
+
+
+long Menu::GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const
+{
+ long nIndex = -1;
+ rItemID = 0;
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData )
+ {
+ nIndex = mpLayoutData->GetIndexForPoint( rPoint );
+ for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ )
+ {
+ if( mpLayoutData->m_aLineIndices[i] <= nIndex &&
+ (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) )
+ {
+ // make index relative to item
+ nIndex -= mpLayoutData->m_aLineIndices[i];
+ rItemID = mpLayoutData->m_aLineItemIds[i];
+ break;
+ }
+ }
+ }
+ return nIndex;
+}
+
+long Menu::GetLineCount() const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ return mpLayoutData ? mpLayoutData->GetLineCount() : 0;
+}
+
+Pair Menu::GetLineStartEnd( long nLine ) const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ return mpLayoutData ? mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
+}
+
+Pair Menu::GetItemStartEnd( USHORT nItem ) const
+{
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+
+ for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
+ if( mpLayoutData->m_aLineItemIds[i] == nItem )
+ return GetLineStartEnd( i );
+
+ return Pair( -1, -1 );
+}
+
+USHORT Menu::GetDisplayItemId( long nLine ) const
+{
+ USHORT nItemId = 0;
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData && ( nLine >= 0 ) && ( nLine < (long)mpLayoutData->m_aLineItemIds.size() ) )
+ nItemId = mpLayoutData->m_aLineItemIds[nLine];
+ return nItemId;
+}
+
+BOOL Menu::ConvertPoint( Point& rPoint, Window* pReferenceWindow ) const
+{
+ BOOL bRet = FALSE;
+ if( pWindow && pReferenceWindow )
+ {
+ rPoint = pReferenceWindow->OutputToAbsoluteScreenPixel( rPoint );
+ rPoint = pWindow->AbsoluteScreenToOutputPixel( rPoint );
+ bRet = TRUE;
+ }
+ return bRet;
+}
+
+Rectangle Menu::GetBoundingRectangle( USHORT nPos ) const
+{
+ Rectangle aRet;
+
+ if( ! mpLayoutData )
+ ImplFillLayoutData();
+ if( mpLayoutData )
+ {
+ std::map< USHORT, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos );
+ if( it != mpLayoutData->m_aVisibleItemBoundRects.end() )
+ aRet = it->second;
+ }
+ return aRet;
+}
+
+void Menu::SetAccessibleName( USHORT nItemId, const XubString& rStr )
+{
+ USHORT nPos;
+ MenuItemData* pData = pItemList->GetData( nItemId, nPos );
+
+ if ( pData && !rStr.Equals( pData->aAccessibleName ) )
+ {
+ pData->aAccessibleName = rStr;
+ ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos );
+ }
+}
+
+XubString Menu::GetAccessibleName( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aAccessibleName;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::SetAccessibleDescription( USHORT nItemId, const XubString& rStr )
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ pData->aAccessibleDescription = rStr;
+}
+
+XubString Menu::GetAccessibleDescription( USHORT nItemId ) const
+{
+ MenuItemData* pData = pItemList->GetData( nItemId );
+
+ if ( pData )
+ return pData->aAccessibleDescription;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+void Menu::ImplSetSalMenu( SalMenu *pSalMenu )
+{
+ if( mpSalMenu )
+ ImplGetSVData()->mpDefInst->DestroyMenu( mpSalMenu );
+ mpSalMenu = pSalMenu;
+}
+
+BOOL Menu::GetSystemMenuData( SystemMenuData* pData ) const
+{
+ Menu* pMenu = (Menu*)this;
+ if( pData && pMenu->ImplGetSalMenu() )
+ {
+ pMenu->ImplGetSalMenu()->GetSystemMenuData( pData );
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+bool Menu::IsHighlighted( USHORT nItemPos ) const
+{
+ bool bRet = false;
+
+ if( pWindow )
+ {
+ if( bIsMenuBar )
+ bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow)->GetHighlightedItem() );
+ else
+ bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow)->GetHighlightedItem() );
+ }
+
+ return bRet;
+}
+
+void Menu::HighlightItem( USHORT nItemPos )
+{
+ if ( pWindow )
+ {
+ if ( bIsMenuBar )
+ {
+ MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow );
+ pMenuWin->SetAutoPopup( FALSE );
+ pMenuWin->ChangeHighlightItem( nItemPos, FALSE );
+ }
+ else
+ {
+ static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, FALSE );
+ }
+ }
+}
+
+// -----------
+// - MenuBar -
+// -----------
+
+MenuBar::MenuBar() : Menu( TRUE )
+{
+ mbDisplayable = TRUE;
+ mbCloserVisible = FALSE;
+ mbFloatBtnVisible = FALSE;
+ mbHideBtnVisible = FALSE;
+}
+
+MenuBar::MenuBar( const MenuBar& rMenu ) : Menu( TRUE )
+{
+ mbDisplayable = TRUE;
+ mbCloserVisible = FALSE;
+ mbFloatBtnVisible = FALSE;
+ mbHideBtnVisible = FALSE;
+ *this = rMenu;
+ bIsMenuBar = TRUE;
+}
+
+MenuBar::MenuBar( const ResId& rResId ) : Menu ( TRUE )
+{
+ mbDisplayable = TRUE;
+ mbCloserVisible = FALSE;
+ mbFloatBtnVisible = FALSE;
+ mbHideBtnVisible = FALSE;
+ ImplLoadRes( rResId );
+}
+
+MenuBar::~MenuBar()
+{
+ ImplDestroy( this, TRUE );
+}
+
+void MenuBar::ShowCloser( BOOL bShow )
+{
+ ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible );
+}
+
+void MenuBar::ShowFloatButton( BOOL bShow )
+{
+ ShowButtons( mbCloserVisible, bShow, mbHideBtnVisible );
+}
+
+void MenuBar::ShowHideButton( BOOL bShow )
+{
+ ShowButtons( mbCloserVisible, mbFloatBtnVisible, bShow );
+}
+
+void MenuBar::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide )
+{
+ if ( (bClose != mbCloserVisible) ||
+ (bFloat != mbFloatBtnVisible) ||
+ (bHide != mbHideBtnVisible) )
+ {
+ mbCloserVisible = bClose;
+ mbFloatBtnVisible = bFloat;
+ mbHideBtnVisible = bHide;
+ if ( ImplGetWindow() )
+ ((MenuBarWindow*)ImplGetWindow())->ShowButtons( bClose, bFloat, bHide );
+ }
+}
+
+void MenuBar::SetDisplayable( BOOL bDisplayable )
+{
+ if( bDisplayable != mbDisplayable )
+ {
+ mbDisplayable = bDisplayable;
+ MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
+ if( pMenuWin )
+ pMenuWin->ImplLayoutChanged();
+ }
+}
+
+Window* MenuBar::ImplCreate( Window* pParent, Window* pWindow, MenuBar* pMenu )
+{
+ if ( !pWindow )
+ pWindow = new MenuBarWindow( pParent );
+
+ pMenu->pStartedFrom = 0;
+ pMenu->pWindow = pWindow;
+ ((MenuBarWindow*)pWindow)->SetMenu( pMenu );
+ long nHeight = pMenu->ImplCalcSize( pWindow ).Height();
+
+ // depending on the native implementation or the displayable flag
+ // the menubar windows is supressed (ie, height=0)
+ if( !((MenuBar*) pMenu)->IsDisplayable() ||
+ ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
+ nHeight = 0;
+
+ pWindow->SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
+ return pWindow;
+}
+
+void MenuBar::ImplDestroy( MenuBar* pMenu, BOOL bDelete )
+{
+ MenuBarWindow* pWindow = (MenuBarWindow*) pMenu->ImplGetWindow();
+ if ( pWindow && bDelete )
+ {
+ pWindow->KillActivePopup();
+ delete pWindow;
+ }
+ pMenu->pWindow = NULL;
+}
+
+BOOL MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu )
+{
+ BOOL bDone = FALSE;
+
+ // No keyboard processing when system handles the menu or our menubar is invisible
+ if( !IsDisplayable() ||
+ ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
+ return bDone;
+
+ // Enabled-Abfragen, falls diese Methode von einem anderen Fenster gerufen wurde...
+ Window* pWin = ImplGetWindow();
+ if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && ! pWin->IsInModalMode() )
+ bDone = ((MenuBarWindow*)pWin)->ImplHandleKeyEvent( rKEvent, bFromMenu );
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+void MenuBar::SelectEntry( USHORT nId )
+{
+ MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow();
+
+ if( pMenuWin )
+ {
+ pMenuWin->GrabFocus();
+ nId = GetItemPos( nId );
+
+ // #99705# popup the selected menu
+ pMenuWin->SetAutoPopup( TRUE );
+ if( ITEMPOS_INVALID != pMenuWin->nHighlightedItem )
+ {
+ pMenuWin->KillActivePopup();
+ pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ }
+ if( nId != ITEMPOS_INVALID )
+ pMenuWin->ChangeHighlightItem( nId, FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// handler for native menu selection and command events
+
+BOOL MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const
+{
+ if( pMenu )
+ {
+ ImplMenuDelData aDelData( this );
+
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->bInCallback = TRUE;
+ pMenu->Activate();
+
+ if( !aDelData.isDeleted() )
+ pMenu->bInCallback = FALSE;
+ }
+ return TRUE;
+}
+
+BOOL MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const
+{
+ if( pMenu )
+ {
+ ImplMenuDelData aDelData( this );
+
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->bInCallback = TRUE;
+ pMenu->Deactivate();
+ if( !aDelData.isDeleted() )
+ pMenu->bInCallback = FALSE;
+ }
+ return TRUE;
+}
+
+BOOL MenuBar::HandleMenuHighlightEvent( Menu *pMenu, USHORT nHighlightEventId ) const
+{
+ if( !pMenu )
+ pMenu = ((Menu*) this)->ImplFindMenu( nHighlightEventId );
+ if( pMenu )
+ {
+ ImplMenuDelData aDelData( pMenu );
+
+ if( mnHighlightedItemPos != ITEMPOS_INVALID )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, mnHighlightedItemPos );
+
+ if( !aDelData.isDeleted() )
+ {
+ pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId );
+ pMenu->nSelectedId = nHighlightEventId;
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos );
+ }
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+BOOL MenuBar::HandleMenuCommandEvent( Menu *pMenu, USHORT nCommandEventId ) const
+{
+ if( !pMenu )
+ pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId );
+ if( pMenu )
+ {
+ pMenu->nSelectedId = nCommandEventId;
+ pMenu->pStartedFrom = (Menu*)this;
+ pMenu->ImplSelect();
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, USHORT i_nPos )
+{
+ return AddMenuBarButton( i_rImage, i_rLink, String(), i_nPos );
+}
+
+USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos )
+{
+ return pWindow ? static_cast<MenuBarWindow*>(pWindow)->AddMenuBarButton( i_rImage, i_rLink, i_rToolTip, i_nPos ) : 0;
+}
+
+void MenuBar::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink )
+{
+ if( pWindow )
+ static_cast<MenuBarWindow*>(pWindow)->SetMenuBarButtonHighlightHdl( nId, rLink );
+}
+
+Rectangle MenuBar::GetMenuBarButtonRectPixel( USHORT nId )
+{
+ return pWindow ? static_cast<MenuBarWindow*>(pWindow)->GetMenuBarButtonRectPixel( nId ) : Rectangle();
+}
+
+void MenuBar::RemoveMenuBarButton( USHORT nId )
+{
+ if( pWindow )
+ static_cast<MenuBarWindow*>(pWindow)->RemoveMenuBarButton( nId );
+}
+
+BOOL MenuBar::HandleMenuButtonEvent( Menu *, USHORT i_nButtonId ) const
+{
+ return static_cast<MenuBarWindow*>(pWindow)->HandleMenuButtonEvent( i_nButtonId );
+}
+
+// -----------------------------------------------------------------------
+
+// BOOL PopupMenu::bAnyPopupInExecute = FALSE;
+
+PopupMenu::PopupMenu()
+{
+ pRefAutoSubMenu = NULL;
+}
+
+PopupMenu::PopupMenu( const ResId& rResId )
+{
+ pRefAutoSubMenu = NULL;
+ ImplLoadRes( rResId );
+}
+
+PopupMenu::PopupMenu( const PopupMenu& rMenu ) : Menu()
+{
+ pRefAutoSubMenu = NULL;
+ *this = rMenu;
+}
+
+PopupMenu::~PopupMenu()
+{
+ if( pRefAutoSubMenu && *pRefAutoSubMenu == this )
+ *pRefAutoSubMenu = NULL; // #111060# avoid second delete in ~MenuItemData
+}
+
+BOOL PopupMenu::IsInExecute()
+{
+ return GetActivePopupMenu() ? TRUE : FALSE;
+}
+
+PopupMenu* PopupMenu::GetActivePopupMenu()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->maAppData.mpActivePopupMenu;
+}
+
+void PopupMenu::EndExecute( USHORT nSelectId )
+{
+ if ( ImplGetWindow() )
+ ImplGetFloatingWindow()->EndExecute( nSelectId );
+}
+
+void PopupMenu::SelectEntry( USHORT nId )
+{
+ if ( ImplGetWindow() )
+ {
+ if( nId != ITEMPOS_INVALID )
+ {
+ USHORT nPos;
+ MenuItemData* pData = GetItemList()->GetData( nId, nPos );
+ if ( pData->pSubMenu )
+ ImplGetFloatingWindow()->ChangeHighlightItem( nPos, TRUE );
+ else
+ ImplGetFloatingWindow()->EndExecute( nId );
+ }
+ else
+ {
+ MenuFloatingWindow* pFloat = ImplGetFloatingWindow();
+ pFloat->GrabFocus();
+ USHORT nPos;
+ for( nPos = 0; nPos < GetItemList()->Count(); nPos++ )
+ {
+ MenuItemData* pData = (MenuItemData*)GetItemList()->GetObject( nPos );
+ if( pData->pSubMenu )
+ {
+ pFloat->KillActivePopup();
+ }
+ }
+ pFloat->ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ }
+ }
+}
+
+void PopupMenu::SetSelectedEntry( USHORT nId )
+{
+ nSelectedId = nId;
+}
+
+USHORT PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos )
+{
+ return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN );
+}
+
+USHORT PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, USHORT nFlags )
+{
+ ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 );
+
+
+ ULONG nPopupModeFlags = 0;
+ if ( nFlags & POPUPMENU_EXECUTE_DOWN )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
+ else if ( nFlags & POPUPMENU_EXECUTE_UP )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_UP;
+ else if ( nFlags & POPUPMENU_EXECUTE_LEFT )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_LEFT;
+ else if ( nFlags & POPUPMENU_EXECUTE_RIGHT )
+ nPopupModeFlags = FLOATWIN_POPUPMODE_RIGHT;
+ else
+ nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN;
+
+ if (nFlags & POPUPMENU_NOMOUSEUPCLOSE ) // allow popup menus to stay open on mouse button up
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; // useful if the menu was opened on mousebutton down (eg toolbox configuration)
+
+ return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, FALSE );
+}
+
+USHORT PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, ULONG nPopupModeFlags, Menu* pSFrom, BOOL bPreSelectFirst )
+{
+ if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) )
+ return 0;
+
+ delete mpLayoutData, mpLayoutData = NULL;
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ pStartedFrom = pSFrom;
+ nSelectedId = 0;
+ bCanceled = FALSE;
+
+ ULONG nFocusId = 0;
+ BOOL bRealExecute = FALSE;
+ if ( !pStartedFrom )
+ {
+ pSVData->maWinData.mbNoDeactivate = TRUE;
+ nFocusId = Window::SaveFocus();
+ bRealExecute = TRUE;
+ }
+ else
+ {
+ // assure that only one menu is open at a time
+ if( pStartedFrom->bIsMenuBar && pSVData->maWinData.mpFirstFloat )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+
+ DBG_ASSERT( !ImplGetWindow(), "Win?!" );
+ Rectangle aRect( rRect );
+ aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) );
+
+ WinBits nStyle = WB_BORDER;
+ if ( bRealExecute )
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_NEWLEVEL;
+ if ( !pStartedFrom || !pStartedFrom->bIsMenuBar )
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE;
+
+ nPopupModeFlags |= FLOATWIN_POPUPMODE_NOKEYCLOSE;
+
+ // Kann beim Debuggen hilfreich sein.
+ // nPopupModeFlags |= FLOATWIN_POPUPMODE_NOFOCUSCLOSE;
+
+ ImplDelData aDelData;
+ pW->ImplAddDel( &aDelData );
+
+ bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen
+ Activate();
+ bInCallback = FALSE;
+
+ if ( aDelData.IsDelete() )
+ return 0; // Error
+
+ pW->ImplRemoveDel( &aDelData );
+
+ if ( bCanceled || bKilled )
+ return 0;
+
+ if ( !GetItemCount() )
+ return 0;
+
+ // Das Flag MENU_FLAG_HIDEDISABLEDENTRIES wird vererbt.
+ if ( pSFrom )
+ {
+ if ( pSFrom->nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES )
+ nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
+ else
+ nMenuFlags &= ~MENU_FLAG_HIDEDISABLEDENTRIES;
+ }
+ else
+ // #102790# context menues shall never show disabled entries
+ nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES;
+
+
+ USHORT nVisibleEntries = ImplGetVisibleItemCount();
+ if ( !nVisibleEntries )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ {
+ String aTmpEntryText( ResId( SV_RESID_STRING_NOSELECTIONPOSSIBLE, *pResMgr ) );
+ MenuItemData* pData = pItemList->Insert(
+ 0xFFFF, MENUITEM_STRING, 0, aTmpEntryText, Image(), NULL, 0xFFFF );
+ pData->bIsTemporary = TRUE;
+ }
+ }
+ else if ( Application::GetSettings().GetStyleSettings().GetAutoMnemonic() && !( nMenuFlags & MENU_FLAG_NOAUTOMNEMONICS ) )
+ {
+ CreateAutoMnemonics();
+ }
+
+ MenuFloatingWindow* pWin = new MenuFloatingWindow( this, pW, nStyle | WB_SYSTEMWINDOW );
+ if( pSVData->maNWFData.mbFlatMenu )
+ pWin->SetBorderStyle( WINDOW_BORDER_NOBORDER );
+ else
+ pWin->SetBorderStyle( pWin->GetBorderStyle() | WINDOW_BORDER_MENU );
+ pWindow = pWin;
+
+ Size aSz = ImplCalcSize( pWin );
+
+ long nMaxHeight = pWin->GetDesktopRectPixel().GetHeight();
+ if( Application::GetScreenCount() > 1 && ! Application::IsMultiDisplay() )
+ {
+ Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT );
+ if( ! pDeskW )
+ pDeskW = pWindow;
+ Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
+ nMaxHeight = Application::GetWorkAreaPosSizePixel(
+ Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) )
+ ).GetHeight();
+ }
+ if ( pStartedFrom && pStartedFrom->bIsMenuBar )
+ nMaxHeight -= pW->GetSizePixel().Height();
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ pWindow->GetBorder( nLeft, nTop, nRight, nBottom );
+ nMaxHeight -= nTop+nBottom;
+ if ( aSz.Height() > nMaxHeight )
+ {
+ pWin->EnableScrollMenu( TRUE );
+ USHORT nStart = ImplGetFirstVisible();
+ USHORT nEntries = ImplCalcVisEntries( nMaxHeight, nStart );
+ aSz.Height() = ImplCalcHeight( nEntries );
+ }
+
+ pWin->SetFocusId( nFocusId );
+ pWin->SetOutputSizePixel( aSz );
+ // #102158# menus must never grab the focus, otherwise
+ // they will be closed immediately
+ // from now on focus grabbing is only prohibited automatically if
+ // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some
+ // floaters (like floating toolboxes) may grab the focus
+ // pWin->GrabFocus();
+ if ( GetItemCount() )
+ {
+ SalMenu* pMenu = ImplGetSalMenu();
+ if( pMenu && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) )
+ {
+ pWin->StopExecute(0);
+ pWin->doShutdown();
+ pWindow->doLazyDelete();
+ pWindow = NULL;
+ return nSelectedId;
+ }
+ else
+ {
+ pWin->StartPopupMode( aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS );
+ }
+ if( pSFrom )
+ {
+ USHORT aPos;
+ if( pSFrom->bIsMenuBar )
+ aPos = ((MenuBarWindow *) pSFrom->pWindow)->GetHighlightedItem();
+ else
+ aPos = ((MenuFloatingWindow *) pSFrom->pWindow)->GetHighlightedItem();
+
+ pWin->SetPosInParent( aPos ); // store position to be sent in SUBMENUDEACTIVATE
+ pSFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUACTIVATE, aPos );
+ }
+ }
+ if ( bPreSelectFirst )
+ {
+ USHORT nCount = (USHORT)pItemList->Count();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ if ( ( pData->bEnabled || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus() )
+ && ( pData->eType != MENUITEM_SEPARATOR ) && ImplIsVisible( n ) && ImplIsSelectable( n ) )
+ {
+ pWin->ChangeHighlightItem( n, FALSE );
+ break;
+ }
+ }
+ }
+ if ( bRealExecute )
+ {
+ pWin->ImplAddDel( &aDelData );
+
+ ImplDelData aModalWinDel;
+ pW->ImplAddDel( &aModalWinDel );
+ pW->ImplIncModalCount();
+
+ pWin->Execute();
+
+ DBG_ASSERT( ! aModalWinDel.IsDead(), "window for popup died, modal count incorrect !" );
+ if( ! aModalWinDel.IsDead() )
+ pW->ImplDecModalCount();
+
+ if ( !aDelData.IsDelete() )
+ pWin->ImplRemoveDel( &aDelData );
+ else
+ return 0;
+
+ // Focus wieder herstellen (kann schon im Select wieder
+ // hergestellt wurden sein
+ nFocusId = pWin->GetFocusId();
+ if ( nFocusId )
+ {
+ pWin->SetFocusId( 0 );
+ pSVData->maWinData.mbNoDeactivate = FALSE;
+ }
+ pWin->ImplEndPopupMode( 0, nFocusId );
+
+ if ( nSelectedId ) // Dann abraeumen... ( sonst macht TH das )
+ {
+ PopupMenu* pSub = pWin->GetActivePopup();
+ while ( pSub )
+ {
+ pSub->ImplGetFloatingWindow()->EndPopupMode();
+ pSub = pSub->ImplGetFloatingWindow()->GetActivePopup();
+ }
+ }
+ pWin->doShutdown();
+ pWindow->doLazyDelete();
+ pWindow = NULL;
+
+ // Steht noch ein Select aus?
+ Menu* pSelect = ImplFindSelectMenu();
+ if ( pSelect )
+ {
+ // Beim Popup-Menu muss das Select vor dem Verlassen von Execute gerufen werden!
+ Application::RemoveUserEvent( pSelect->nEventId );
+ pSelect->nEventId = 0;
+ pSelect->Select();
+ }
+ }
+
+ return bRealExecute ? nSelectedId : 0;
+}
+
+USHORT PopupMenu::ImplCalcVisEntries( long nMaxHeight, USHORT nStartEntry, USHORT* pLastVisible ) const
+{
+ nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight();
+
+ long nHeight = 0;
+ USHORT nEntries = (USHORT) pItemList->Count();
+ USHORT nVisEntries = 0;
+
+ if ( pLastVisible )
+ *pLastVisible = 0;
+
+ for ( USHORT n = nStartEntry; n < nEntries; n++ )
+ {
+ if ( ImplIsVisible( n ) )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ nHeight += pData->aSz.Height();
+ if ( nHeight > nMaxHeight )
+ break;
+
+ if ( pLastVisible )
+ *pLastVisible = n;
+ nVisEntries++;
+ }
+ }
+ return nVisEntries;
+}
+
+long PopupMenu::ImplCalcHeight( USHORT nEntries ) const
+{
+ long nHeight = 0;
+
+ USHORT nFound = 0;
+ for ( USHORT n = 0; ( nFound < nEntries ) && ( n < pItemList->Count() ); n++ )
+ {
+ if ( ImplIsVisible( (USHORT) n ) )
+ {
+ MenuItemData* pData = pItemList->GetDataFromPos( n );
+ nHeight += pData->aSz.Height();
+ nFound++;
+ }
+ }
+
+ nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight();
+
+ return nHeight;
+}
+
+
+static void ImplInitMenuWindow( Window* pWin, BOOL bFont, BOOL bMenuBar )
+{
+ const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
+
+ if ( bFont )
+ pWin->SetPointFont( rStyleSettings.GetMenuFont() );
+ if( bMenuBar )
+ {
+ if( pWin->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ pWin->SetBackground(); // background will be drawn by NWF
+ }
+ else
+ {
+ Wallpaper aWallpaper;
+ aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT );
+ pWin->SetBackground( aWallpaper );
+ pWin->SetPaintTransparent( FALSE );
+ pWin->SetParentClipMode( 0 );
+ }
+ }
+ else
+ {
+ if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
+ {
+ pWin->SetBackground(); // background will be drawn by NWF
+ }
+ else
+ pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) );
+ }
+
+ if ( bMenuBar )
+ pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() );
+ else
+ pWin->SetTextColor( rStyleSettings.GetMenuTextColor() );
+ pWin->SetTextFillColor();
+ pWin->SetLineColor();
+}
+
+MenuFloatingWindow::MenuFloatingWindow( Menu* pMen, Window* pParent, WinBits nStyle ) :
+ FloatingWindow( pParent, nStyle )
+{
+ mpWindowImpl->mbMenuFloatingWindow= TRUE;
+ pMenu = pMen;
+ pActivePopup = 0;
+ nSaveFocusId = 0;
+ bInExecute = FALSE;
+ bScrollMenu = FALSE;
+ nHighlightedItem = ITEMPOS_INVALID;
+ nMBDownPos = ITEMPOS_INVALID;
+ nPosInParent = ITEMPOS_INVALID;
+ nScrollerHeight = 0;
+// nStartY = 0;
+ nBorder = EXTRASPACEY;
+ nFirstEntry = 0;
+ bScrollUp = FALSE;
+ bScrollDown = FALSE;
+ bIgnoreFirstMove = TRUE;
+ bKeyInput = FALSE;
+
+ EnableSaveBackground();
+ ImplInitMenuWindow( this, TRUE, FALSE );
+
+ SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) );
+
+ aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) );
+ aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
+ aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() );
+ aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) );
+ aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) );
+
+ AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
+}
+
+void MenuFloatingWindow::doShutdown()
+{
+ if( pMenu )
+ {
+ // #105373# notify toolkit that highlight was removed
+ // otherwise the entry will not be read when the menu is opened again
+ if( nHighlightedItem != ITEMPOS_INVALID )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
+
+ if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
+ {
+ // #102461# remove highlight in parent
+ MenuItemData* pData;
+ USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count();
+ for(i = 0; i < nCount; i++)
+ {
+ pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
+ if( pData && ( pData->pSubMenu == pMenu ) )
+ break;
+ }
+ if( i < nCount )
+ {
+ MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
+ if( pPWin )
+ pPWin->HighlightItem( i, FALSE );
+ }
+ }
+
+ // free the reference to the accessible component
+ SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
+
+ aHighlightChangedTimer.Stop();
+
+ // #95056# invalidate screen area covered by system window
+ // so this can be taken into account if the commandhandler performs a scroll operation
+ if( GetParent() )
+ {
+ Rectangle aInvRect( GetWindowExtentsRelative( GetParent() ) );
+ GetParent()->Invalidate( aInvRect );
+ }
+ pMenu = NULL;
+ RemoveEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) );
+ }
+}
+
+MenuFloatingWindow::~MenuFloatingWindow()
+{
+ doShutdown();
+}
+
+void MenuFloatingWindow::Resize()
+{
+ ImplInitClipRegion();
+}
+
+long MenuFloatingWindow::ImplGetStartY() const
+{
+ long nY = 0;
+ if( pMenu )
+ {
+ for ( USHORT n = 0; n < nFirstEntry; n++ )
+ nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height();
+ }
+ return -nY;
+}
+
+Region MenuFloatingWindow::ImplCalcClipRegion( BOOL bIncludeLogo ) const
+{
+ Size aOutSz = GetOutputSizePixel();
+ Point aPos;
+ Rectangle aRect( aPos, aOutSz );
+ aRect.Top() += nScrollerHeight;
+ aRect.Bottom() -= nScrollerHeight;
+
+ if ( pMenu && pMenu->pLogo && !bIncludeLogo )
+ aRect.Left() += pMenu->pLogo->aBitmap.GetSizePixel().Width();
+
+ Region aRegion = aRect;
+ if ( pMenu && pMenu->pLogo && bIncludeLogo && nScrollerHeight )
+ aRegion.Union( Rectangle( Point(), Size( pMenu->pLogo->aBitmap.GetSizePixel().Width(), aOutSz.Height() ) ) );
+
+ return aRegion;
+}
+
+void MenuFloatingWindow::ImplInitClipRegion()
+{
+ if ( IsScrollMenu() )
+ {
+ SetClipRegion( ImplCalcClipRegion() );
+ }
+ else
+ {
+ SetClipRegion();
+ }
+}
+
+void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, BOOL bMBDown )
+{
+ if( ! pMenu )
+ return;
+
+ long nY = nScrollerHeight;
+ long nMouseY = rMEvt.GetPosPixel().Y();
+ Size aOutSz = GetOutputSizePixel();
+ if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) )
+ {
+ BOOL bHighlighted = FALSE;
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ nY += ImplGetStartY(); // ggf. gescrollt.
+ for ( USHORT n = 0; !bHighlighted && ( n < nCount ); n++ )
+ {
+ if ( pMenu->ImplIsVisible( n ) )
+ {
+ MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( n );
+ long nOldY = nY;
+ nY += pItemData->aSz.Height();
+ if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) && pMenu->ImplIsSelectable( n ) )
+ {
+ BOOL bPopupArea = TRUE;
+ if ( pItemData->nBits & MIB_POPUPSELECT )
+ {
+ // Nur wenn ueber dem Pfeil geklickt wurde...
+ Size aSz = GetOutputSizePixel();
+ long nFontHeight = GetTextHeight();
+ bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) );
+ }
+
+ if ( bMBDown )
+ {
+ if ( n != nHighlightedItem )
+ {
+ ChangeHighlightItem( (USHORT)n, FALSE );
+ }
+
+ BOOL bAllowNewPopup = TRUE;
+ if ( pActivePopup )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup );
+ if ( bAllowNewPopup )
+ KillActivePopup();
+ }
+
+ if ( bPopupArea && bAllowNewPopup )
+ {
+ HighlightChanged( NULL );
+ }
+ }
+ else
+ {
+ if ( n != nHighlightedItem )
+ {
+ ChangeHighlightItem( (USHORT)n, TRUE );
+ }
+ else if ( pItemData->nBits & MIB_POPUPSELECT )
+ {
+ if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) )
+ HighlightChanged( NULL );
+ }
+ }
+ bHighlighted = TRUE;
+ }
+ }
+ }
+ if ( !bHighlighted )
+ ChangeHighlightItem( ITEMPOS_INVALID, TRUE );
+ }
+ else
+ {
+ ImplScroll( rMEvt.GetPosPixel() );
+ ChangeHighlightItem( ITEMPOS_INVALID, TRUE );
+ }
+}
+
+IMPL_LINK( MenuFloatingWindow, PopupEnd, FloatingWindow*, EMPTYARG )
+{
+ // "this" will be deleted before the end of this method!
+ Menu* pM = pMenu;
+ if ( bInExecute )
+ {
+ if ( pActivePopup )
+ {
+ //DBG_ASSERT( !pActivePopup->ImplGetWindow(), "PopupEnd, obwohl pActivePopup MIT Window!" );
+ KillActivePopup(); // should be ok to just remove it
+ //pActivePopup->bCanceled = TRUE;
+ }
+ bInExecute = FALSE;
+ pMenu->bInCallback = TRUE;
+ pMenu->Deactivate();
+ pMenu->bInCallback = FALSE;
+ }
+ else
+ {
+ if( pMenu )
+ {
+ // Wenn dies Fenster von TH geschlossen wurde, hat noch ein anderes
+ // Menu dieses Fenster als pActivePopup.
+ if ( pMenu->pStartedFrom )
+ {
+ // Das pWin am 'Parent' kann aber schon 0 sein, falls die Kette von
+ // vorne abgeraeumt wurde und jetzt die EndPopup-Events eintrudeln
+ if ( pMenu->pStartedFrom->bIsMenuBar )
+ {
+ MenuBarWindow* p = (MenuBarWindow*) pMenu->pStartedFrom->ImplGetWindow();
+ if ( p )
+ p->PopupClosed( pMenu );
+ }
+ else
+ {
+ MenuFloatingWindow* p = (MenuFloatingWindow*) pMenu->pStartedFrom->ImplGetWindow();
+ if ( p )
+ p->KillActivePopup( (PopupMenu*)pMenu );
+ }
+ }
+ }
+ }
+
+ if ( pM )
+ pM->pStartedFrom = 0;
+
+ return 0;
+}
+
+IMPL_LINK( MenuFloatingWindow, AutoScroll, Timer*, EMPTYARG )
+{
+ ImplScroll( GetPointerPosPixel() );
+ return 1;
+}
+
+IMPL_LINK( MenuFloatingWindow, HighlightChanged, Timer*, pTimer )
+{
+ if( ! pMenu )
+ return 0;
+
+ MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
+ if ( pItemData )
+ {
+ if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
+ {
+ ULONG nOldFlags = GetPopupModeFlags();
+ SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
+ KillActivePopup();
+ SetPopupModeFlags( nOldFlags );
+ }
+ if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) )
+ {
+ pActivePopup = (PopupMenu*)pItemData->pSubMenu;
+ long nY = nScrollerHeight+ImplGetStartY();
+ MenuItemData* pData = 0;
+ for ( ULONG n = 0; n < nHighlightedItem; n++ )
+ {
+ pData = pMenu->pItemList->GetDataFromPos( n );
+ nY += pData->aSz.Height();
+ }
+ pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
+ Size MySize = GetOutputSizePixel();
+// Point MyPos = GetPosPixel();
+// Point aItemTopLeft( MyPos.X(), MyPos.Y()+nY );
+ Point aItemTopLeft( 0, nY );
+ Point aItemBottomRight( aItemTopLeft );
+ aItemBottomRight.X() += MySize.Width();
+ aItemBottomRight.Y() += pData->aSz.Height();
+
+ // Popups leicht versetzen:
+ aItemTopLeft.X() += 2;
+ aItemBottomRight.X() -= 2;
+ if ( nHighlightedItem )
+ aItemTopLeft.Y() -= 2;
+ else
+ {
+ sal_Int32 nL, nT, nR, nB;
+ GetBorder( nL, nT, nR, nB );
+ aItemTopLeft.Y() -= nT;
+ }
+
+ // pTest: Wegen Abstuerzen durch Reschedule() im Aufruf von Activate()
+ // Ausserdem wird damit auch verhindert, dass SubMenus angezeigt werden,
+ // die lange im Activate Rescheduled haben und jetzt schon nicht mehr
+ // angezeigt werden sollen.
+ Menu* pTest = pActivePopup;
+ ULONG nOldFlags = GetPopupModeFlags();
+ SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE );
+ USHORT nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? FALSE : TRUE );
+ SetPopupModeFlags( nOldFlags );
+
+ // nRet != 0, wenn es waerend Activate() abgeschossen wurde...
+ if ( !nRet && ( pActivePopup == pTest ) && pActivePopup->ImplGetWindow() )
+ pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
+ }
+ }
+
+ return 0;
+}
+
+IMPL_LINK( MenuFloatingWindow, SubmenuClose, Timer*, EMPTYARG )
+{
+ if( pMenu && pMenu->pStartedFrom )
+ {
+ MenuFloatingWindow* pWin = (MenuFloatingWindow*) pMenu->pStartedFrom->GetWindow();
+ if( pWin )
+ pWin->KillActivePopup();
+ }
+ return 0;
+}
+
+IMPL_LINK( MenuFloatingWindow, ShowHideListener, VclWindowEvent*, pEvent )
+{
+ if( ! pMenu )
+ return 0;
+
+ if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
+ else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
+ return 0;
+}
+
+void MenuFloatingWindow::EnableScrollMenu( BOOL b )
+{
+ bScrollMenu = b;
+ nScrollerHeight = b ? (USHORT) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0;
+ bScrollDown = TRUE;
+ ImplInitClipRegion();
+}
+
+void MenuFloatingWindow::Execute()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu;
+
+ bInExecute = TRUE;
+// bCallingSelect = FALSE;
+
+ while ( bInExecute )
+ Application::Yield();
+
+ pSVData->maAppData.mpActivePopupMenu = NULL;
+
+// while ( bCallingSelect )
+// Application::Yield();
+}
+
+void MenuFloatingWindow::StopExecute( ULONG nFocusId )
+{
+ // Focus wieder herstellen
+ // (kann schon im Select wieder hergestellt wurden sein)
+ if ( nSaveFocusId )
+ {
+ Window::EndSaveFocus( nFocusId, FALSE );
+ nFocusId = nSaveFocusId;
+ if ( nFocusId )
+ {
+ nSaveFocusId = 0;
+ ImplGetSVData()->maWinData.mbNoDeactivate = FALSE;
+ }
+ }
+ ImplEndPopupMode( 0, nFocusId );
+
+ aHighlightChangedTimer.Stop();
+ bInExecute = FALSE;
+ if ( pActivePopup )
+ {
+ KillActivePopup();
+ }
+ // notify parent, needed for accessibility
+ if( pMenu && pMenu->pStartedFrom )
+ pMenu->pStartedFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUDEACTIVATE, nPosInParent );
+}
+
+void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly )
+{
+ if ( pActivePopup && ( !pThisOnly || ( pThisOnly == pActivePopup ) ) )
+ {
+ if( pActivePopup->pWindow != NULL )
+ if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
+ return; // kill it later
+ if ( pActivePopup->bInCallback )
+ pActivePopup->bCanceled = TRUE;
+
+ // Vor allen Aktionen schon pActivePopup = 0, falls z.B.
+ // PopupModeEndHdl des zu zerstoerenden Popups mal synchron gerufen wird.
+ PopupMenu* pPopup = pActivePopup;
+ pActivePopup = NULL;
+ pPopup->bInCallback = TRUE;
+ pPopup->Deactivate();
+ pPopup->bInCallback = FALSE;
+ if ( pPopup->ImplGetWindow() )
+ {
+ pPopup->ImplGetFloatingWindow()->StopExecute();
+ pPopup->ImplGetFloatingWindow()->doShutdown();
+ pPopup->pWindow->doLazyDelete();
+ pPopup->pWindow = NULL;
+
+ Update();
+ }
+ }
+}
+
+void MenuFloatingWindow::EndExecute()
+{
+ Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL;
+ ULONG nFocusId = 0;
+ if ( pStart && pStart->bIsMenuBar )
+ {
+ nFocusId = ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->GetFocusId();
+ if ( nFocusId )
+ {
+ ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->SetFocusId( 0 );
+ ImplGetSVData()->maWinData.mbNoDeactivate = FALSE;
+ }
+ }
+
+ // Wenn von woanders gestartet, dann ab dort aufraumen:
+ MenuFloatingWindow* pCleanUpFrom = this;
+ MenuFloatingWindow* pWin = this;
+ while ( pWin && !pWin->bInExecute &&
+ pWin->pMenu->pStartedFrom && !pWin->pMenu->pStartedFrom->bIsMenuBar )
+ {
+ pWin = ((PopupMenu*)pWin->pMenu->pStartedFrom)->ImplGetFloatingWindow();
+ }
+ if ( pWin )
+ pCleanUpFrom = pWin;
+
+ // Dies Fenster wird gleich zerstoert => Daten lokal merken...
+ Menu* pM = pMenu;
+ USHORT nItem = nHighlightedItem;
+
+ pCleanUpFrom->StopExecute( nFocusId );
+
+ if ( nItem != ITEMPOS_INVALID && pM )
+ {
+ MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem );
+ if ( pItemData && !pItemData->bIsTemporary )
+ {
+ pM->nSelectedId = pItemData->nId;
+ if ( pStart )
+ pStart->nSelectedId = pItemData->nId;
+
+ pM->ImplSelect();
+ }
+ }
+}
+
+void MenuFloatingWindow::EndExecute( USHORT nId )
+{
+ USHORT nPos;
+ if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) )
+ nHighlightedItem = nPos;
+ else
+ nHighlightedItem = ITEMPOS_INVALID;
+
+ EndExecute();
+}
+
+void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ // TH macht ein ToTop auf dieses Fenster, aber das aktive Popup
+ // soll oben bleiben...
+ // due to focus chage this would close all menues -> don't do it (#94123)
+ //if ( pActivePopup && pActivePopup->ImplGetWindow() && !pActivePopup->ImplGetFloatingWindow()->pActivePopup )
+ // pActivePopup->ImplGetFloatingWindow()->ToTop( TOTOP_NOGRABFOCUS );
+
+ ImplHighlightItem( rMEvt, TRUE );
+
+ nMBDownPos = nHighlightedItem;
+}
+
+void MenuFloatingWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ MenuItemData* pData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
+ // nMBDownPos in lokaler Variable merken und gleich zuruecksetzen,
+ // weil nach EndExecute zu spaet
+ USHORT _nMBDownPos = nMBDownPos;
+ nMBDownPos = ITEMPOS_INVALID;
+ if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) )
+ {
+ if ( !pData->pSubMenu )
+ {
+ EndExecute();
+ }
+ else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) )
+ {
+ // Nicht wenn ueber dem Pfeil geklickt wurde...
+ Size aSz = GetOutputSizePixel();
+ long nFontHeight = GetTextHeight();
+ if ( rMEvt.GetPosPixel().X() < ( aSz.Width() - nFontHeight - nFontHeight/4 ) )
+ EndExecute();
+ }
+ }
+
+}
+
+void MenuFloatingWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( !IsVisible() || rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
+ return;
+
+ if ( rMEvt.IsLeaveWindow() )
+ {
+#ifdef OS2
+ if ( ImplHilite(rMEvt) )
+ {
+#endif
+ // #102461# do not remove highlight if a popup menu is open at this position
+ MenuItemData* pData = pMenu ? pMenu->pItemList->GetDataFromPos( nHighlightedItem ) : NULL;
+ // close popup with some delayed if we leave somewhere else
+ if( pActivePopup && pData && pData->pSubMenu != pActivePopup )
+ pActivePopup->ImplGetFloatingWindow()->aSubmenuCloseTimer.Start();
+
+ if( !pActivePopup || (pData && pData->pSubMenu != pActivePopup ) )
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+#ifdef OS2
+ }
+#endif
+
+ if ( IsScrollMenu() )
+ ImplScroll( rMEvt.GetPosPixel() );
+ }
+ else
+#ifdef OS2
+ if ( ImplHilite(rMEvt) )
+#endif
+ {
+ aSubmenuCloseTimer.Stop();
+ if( bIgnoreFirstMove )
+ bIgnoreFirstMove = FALSE;
+ else
+ ImplHighlightItem( rMEvt, FALSE );
+ }
+}
+
+void MenuFloatingWindow::ImplScroll( BOOL bUp )
+{
+ KillActivePopup();
+ Update();
+
+ if( ! pMenu )
+ return;
+
+ HighlightItem( nHighlightedItem, FALSE );
+
+ pMenu->ImplKillLayoutData();
+
+ if ( bScrollUp && bUp )
+ {
+ nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry );
+ DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
+
+ long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
+
+// nStartY += nEntryHeight;
+
+ if ( !bScrollDown )
+ {
+ bScrollDown = TRUE;
+ ImplDrawScroller( FALSE );
+ }
+
+ if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID )
+ {
+ bScrollUp = FALSE;
+ ImplDrawScroller( TRUE );
+ }
+
+ Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( FALSE ).GetBoundRect(), SCROLL_CLIP );
+ }
+ else if ( bScrollDown && !bUp )
+ {
+ long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height();
+
+ nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry );
+ DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" );
+
+
+ if ( !bScrollUp )
+ {
+ bScrollUp = TRUE;
+ ImplDrawScroller( TRUE );
+ }
+
+ long nHeight = GetOutputSizePixel().Height();
+ USHORT nLastVisible;
+ ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible );
+ if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID )
+ {
+ bScrollDown = FALSE;
+ ImplDrawScroller( FALSE );
+ }
+
+// nStartY -= nEntryHeight;
+ Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( FALSE ).GetBoundRect(), SCROLL_CLIP );
+ }
+
+ HighlightItem( nHighlightedItem, TRUE );
+}
+
+void MenuFloatingWindow::ImplScroll( const Point& rMousePos )
+{
+ Size aOutSz = GetOutputSizePixel();
+
+ long nY = nScrollerHeight;
+ long nMouseY = rMousePos.Y();
+ long nDelta = 0;
+
+ if ( bScrollUp && ( nMouseY < nY ) )
+ {
+ ImplScroll( TRUE );
+ nDelta = nY - nMouseY;
+ }
+ else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) )
+ {
+ ImplScroll( FALSE );
+ nDelta = nMouseY - ( aOutSz.Height() - nY );
+ }
+
+ if ( nDelta )
+ {
+ aScrollTimer.Stop(); // Falls durch MouseMove gescrollt.
+ long nTimeout;
+ if ( nDelta < 3 )
+ nTimeout = 200;
+ else if ( nDelta < 5 )
+ nTimeout = 100;
+ else if ( nDelta < 8 )
+ nTimeout = 70;
+ else if ( nDelta < 12 )
+ nTimeout = 40;
+ else
+ nTimeout = 20;
+ aScrollTimer.SetTimeout( nTimeout );
+ aScrollTimer.Start();
+ }
+}
+void MenuFloatingWindow::ChangeHighlightItem( USHORT n, BOOL bStartPopupTimer )
+{
+ // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
+ // #65750# Dann verzichten wir lieber auf den schmalen Streifen Hintergrundsicherung.
+ // Sonst lassen sich die Menus schlecht bedienen.
+// MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
+// if ( pActivePopup && pNextData && ( pActivePopup != pNextData->pSubMenu ) )
+// KillActivePopup();
+
+ aSubmenuCloseTimer.Stop();
+ if( ! pMenu )
+ return;
+
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ HighlightItem( nHighlightedItem, FALSE );
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
+ }
+
+ nHighlightedItem = (USHORT)n;
+ DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" );
+ if( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar )
+ {
+ // #102461# make sure parent entry is highlighted as well
+ MenuItemData* pData;
+ USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count();
+ for(i = 0; i < nCount; i++)
+ {
+ pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i );
+ if( pData && ( pData->pSubMenu == pMenu ) )
+ break;
+ }
+ if( i < nCount )
+ {
+ MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow();
+ if( pPWin && pPWin->nHighlightedItem != i )
+ {
+ pPWin->HighlightItem( i, TRUE );
+ pPWin->nHighlightedItem = i;
+ }
+ }
+ }
+ HighlightItem( nHighlightedItem, TRUE );
+ pMenu->ImplCallHighlight( nHighlightedItem );
+ }
+ else
+ pMenu->nSelectedId = 0;
+
+ if ( bStartPopupTimer )
+ {
+ // #102438# Menu items are not selectable
+ // If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue
+ // or XAccessibleSelection interface, and the parent popup menus are not executed yet,
+ // the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected.
+ if ( GetSettings().GetMouseSettings().GetMenuDelay() )
+ aHighlightChangedTimer.Start();
+ else
+ HighlightChanged( &aHighlightChangedTimer );
+ }
+}
+
+void MenuFloatingWindow::HighlightItem( USHORT nPos, BOOL bHighlight )
+{
+ if( ! pMenu )
+ return;
+
+ Size aSz = GetOutputSizePixel();
+ long nStartY = ImplGetStartY();
+ long nY = nScrollerHeight+nStartY;
+ long nX = 0;
+
+ if ( pMenu->pLogo )
+ nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
+
+ int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder;
+ nY += nOuterSpace;
+
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ DBG_ASSERT( pMenu->ImplIsVisible( n ), "Highlight: Item not visible!" );
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ {
+ BOOL bRestoreLineColor = FALSE;
+ Color oldLineColor;
+ bool bDrawItemRect = true;
+
+ Rectangle aItemRect( Point( nX+nOuterSpace, nY ), Size( aSz.Width()-2*nOuterSpace, pData->aSz.Height() ) );
+ if ( pData->nBits & MIB_POPUPSELECT )
+ {
+ long nFontHeight = GetTextHeight();
+ aItemRect.Right() -= nFontHeight + nFontHeight/4;
+ }
+
+ if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
+ {
+ Size aPxSize( GetOutputSizePixel() );
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ) );
+ Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) );
+ DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
+ aCtrlRect,
+ CTRL_STATE_ENABLED,
+ ImplControlValue(),
+ OUString() );
+ if( bHighlight &&
+ IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
+ {
+ bDrawItemRect = false;
+ if( FALSE == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
+ aItemRect,
+ CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ),
+ ImplControlValue(),
+ OUString() ) )
+ {
+ bDrawItemRect = bHighlight;
+ }
+ }
+ else
+ bDrawItemRect = bHighlight;
+ Pop();
+ }
+ if( bDrawItemRect )
+ {
+ if ( bHighlight )
+ {
+ if( pData->bEnabled )
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
+ else
+ {
+ SetFillColor();
+ oldLineColor = GetLineColor();
+ SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
+ bRestoreLineColor = TRUE;
+ }
+ }
+ else
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
+
+ DrawRect( aItemRect );
+ }
+ pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight );
+ if( bRestoreLineColor )
+ SetLineColor( oldLineColor );
+ }
+ return;
+ }
+
+ nY += pData->aSz.Height();
+ }
+}
+
+Rectangle MenuFloatingWindow::ImplGetItemRect( USHORT nPos )
+{
+ if( ! pMenu )
+ return Rectangle();
+
+ Rectangle aRect;
+ Size aSz = GetOutputSizePixel();
+ long nStartY = ImplGetStartY();
+ long nY = nScrollerHeight+nStartY;
+ long nX = 0;
+
+ if ( pMenu->pLogo )
+ nX = pMenu->pLogo->aBitmap.GetSizePixel().Width();
+
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ DBG_ASSERT( pMenu->ImplIsVisible( n ), "ImplGetItemRect: Item not visible!" );
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ {
+ aRect = Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) );
+ if ( pData->nBits & MIB_POPUPSELECT )
+ {
+ long nFontHeight = GetTextHeight();
+ aRect.Right() -= nFontHeight + nFontHeight/4;
+ }
+ }
+ break;
+ }
+ nY += pData->aSz.Height();
+ }
+ return aRect;
+}
+
+
+void MenuFloatingWindow::ImplCursorUpDown( BOOL bUp, BOOL bHomeEnd )
+{
+ if( ! pMenu )
+ return;
+
+ const StyleSettings& rSettings = GetSettings().GetStyleSettings();
+
+ USHORT n = nHighlightedItem;
+ if ( n == ITEMPOS_INVALID )
+ {
+ if ( bUp )
+ n = 0;
+ else
+ n = pMenu->GetItemCount()-1;
+ }
+
+ USHORT nLoop = n;
+
+ if( bHomeEnd )
+ {
+ // absolute positioning
+ if( bUp )
+ {
+ n = pMenu->GetItemCount();
+ nLoop = n-1;
+ }
+ else
+ {
+ n = (USHORT)-1;
+ nLoop = n+1;
+ }
+ }
+
+ do
+ {
+ if ( bUp )
+ {
+ if ( n )
+ n--;
+ else
+ if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
+ n = pMenu->GetItemCount()-1;
+ else
+ break;
+ }
+ else
+ {
+ n++;
+ if ( n >= pMenu->GetItemCount() )
+ {
+ if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) )
+ n = 0;
+ else
+ break;
+ }
+ }
+
+ MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
+ if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() )
+ && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) )
+ {
+ // Selektion noch im sichtbaren Bereich?
+ if ( IsScrollMenu() )
+ {
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+
+ while ( n < nFirstEntry )
+ ImplScroll( TRUE );
+
+ Size aOutSz = GetOutputSizePixel();
+ USHORT nLastVisible;
+ ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
+ while ( n > nLastVisible )
+ {
+ ImplScroll( FALSE );
+ ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible );
+ }
+ }
+ ChangeHighlightItem( n, FALSE );
+ break;
+ }
+ } while ( n != nLoop );
+}
+
+void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent )
+{
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+ USHORT nCode = rKEvent.GetKeyCode().GetCode();
+ bKeyInput = TRUE;
+ switch ( nCode )
+ {
+ case KEY_UP:
+ case KEY_DOWN:
+ {
+ ImplCursorUpDown( nCode == KEY_UP );
+ }
+ break;
+ case KEY_END:
+ case KEY_HOME:
+ {
+ ImplCursorUpDown( nCode == KEY_END, TRUE );
+ }
+ break;
+ case KEY_F6:
+ case KEY_ESCAPE:
+ {
+ // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document
+ if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() )
+ break;
+ if( pMenu )
+ {
+ if ( !pMenu->pStartedFrom )
+ {
+ StopExecute();
+ KillActivePopup();
+ }
+ else if ( pMenu->pStartedFrom->bIsMenuBar )
+ {
+ // Forward...
+ ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
+ }
+ else
+ {
+ StopExecute();
+ PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom;
+ MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow();
+ pFloat->GrabFocus();
+ pFloat->KillActivePopup();
+ pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem);
+ }
+ }
+ }
+ break;
+ case KEY_LEFT:
+ {
+ if ( pMenu && pMenu->pStartedFrom )
+ {
+ StopExecute();
+ if ( pMenu->pStartedFrom->bIsMenuBar )
+ {
+ // Forward...
+ ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent );
+ }
+ else
+ {
+ MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow();
+ pFloat->GrabFocus();
+ pFloat->KillActivePopup();
+ }
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ {
+ if( pMenu )
+ {
+ BOOL bDone = FALSE;
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
+ if ( pData && pData->pSubMenu )
+ {
+ HighlightChanged( 0 );
+ bDone = TRUE;
+ }
+ }
+ if ( !bDone )
+ {
+ Menu* pStart = pMenu->ImplGetStartMenu();
+ if ( pStart && pStart->bIsMenuBar )
+ {
+ // Forward...
+ pStart->ImplGetWindow()->KeyInput( rKEvent );
+ }
+ }
+ }
+ }
+ break;
+ case KEY_RETURN:
+ {
+ if( pMenu )
+ {
+ MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem );
+ if ( pData && pData->bEnabled )
+ {
+ if ( pData->pSubMenu )
+ HighlightChanged( 0 );
+ else
+ EndExecute();
+ }
+ else
+ StopExecute();
+ }
+ }
+ break;
+ case KEY_MENU:
+ {
+ if( pMenu )
+ {
+ Menu* pStart = pMenu->ImplGetStartMenu();
+ if ( pStart && pStart->bIsMenuBar )
+ {
+ // Forward...
+ pStart->ImplGetWindow()->KeyInput( rKEvent );
+ }
+ }
+ }
+ break;
+ default:
+ {
+ xub_Unicode nCharCode = rKEvent.GetCharCode();
+ USHORT nPos = 0;
+ USHORT nDuplicates = 0;
+ MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL;
+ if ( pData )
+ {
+ if ( pData->pSubMenu || nDuplicates > 1 )
+ {
+ ChangeHighlightItem( nPos, FALSE );
+ HighlightChanged( 0 );
+ }
+ else
+ {
+ nHighlightedItem = nPos;
+ EndExecute();
+ }
+ }
+ else
+ {
+ // Bei ungueltigen Tasten Beepen, aber nicht bei HELP und F-Tasten
+ if ( !rKEvent.GetKeyCode().IsMod2() && ( nCode != KEY_HELP ) && ( rKEvent.GetKeyCode().GetGroup() != KEYGROUP_FKEYS ) )
+ Sound::Beep();
+ FloatingWindow::KeyInput( rKEvent );
+ }
+ }
+ }
+ // #105474# check if menu window was not destroyed
+ if ( !aDelData.IsDelete() )
+ {
+ ImplRemoveDel( &aDelData );
+ bKeyInput = FALSE;
+ }
+}
+
+void MenuFloatingWindow::Paint( const Rectangle& )
+{
+ if( ! pMenu )
+ return;
+
+ if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) )
+ {
+ SetClipRegion();
+ long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
+ Size aPxSize( GetOutputSizePixel() );
+ aPxSize.Width() -= nX;
+ DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL,
+ Rectangle( Point( nX, 0 ), aPxSize ),
+ CTRL_STATE_ENABLED,
+ ImplControlValue(),
+ OUString() );
+ ImplInitClipRegion();
+ }
+ if ( IsScrollMenu() )
+ {
+ ImplDrawScroller( TRUE );
+ ImplDrawScroller( FALSE );
+ }
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
+ pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() );
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ HighlightItem( nHighlightedItem, TRUE );
+}
+
+void MenuFloatingWindow::ImplDrawScroller( BOOL bUp )
+{
+ if( ! pMenu )
+ return;
+
+ SetClipRegion();
+
+ Size aOutSz = GetOutputSizePixel();
+ long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight );
+ long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0;
+ Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) );
+
+ DecorationView aDecoView( this );
+ SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN;
+
+ USHORT nStyle = 0;
+ if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) )
+ nStyle |= SYMBOL_DRAW_DISABLE;
+
+ aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
+
+ ImplInitClipRegion();
+}
+
+void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ USHORT nId = nHighlightedItem;
+ Menu* pM = pMenu;
+ Window* pW = this;
+
+ // #102618# Get item rect before destroying the window in EndExecute() call
+ Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
+
+ if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
+ {
+ nHighlightedItem = ITEMPOS_INVALID;
+ EndExecute();
+ pW = NULL;
+ }
+
+ if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) )
+ Window::RequestHelp( rHEvt );
+}
+
+void MenuFloatingWindow::StateChanged( StateChangedType nType )
+{
+ FloatingWindow::StateChanged( nType );
+
+ if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
+ {
+ ImplInitMenuWindow( this, FALSE, FALSE );
+ Invalidate();
+ }
+}
+
+void MenuFloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ FloatingWindow::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitMenuWindow( this, FALSE, FALSE );
+ Invalidate();
+ }
+}
+
+void MenuFloatingWindow::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
+ {
+// ImplCursorUpDown( pData->GetDelta() > 0L );
+ ImplScroll( pData->GetDelta() > 0L );
+ MouseMove( MouseEvent( GetPointerPosPixel(), 0 ) );
+ }
+ }
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuFloatingWindow::CreateAccessible()
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
+
+ if ( pMenu && !pMenu->pStartedFrom )
+ xAcc = pMenu->GetAccessible();
+
+ return xAcc;
+}
+
+MenuBarWindow::MenuBarWindow( Window* pParent ) :
+ Window( pParent, 0 ),
+ aCloser( this ),
+ aFloatBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ),
+ aHideBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE )
+{
+ SetType( WINDOW_MENUBARWINDOW );
+ pMenu = NULL;
+ pActivePopup = NULL;
+ nSaveFocusId = 0;
+ nHighlightedItem = ITEMPOS_INVALID;
+ mbAutoPopup = TRUE;
+ nSaveFocusId = 0;
+ bIgnoreFirstMove = TRUE;
+ bStayActive = FALSE;
+
+ ResMgr* pResMgr = ImplGetResMgr();
+
+ if( pResMgr )
+ {
+ BitmapEx aBitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) );
+ BitmapEx aBitmapHC( ResId( SV_RESID_BITMAP_CLOSEDOCHC, *pResMgr ) );
+
+ aCloser.maImage = Image( aBitmap );
+ aCloser.maImageHC = Image( aBitmapHC );
+
+ aCloser.SetOutStyle( TOOLBOX_STYLE_FLAT );
+ aCloser.SetBackground();
+ aCloser.SetPaintTransparent( TRUE );
+ aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+
+ aCloser.InsertItem( IID_DOCUMENTCLOSE,
+ GetSettings().GetStyleSettings().GetHighContrastMode() ? aCloser.maImageHC : aCloser.maImage, 0 );
+ aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) );
+ aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
+ aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, XubString( ResId( SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr ) ) );
+
+ aFloatBtn.SetClickHdl( LINK( this, MenuBarWindow, FloatHdl ) );
+ aFloatBtn.SetSymbol( SYMBOL_FLOAT );
+ aFloatBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_RESTORE, *pResMgr ) ) );
+
+ aHideBtn.SetClickHdl( LINK( this, MenuBarWindow, HideHdl ) );
+ aHideBtn.SetSymbol( SYMBOL_HIDE );
+ aHideBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_MINIMIZE, *pResMgr ) ) );
+ }
+
+ ImplInitStyleSettings();
+
+ AddEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
+}
+
+MenuBarWindow::~MenuBarWindow()
+{
+ aCloser.RemoveEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) );
+ RemoveEventListener( LINK( this, MenuBarWindow, ShowHideListener ) );
+}
+
+void MenuBarWindow::SetMenu( MenuBar* pMen )
+{
+ pMenu = pMen;
+ KillActivePopup();
+ nHighlightedItem = ITEMPOS_INVALID;
+ ImplInitMenuWindow( this, TRUE, TRUE );
+ if ( pMen )
+ {
+ aCloser.ShowItem( IID_DOCUMENTCLOSE, pMen->HasCloser() );
+ aCloser.Show( pMen->HasCloser() || !m_aAddButtons.empty() );
+ aFloatBtn.Show( pMen->HasFloatButton() );
+ aHideBtn.Show( pMen->HasHideButton() );
+ }
+ Invalidate();
+
+ // show and connect native menubar
+ if( pMenu && pMenu->ImplGetSalMenu() )
+ {
+ if( pMenu->ImplGetSalMenu()->VisibleMenuBar() )
+ ImplGetFrame()->SetMenu( pMenu->ImplGetSalMenu() );
+
+ pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
+ }
+}
+
+void MenuBarWindow::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide )
+{
+ aCloser.ShowItem( IID_DOCUMENTCLOSE, bClose );
+ aCloser.Show( bClose || ! m_aAddButtons.empty() );
+ aFloatBtn.Show( bFloat );
+ aHideBtn.Show( bHide );
+ Resize();
+}
+
+Size MenuBarWindow::MinCloseButtonSize()
+{
+ return aCloser.getMinSize();
+}
+
+IMPL_LINK( MenuBarWindow, CloserHdl, PushButton*, EMPTYARG )
+{
+ if( ! pMenu )
+ return 0;
+
+ if( aCloser.GetCurItemId() == IID_DOCUMENTCLOSE )
+ {
+ // #i106052# call close hdl asynchronously to ease handler implementation
+ // this avoids still being in the handler while the DecoToolBox already
+ // gets destroyed
+ Application::PostUserEvent( ((MenuBar*)pMenu)->GetCloserHdl(), pMenu );
+ }
+ else
+ {
+ std::map<USHORT,AddButtonEntry>::iterator it = m_aAddButtons.find( aCloser.GetCurItemId() );
+ if( it != m_aAddButtons.end() )
+ {
+ MenuBar::MenuBarButtonCallbackArg aArg;
+ aArg.nId = it->first;
+ aArg.bHighlight = (aCloser.GetHighlightItemId() == it->first);
+ aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
+ return it->second.m_aSelectLink.Call( &aArg );
+ }
+ }
+ return 0;
+}
+
+IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent*, pEvent )
+{
+ if( ! pMenu )
+ return 0;
+
+ MenuBar::MenuBarButtonCallbackArg aArg;
+ aArg.nId = 0xffff;
+ aArg.bHighlight = (pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT);
+ aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
+ if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT )
+ aArg.nId = aCloser.GetHighlightItemId();
+ else if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF )
+ {
+ USHORT nPos = static_cast< USHORT >(reinterpret_cast<sal_IntPtr>(pEvent->GetData()));
+ aArg.nId = aCloser.GetItemId( nPos );
+ }
+ std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId );
+ if( it != m_aAddButtons.end() )
+ {
+ it->second.m_aHighlightLink.Call( &aArg );
+ }
+ return 0;
+}
+
+IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent*, pEvent )
+{
+ if( ! pMenu )
+ return 0;
+
+ if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID );
+ else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID );
+ return 0;
+}
+
+IMPL_LINK( MenuBarWindow, FloatHdl, PushButton*, EMPTYARG )
+{
+ return pMenu ? ((MenuBar*)pMenu)->GetFloatButtonClickHdl().Call( pMenu ) : 0;
+}
+
+IMPL_LINK( MenuBarWindow, HideHdl, PushButton*, EMPTYARG )
+{
+ return pMenu ? ((MenuBar*)pMenu)->GetHideButtonClickHdl().Call( pMenu ) : 0;
+}
+
+void MenuBarWindow::ImplCreatePopup( BOOL bPreSelectFirst )
+{
+ MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL;
+ if ( pItemData )
+ {
+ bIgnoreFirstMove = TRUE;
+ if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) )
+ {
+ KillActivePopup();
+ }
+ if ( pItemData->bEnabled && pItemData->pSubMenu && ( nHighlightedItem != ITEMPOS_INVALID ) && ( pItemData->pSubMenu != pActivePopup ) )
+ {
+ pActivePopup = (PopupMenu*)pItemData->pSubMenu;
+ long nX = 0;
+ MenuItemData* pData = 0;
+ for ( ULONG n = 0; n < nHighlightedItem; n++ )
+ {
+ pData = pMenu->GetItemList()->GetDataFromPos( n );
+ nX += pData->aSz.Width();
+ }
+ pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem );
+// Point MyPos = GetPosPixel();
+// Point aItemTopLeft( MyPos.X()+nX, MyPos.Y() );
+ Point aItemTopLeft( nX, 0 );
+ Point aItemBottomRight( aItemTopLeft );
+ aItemBottomRight.X() += pData->aSz.Width();
+
+ // Im Vollbild-Modus hat die MenuBar ggf. die Hoehe 0:
+ // Nicht immer einfach die Window-Hoehe nehmen, weil ItemHeight < WindowHeight.
+ if ( GetSizePixel().Height() )
+ {
+ // #107747# give menuitems the height of the menubar
+ aItemBottomRight.Y() += GetOutputSizePixel().Height()-1;
+ }
+
+ // ImplExecute ist doch nicht modal...
+ // #99071# do not grab the focus, otherwise it will be restored to the menubar
+ // when the frame is reactivated later
+ //GrabFocus();
+ pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN, pMenu, bPreSelectFirst );
+ if ( pActivePopup )
+ {
+ // Hat kein Window, wenn vorher abgebrochen oder keine Eintraege
+ if ( pActivePopup->ImplGetFloatingWindow() )
+ pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
+ else
+ pActivePopup = NULL;
+ }
+ }
+ }
+}
+
+
+void MenuBarWindow::KillActivePopup()
+{
+ if ( pActivePopup )
+ {
+ if( pActivePopup->pWindow != NULL )
+ if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() )
+ return; // kill it later
+
+ if ( pActivePopup->bInCallback )
+ pActivePopup->bCanceled = TRUE;
+
+ pActivePopup->bInCallback = TRUE;
+ pActivePopup->Deactivate();
+ pActivePopup->bInCallback = FALSE;
+ // Abfrage auf pActivePopup, falls im Deactivate abgeschossen...
+ if ( pActivePopup && pActivePopup->ImplGetWindow() )
+ {
+ pActivePopup->ImplGetFloatingWindow()->StopExecute();
+ pActivePopup->ImplGetFloatingWindow()->doShutdown();
+ pActivePopup->pWindow->doLazyDelete();
+ pActivePopup->pWindow = NULL;
+ }
+ pActivePopup = 0;
+ }
+}
+
+void MenuBarWindow::PopupClosed( Menu* pPopup )
+{
+ if ( pPopup == pActivePopup )
+ {
+ KillActivePopup();
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, FALSE );
+ }
+}
+
+void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ mbAutoPopup = TRUE;
+ USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
+ if ( ( nEntry != ITEMPOS_INVALID ) && ( nEntry != nHighlightedItem ) )
+ {
+ ChangeHighlightItem( nEntry, FALSE );
+ }
+ else
+ {
+ KillActivePopup();
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ }
+}
+
+void MenuBarWindow::MouseButtonUp( const MouseEvent& )
+{
+}
+
+void MenuBarWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ // Im Move nur Highlighten, wenn schon eins gehighlightet.
+ if ( rMEvt.IsSynthetic() || rMEvt.IsLeaveWindow() || rMEvt.IsEnterWindow() || ( nHighlightedItem == ITEMPOS_INVALID ) )
+ return;
+
+ if( bIgnoreFirstMove )
+ {
+ bIgnoreFirstMove = FALSE;
+ return;
+ }
+
+ USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
+ if ( ( nEntry != ITEMPOS_INVALID )
+#ifdef OS2
+ && ( ImplHilite(rMEvt) )
+#endif
+ && ( nEntry != nHighlightedItem ) )
+ ChangeHighlightItem( nEntry, FALSE );
+}
+
+void MenuBarWindow::ChangeHighlightItem( USHORT n, BOOL bSelectEntry, BOOL bAllowRestoreFocus, BOOL bDefaultToDocument)
+{
+ if( ! pMenu )
+ return;
+
+ // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert.
+ MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n );
+ if ( pActivePopup && pActivePopup->ImplGetWindow() && ( !pNextData || ( pActivePopup != pNextData->pSubMenu ) ) )
+ KillActivePopup(); // pActivePopup ggf. ohne pWin, wenn in Activate() Rescheduled wurde
+
+ // Activate am MenuBar immer nur einmal pro Vorgang...
+ BOOL bJustActivated = FALSE;
+ if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) )
+ {
+ ImplGetSVData()->maWinData.mbNoDeactivate = TRUE;
+ if( !bStayActive )
+ {
+ // #105406# avoid saving the focus when we already have the focus
+ BOOL bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin );
+
+ if( nSaveFocusId )
+ {
+ if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
+ {
+ // we didn't clean up last time
+ Window::EndSaveFocus( nSaveFocusId, FALSE ); // clean up
+ nSaveFocusId = 0;
+ if( !bNoSaveFocus )
+ nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
+ }
+ else {
+ ; // do nothing: we 're activated again from taskpanelist, focus was already saved
+ }
+ }
+ else
+ {
+ if( !bNoSaveFocus )
+ nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
+ }
+ }
+ else
+ bStayActive = FALSE;
+ pMenu->bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen
+ pMenu->Activate();
+ pMenu->bInCallback = FALSE;
+ bJustActivated = TRUE;
+ }
+ else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) )
+ {
+ pMenu->bInCallback = TRUE;
+ pMenu->Deactivate();
+ pMenu->bInCallback = FALSE;
+ ImplGetSVData()->maWinData.mbNoDeactivate = FALSE;
+ if( !ImplGetSVData()->maWinData.mbNoSaveFocus )
+ {
+ ULONG nTempFocusId = nSaveFocusId;
+ nSaveFocusId = 0;
+ Window::EndSaveFocus( nTempFocusId, bAllowRestoreFocus );
+ // #105406# restore focus to document if we could not save focus before
+ if( bDefaultToDocument && !nTempFocusId && bAllowRestoreFocus )
+ GrabFocusToDocument();
+ }
+ }
+
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ {
+ HighlightItem( nHighlightedItem, FALSE );
+ pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem );
+ }
+
+ nHighlightedItem = (USHORT)n;
+ DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" );
+ HighlightItem( nHighlightedItem, TRUE );
+ pMenu->ImplCallHighlight( nHighlightedItem );
+
+ if( mbAutoPopup )
+ ImplCreatePopup( bSelectEntry );
+
+ // #58935# #73659# Focus, wenn kein Popup drunter haengt...
+ if ( bJustActivated && !pActivePopup )
+ GrabFocus();
+}
+
+void MenuBarWindow::HighlightItem( USHORT nPos, BOOL bHighlight )
+{
+ if( ! pMenu )
+ return;
+
+ long nX = 0;
+ ULONG nCount = pMenu->pItemList->Count();
+ for ( ULONG n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ {
+ // #107747# give menuitems the height of the menubar
+ Rectangle aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
+ Push( PUSH_CLIPREGION );
+ IntersectClipRegion( aRect );
+ if ( bHighlight )
+ {
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
+ IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ // draw background (transparency)
+ MenubarValue aControlValue;
+ aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+
+ Point tmp(0,0);
+ Rectangle aBgRegion( tmp, GetOutputSizePixel() );
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL,
+ aBgRegion,
+ CTRL_STATE_ENABLED,
+ aControlValue,
+ OUString() );
+ ImplAddNWFSeparator( this, aControlValue );
+
+ // draw selected item
+ DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM,
+ aRect,
+ CTRL_STATE_ENABLED | CTRL_STATE_SELECTED,
+ aControlValue,
+ OUString() );
+ }
+ else
+ {
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() );
+ SetLineColor();
+ DrawRect( aRect );
+ }
+ }
+ else
+ {
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
+ {
+ MenubarValue aMenubarValue;
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+
+ // use full window size to get proper gradient
+ // but clip accordingly
+ Point aPt;
+ Rectangle aCtrlRect( aPt, GetOutputSizePixel() );
+
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() );
+ ImplAddNWFSeparator( this, aMenubarValue );
+ }
+ else
+ Erase( aRect );
+ }
+ Pop();
+ pMenu->ImplPaint( this, 0, 0, pData, bHighlight );
+ }
+ return;
+ }
+
+ nX += pData->aSz.Width();
+ }
+}
+
+Rectangle MenuBarWindow::ImplGetItemRect( USHORT nPos )
+{
+ Rectangle aRect;
+ if( pMenu )
+ {
+ long nX = 0;
+ ULONG nCount = pMenu->pItemList->Count();
+ for ( ULONG n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( n == nPos )
+ {
+ if ( pData->eType != MENUITEM_SEPARATOR )
+ // #107747# give menuitems the height of the menubar
+ aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
+ break;
+ }
+
+ nX += pData->aSz.Width();
+ }
+ }
+ return aRect;
+}
+
+void MenuBarWindow::KeyInput( const KeyEvent& rKEvent )
+{
+ if ( !ImplHandleKeyEvent( rKEvent ) )
+ Window::KeyInput( rKEvent );
+}
+
+BOOL MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu )
+{
+ if( ! pMenu )
+ return FALSE;
+
+ if ( pMenu->bInCallback )
+ return TRUE; // schlucken
+
+ BOOL bDone = FALSE;
+ USHORT nCode = rKEvent.GetKeyCode().GetCode();
+
+ if( GetParent() )
+ {
+ if( GetParent()->GetWindow( WINDOW_CLIENT )->IsSystemWindow() )
+ {
+ SystemWindow *pSysWin = (SystemWindow*)GetParent()->GetWindow( WINDOW_CLIENT );
+ if( pSysWin->GetTaskPaneList() )
+ if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) )
+ return TRUE;
+ }
+ }
+
+ if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10
+ {
+ mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10;
+ if ( nHighlightedItem == ITEMPOS_INVALID )
+ {
+ ChangeHighlightItem( 0, FALSE );
+ GrabFocus();
+ }
+ else
+ {
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+ nSaveFocusId = 0;
+ }
+ bDone = TRUE;
+ }
+ else if ( bFromMenu )
+ {
+ if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ||
+ ( nCode == KEY_HOME ) || ( nCode == KEY_END ) )
+ {
+ USHORT n = nHighlightedItem;
+ if ( n == ITEMPOS_INVALID )
+ {
+ if ( nCode == KEY_LEFT)
+ n = 0;
+ else
+ n = pMenu->GetItemCount()-1;
+ }
+
+ // handling gtk like (aka mbOpenMenuOnF10)
+ // do not highlight an item when opening a sub menu
+ // unless there already was a higlighted sub menu item
+ bool bWasHighlight = false;
+ if( pActivePopup )
+ {
+ MenuFloatingWindow* pSubWindow = dynamic_cast<MenuFloatingWindow*>(pActivePopup->ImplGetWindow());
+ if( pSubWindow )
+ bWasHighlight = (pSubWindow->GetHighlightedItem() != ITEMPOS_INVALID);
+ }
+
+ USHORT nLoop = n;
+
+ if( nCode == KEY_HOME )
+ { n = (USHORT)-1; nLoop = n+1; }
+ if( nCode == KEY_END )
+ { n = pMenu->GetItemCount(); nLoop = n-1; }
+
+ do
+ {
+ if ( nCode == KEY_LEFT || nCode == KEY_END )
+ {
+ if ( n )
+ n--;
+ else
+ n = pMenu->GetItemCount()-1;
+ }
+ if ( nCode == KEY_RIGHT || nCode == KEY_HOME )
+ {
+ n++;
+ if ( n >= pMenu->GetItemCount() )
+ n = 0;
+ }
+
+ MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n );
+ if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) )
+ {
+ BOOL bDoSelect = TRUE;
+ if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 )
+ bDoSelect = bWasHighlight;
+ ChangeHighlightItem( n, bDoSelect );
+ break;
+ }
+ } while ( n != nLoop );
+ bDone = TRUE;
+ }
+ else if ( nCode == KEY_RETURN )
+ {
+ if( pActivePopup ) KillActivePopup();
+ else
+ if ( !mbAutoPopup )
+ {
+ ImplCreatePopup( TRUE );
+ mbAutoPopup = TRUE;
+ }
+ bDone = TRUE;
+ }
+ else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) )
+ {
+ if ( !mbAutoPopup )
+ {
+ ImplCreatePopup( TRUE );
+ mbAutoPopup = TRUE;
+ }
+ bDone = TRUE;
+ }
+ else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) )
+ {
+ if( pActivePopup )
+ {
+ // bring focus to menu bar without any open popup
+ mbAutoPopup = FALSE;
+ USHORT n = nHighlightedItem;
+ nHighlightedItem = ITEMPOS_INVALID;
+ bStayActive = TRUE;
+ ChangeHighlightItem( n, FALSE );
+ bStayActive = FALSE;
+ KillActivePopup();
+ GrabFocus();
+ }
+ else
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE );
+
+ if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() )
+ {
+ // put focus into document
+ GrabFocusToDocument();
+ }
+
+ bDone = TRUE;
+ }
+ }
+
+ if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) )
+ {
+ xub_Unicode nCharCode = rKEvent.GetCharCode();
+ if ( nCharCode )
+ {
+ USHORT nEntry, nDuplicates;
+ MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem );
+ if ( pData && (nEntry != ITEMPOS_INVALID) )
+ {
+ mbAutoPopup = TRUE;
+ ChangeHighlightItem( nEntry, TRUE );
+ bDone = TRUE;
+ }
+ else
+ {
+ // Wegen Systemmenu und anderen System-HotKeys, nur
+ // eigenstaendige Character-Kombinationen auswerten
+ USHORT nKeyCode = rKEvent.GetKeyCode().GetCode();
+ if ( ((nKeyCode >= KEY_A) && (nKeyCode <= KEY_Z)) )
+ Sound::Beep();
+ }
+ }
+ }
+ return bDone;
+}
+
+void MenuBarWindow::Paint( const Rectangle& )
+{
+ if( ! pMenu )
+ return;
+
+ // no VCL paint if native menus
+ if( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() )
+ {
+ ImplGetFrame()->DrawMenuBar();
+ return;
+ }
+
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) )
+ {
+ Point aPt;
+ Rectangle aCtrlRegion( aPt, GetOutputSizePixel() );
+
+ MenubarValue aMenubarValue;
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() );
+ ImplAddNWFSeparator( this, aMenubarValue );
+ }
+ SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() );
+ pMenu->ImplPaint( this, 0 );
+ if ( nHighlightedItem != ITEMPOS_INVALID )
+ HighlightItem( nHighlightedItem, TRUE );
+
+ // in high contrast mode draw a separating line on the lower edge
+ if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) &&
+ GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ Push( PUSH_LINECOLOR | PUSH_MAPMODE );
+ SetLineColor( Color( COL_WHITE ) );
+ SetMapMode( MapMode( MAP_PIXEL ) );
+ Size aSize = GetSizePixel();
+ DrawLine( Point( 0, aSize.Height()-1 ), Point( aSize.Width()-1, aSize.Height()-1 ) );
+ Pop();
+ }
+
+}
+
+void MenuBarWindow::Resize()
+{
+ Size aOutSz = GetOutputSizePixel();
+ long n = aOutSz.Height()-4;
+ long nX = aOutSz.Width()-3;
+ long nY = 2;
+
+ if ( aCloser.IsVisible() )
+ {
+ aCloser.Hide();
+ aCloser.SetImages( n );
+ Size aTbxSize( aCloser.CalcWindowSizePixel() );
+ nX -= aTbxSize.Width();
+ long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2;
+ aCloser.SetPosSizePixel( nX, nTbxY, aTbxSize.Width(), aTbxSize.Height() );
+ nX -= 3;
+ aCloser.Show();
+ }
+ if ( aFloatBtn.IsVisible() )
+ {
+ nX -= n;
+ aFloatBtn.SetPosSizePixel( nX, nY, n, n );
+ }
+ if ( aHideBtn.IsVisible() )
+ {
+ nX -= n;
+ aHideBtn.SetPosSizePixel( nX, nY, n, n );
+ }
+
+ aFloatBtn.SetSymbol( SYMBOL_FLOAT );
+ aHideBtn.SetSymbol( SYMBOL_HIDE );
+ //aCloser.SetSymbol( SYMBOL_CLOSE ); //is a toolbox now
+
+ Invalidate();
+}
+
+USHORT MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const
+{
+ if( pMenu )
+ {
+ long nX = 0;
+ USHORT nCount = (USHORT)pMenu->pItemList->Count();
+ for ( USHORT n = 0; n < nCount; n++ )
+ {
+ MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n );
+ if ( pMenu->ImplIsVisible( n ) )
+ {
+ nX += pData->aSz.Width();
+ if ( nX > rMousePos.X() )
+ return (USHORT)n;
+ }
+ }
+ }
+ return ITEMPOS_INVALID;
+}
+
+void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ USHORT nId = nHighlightedItem;
+ if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) )
+ ChangeHighlightItem( ITEMPOS_INVALID, TRUE );
+
+ Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) );
+ if( !ImplHandleHelpEvent( this, pMenu, nId, rHEvt, aHighlightRect ) )
+ Window::RequestHelp( rHEvt );
+}
+
+void MenuBarWindow::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) ||
+ ( nType == STATE_CHANGE_CONTROLBACKGROUND ) )
+ {
+ ImplInitMenuWindow( this, FALSE, TRUE );
+ Invalidate();
+ }
+ else if( pMenu )
+ pMenu->ImplKillLayoutData();
+
+}
+
+void MenuBarWindow::ImplLayoutChanged()
+{
+ if( pMenu )
+ {
+ ImplInitMenuWindow( this, TRUE, TRUE );
+ // Falls sich der Font geaendert hat.
+ long nHeight = pMenu->ImplCalcSize( this ).Height();
+
+ // depending on the native implementation or the displayable flag
+ // the menubar windows is supressed (ie, height=0)
+ if( !((MenuBar*) pMenu)->IsDisplayable() ||
+ ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) )
+ nHeight = 0;
+
+ SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT );
+ GetParent()->Resize();
+ Invalidate();
+ Resize();
+ if( pMenu )
+ pMenu->ImplKillLayoutData();
+ }
+}
+
+void MenuBarWindow::ImplInitStyleSettings()
+{
+ if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) &&
+ IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) )
+ {
+ Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor;
+ if( aHighlightTextColor != Color( COL_TRANSPARENT ) )
+ {
+ AllSettings aSettings( GetSettings() );
+ StyleSettings aStyle( aSettings.GetStyleSettings() );
+ aStyle.SetMenuHighlightTextColor( aHighlightTextColor );
+ aSettings.SetStyleSettings( aStyle );
+ OutputDevice::SetSettings( aSettings );
+ }
+ }
+}
+
+void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplLayoutChanged();
+ ImplInitStyleSettings();
+ }
+}
+
+void MenuBarWindow::LoseFocus()
+{
+ if ( !HasChildPathFocus( TRUE ) )
+ ChangeHighlightItem( ITEMPOS_INVALID, FALSE, FALSE );
+}
+
+void MenuBarWindow::GetFocus()
+{
+ if ( nHighlightedItem == ITEMPOS_INVALID )
+ {
+ mbAutoPopup = FALSE; // do not open menu when activated by focus handling like taskpane cycling
+ ChangeHighlightItem( 0, FALSE );
+ }
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuBarWindow::CreateAccessible()
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc;
+
+ if ( pMenu )
+ xAcc = pMenu->GetAccessible();
+
+ return xAcc;
+}
+
+USHORT MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos )
+{
+ // find first free button id
+ USHORT nId = IID_DOCUMENTCLOSE;
+ std::map< USHORT, AddButtonEntry >::const_iterator it;
+ if( i_nPos > m_aAddButtons.size() )
+ i_nPos = static_cast<USHORT>(m_aAddButtons.size());
+ do
+ {
+ nId++;
+ it = m_aAddButtons.find( nId );
+ } while( it != m_aAddButtons.end() && nId < 128 );
+ DBG_ASSERT( nId < 128, "too many addbuttons in menubar" );
+ AddButtonEntry& rNewEntry = m_aAddButtons[nId];
+ rNewEntry.m_nId = nId;
+ rNewEntry.m_aSelectLink = i_rLink;
+ aCloser.InsertItem( nId, i_rImage, 0, 0 );
+ aCloser.calcMinSize();
+ ShowButtons( aCloser.IsItemVisible( IID_DOCUMENTCLOSE ),
+ aFloatBtn.IsVisible(),
+ aHideBtn.IsVisible() );
+ ImplLayoutChanged();
+
+ if( pMenu->mpSalMenu )
+ pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) );
+
+ return nId;
+}
+
+void MenuBarWindow::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink )
+{
+ std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( nId );
+ if( it != m_aAddButtons.end() )
+ it->second.m_aHighlightLink = rLink;
+}
+
+Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( USHORT nId )
+{
+ Rectangle aRect;
+ if( m_aAddButtons.find( nId ) != m_aAddButtons.end() )
+ {
+ if( pMenu->mpSalMenu )
+ {
+ aRect = pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame );
+ if( aRect == Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
+ {
+ // system menu button is somehwere but location cannot be determined
+ return Rectangle();
+ }
+ }
+
+ if( aRect.IsEmpty() )
+ {
+ aRect = aCloser.GetItemRect( nId );
+ Point aOffset = aCloser.OutputToScreenPixel( Point() );
+ aRect.Move( aOffset.X(), aOffset.Y() );
+ }
+ }
+ return aRect;
+}
+
+void MenuBarWindow::RemoveMenuBarButton( USHORT nId )
+{
+ USHORT nPos = aCloser.GetItemPos( nId );
+ aCloser.RemoveItem( nPos );
+ m_aAddButtons.erase( nId );
+ aCloser.calcMinSize();
+ ImplLayoutChanged();
+
+ if( pMenu->mpSalMenu )
+ pMenu->mpSalMenu->RemoveMenuBarButton( nId );
+}
+
+bool MenuBarWindow::HandleMenuButtonEvent( USHORT i_nButtonId )
+{
+ std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId );
+ if( it != m_aAddButtons.end() )
+ {
+ MenuBar::MenuBarButtonCallbackArg aArg;
+ aArg.nId = it->first;
+ aArg.bHighlight = true;
+ aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu);
+ return it->second.m_aSelectLink.Call( &aArg );
+ }
+ return FALSE;
+}
+
+ImplMenuDelData::ImplMenuDelData( const Menu* pMenu )
+: mpNext( 0 )
+, mpMenu( 0 )
+{
+ if( pMenu )
+ const_cast< Menu* >( pMenu )->ImplAddDel( *this );
+}
+
+ImplMenuDelData::~ImplMenuDelData()
+{
+ if( mpMenu )
+ const_cast< Menu* >( mpMenu )->ImplRemoveDel( *this );
+}
diff --git a/vcl/source/window/mnemonic.cxx b/vcl/source/window/mnemonic.cxx
new file mode 100644
index 000000000000..c2c6c18135f2
--- /dev/null
+++ b/vcl/source/window/mnemonic.cxx
@@ -0,0 +1,419 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/mnemonic.hxx>
+
+#include <vcl/unohelp.hxx>
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+
+using namespace ::com::sun::star;
+
+
+// =======================================================================
+
+MnemonicGenerator::MnemonicGenerator()
+{
+ memset( maMnemonics, 1, sizeof( maMnemonics ) );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT MnemonicGenerator::ImplGetMnemonicIndex( sal_Unicode c )
+{
+ static USHORT const aImplMnemonicRangeTab[MNEMONIC_RANGES*2] =
+ {
+ MNEMONIC_RANGE_1_START, MNEMONIC_RANGE_1_END,
+ MNEMONIC_RANGE_2_START, MNEMONIC_RANGE_2_END,
+ MNEMONIC_RANGE_3_START, MNEMONIC_RANGE_3_END,
+ MNEMONIC_RANGE_4_START, MNEMONIC_RANGE_4_END
+ };
+
+ USHORT nMnemonicIndex = 0;
+ for ( USHORT i = 0; i < MNEMONIC_RANGES; i++ )
+ {
+ if ( (c >= aImplMnemonicRangeTab[i*2]) &&
+ (c <= aImplMnemonicRangeTab[i*2+1]) )
+ return nMnemonicIndex+c-aImplMnemonicRangeTab[i*2];
+
+ nMnemonicIndex += aImplMnemonicRangeTab[i*2+1]-aImplMnemonicRangeTab[i*2];
+ }
+
+ return MNEMONIC_INDEX_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Unicode MnemonicGenerator::ImplFindMnemonic( const XubString& rKey )
+{
+ xub_StrLen nIndex = 0;
+ while ( (nIndex = rKey.Search( MNEMONIC_CHAR, nIndex )) != STRING_NOTFOUND )
+ {
+ sal_Unicode cMnemonic = rKey.GetChar( nIndex+1 );
+ if ( cMnemonic != MNEMONIC_CHAR )
+ return cMnemonic;
+ nIndex += 2;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void MnemonicGenerator::RegisterMnemonic( const XubString& rKey )
+{
+ const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale();
+ uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass();
+
+ // Don't crash even when we don't have access to i18n service
+ if ( !xCharClass.is() )
+ return;
+
+ XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale );
+
+ // If we find a Mnemonic, set the flag. In other case count the
+ // characters, because we need this to set most as possible
+ // Mnemonics
+ sal_Unicode cMnemonic = ImplFindMnemonic( aKey );
+ if ( cMnemonic )
+ {
+ USHORT nMnemonicIndex = ImplGetMnemonicIndex( cMnemonic );
+ if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
+ maMnemonics[nMnemonicIndex] = 0;
+ }
+ else
+ {
+ xub_StrLen nIndex = 0;
+ xub_StrLen nLen = aKey.Len();
+ while ( nIndex < nLen )
+ {
+ sal_Unicode c = aKey.GetChar( nIndex );
+
+ USHORT nMnemonicIndex = ImplGetMnemonicIndex( c );
+ if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
+ {
+ if ( maMnemonics[nMnemonicIndex] && (maMnemonics[nMnemonicIndex] < 0xFF) )
+ maMnemonics[nMnemonicIndex]++;
+ }
+
+ nIndex++;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MnemonicGenerator::CreateMnemonic( XubString& rKey )
+{
+ if ( !rKey.Len() || ImplFindMnemonic( rKey ) )
+ return FALSE;
+
+ const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale();
+ uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass();
+
+ // Don't crash even when we don't have access to i18n service
+ if ( !xCharClass.is() )
+ return FALSE;
+
+ XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale );
+
+ BOOL bChanged = FALSE;
+ xub_StrLen nLen = aKey.Len();
+
+ BOOL bCJK = FALSE;
+ switch( Application::GetSettings().GetUILanguage() )
+ {
+ case LANGUAGE_JAPANESE:
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ case LANGUAGE_CHINESE_MACAU:
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ bCJK = TRUE;
+ break;
+ default:
+ break;
+ }
+ // #107889# in CJK versions ALL strings (even those that contain latin characters)
+ // will get mnemonics in the form: xyz (M)
+ // thus steps 1) and 2) are skipped for CJK locales
+
+ // #110720#, avoid CJK-style mnemonics for latin-only strings that do not contain useful mnemonic chars
+ if( bCJK )
+ {
+ BOOL bLatinOnly = TRUE;
+ BOOL bMnemonicIndexFound = FALSE;
+ sal_Unicode c;
+ xub_StrLen nIndex;
+
+ for( nIndex=0; nIndex < nLen; nIndex++ )
+ {
+ c = aKey.GetChar( nIndex );
+ if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk
+ ((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms
+ {
+ bLatinOnly = FALSE;
+ break;
+ }
+ if( ImplGetMnemonicIndex( c ) != MNEMONIC_INDEX_NOTFOUND )
+ bMnemonicIndexFound = TRUE;
+ }
+ if( bLatinOnly && !bMnemonicIndexFound )
+ return FALSE;
+ }
+
+
+ int nCJK = 0;
+ USHORT nMnemonicIndex;
+ sal_Unicode c;
+ xub_StrLen nIndex = 0;
+ if( !bCJK )
+ {
+ // 1) first try the first character of a word
+ do
+ {
+ c = aKey.GetChar( nIndex );
+
+ if ( nCJK != 2 )
+ {
+ if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk
+ ((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms
+ nCJK = 1;
+ else if ( ((c >= 0x0030) && (c <= 0x0039)) || // digits
+ ((c >= 0x0041) && (c <= 0x005A)) || // latin capitals
+ ((c >= 0x0061) && (c <= 0x007A)) || // latin small
+ ((c >= 0x0370) && (c <= 0x037F)) || // greek numeral signs
+ ((c >= 0x0400) && (c <= 0x04FF)) ) // cyrillic
+ nCJK = 2;
+ }
+
+ nMnemonicIndex = ImplGetMnemonicIndex( c );
+ if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
+ {
+ if ( maMnemonics[nMnemonicIndex] )
+ {
+ maMnemonics[nMnemonicIndex] = 0;
+ rKey.Insert( MNEMONIC_CHAR, nIndex );
+ bChanged = TRUE;
+ break;
+ }
+ }
+
+ // Search for next word
+ do
+ {
+ nIndex++;
+ c = aKey.GetChar( nIndex );
+ if ( c == ' ' )
+ break;
+ }
+ while ( nIndex < nLen );
+ nIndex++;
+ }
+ while ( nIndex < nLen );
+
+ // 2) search for a unique/uncommon character
+ if ( !bChanged )
+ {
+ USHORT nBestCount = 0xFFFF;
+ USHORT nBestMnemonicIndex = 0;
+ xub_StrLen nBestIndex = 0;
+ nIndex = 0;
+ do
+ {
+ c = aKey.GetChar( nIndex );
+ nMnemonicIndex = ImplGetMnemonicIndex( c );
+ if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
+ {
+ if ( maMnemonics[nMnemonicIndex] )
+ {
+ if ( maMnemonics[nMnemonicIndex] < nBestCount )
+ {
+ nBestCount = maMnemonics[nMnemonicIndex];
+ nBestIndex = nIndex;
+ nBestMnemonicIndex = nMnemonicIndex;
+ if ( nBestCount == 2 )
+ break;
+ }
+ }
+ }
+
+ nIndex++;
+ }
+ while ( nIndex < nLen );
+
+ if ( nBestCount != 0xFFFF )
+ {
+ maMnemonics[nBestMnemonicIndex] = 0;
+ rKey.Insert( MNEMONIC_CHAR, nBestIndex );
+ bChanged = TRUE;
+ }
+ }
+ }
+ else
+ nCJK = 1;
+
+ // 3) Add English Mnemonic for CJK Text
+ if ( !bChanged && (nCJK == 1) && rKey.Len() )
+ {
+ // Append Ascii Mnemonic
+ for ( c = MNEMONIC_RANGE_2_START; c <= MNEMONIC_RANGE_2_END; c++ )
+ {
+ nMnemonicIndex = ImplGetMnemonicIndex( c );
+ if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
+ {
+ if ( maMnemonics[nMnemonicIndex] )
+ {
+ maMnemonics[nMnemonicIndex] = 0;
+ UniString aStr( '(' );
+ aStr += MNEMONIC_CHAR;
+ aStr += c;
+ aStr += ')';
+ nIndex = rKey.Len();
+ if( nIndex >= 2 )
+ {
+ static sal_Unicode cGreaterGreater[] = { 0xFF1E, 0xFF1E };
+ if ( rKey.EqualsAscii( ">>", nIndex-2, 2 ) ||
+ rKey.Equals( cGreaterGreater, nIndex-2, 2 ) )
+ nIndex -= 2;
+ }
+ if( nIndex >= 3 )
+ {
+ static sal_Unicode cDotDotDot[] = { 0xFF0E, 0xFF0E, 0xFF0E };
+ if ( rKey.EqualsAscii( "...", nIndex-3, 3 ) ||
+ rKey.Equals( cDotDotDot, nIndex-3, 3 ) )
+ nIndex -= 3;
+ }
+ if( nIndex >= 1)
+ {
+ sal_Unicode cLastChar = rKey.GetChar( nIndex-1 );
+ if ( (cLastChar == ':') || (cLastChar == 0xFF1A) ||
+ (cLastChar == '.') || (cLastChar == 0xFF0E) ||
+ (cLastChar == '?') || (cLastChar == 0xFF1F) ||
+ (cLastChar == ' ') )
+ nIndex--;
+ }
+ rKey.Insert( aStr, nIndex );
+ bChanged = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+// #i87415# Duplicates mnemonics are bad for consistent keyboard accessibility
+// It's probably better to not have mnemonics for some widgets, than to have ambiguous ones.
+// if( ! bChanged )
+// {
+// /*
+// * #97809# if all else fails use the first character of a word
+// * anyway and live with duplicate mnemonics
+// */
+// nIndex = 0;
+// do
+// {
+// c = aKey.GetChar( nIndex );
+//
+// nMnemonicIndex = ImplGetMnemonicIndex( c );
+// if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
+// {
+// maMnemonics[nMnemonicIndex] = 0;
+// rKey.Insert( MNEMONIC_CHAR, nIndex );
+// bChanged = TRUE;
+// break;
+// }
+//
+// // Search for next word
+// do
+// {
+// nIndex++;
+// c = aKey.GetChar( nIndex );
+// if ( c == ' ' )
+// break;
+// }
+// while ( nIndex < nLen );
+// nIndex++;
+// }
+// while ( nIndex < nLen );
+// }
+
+ return bChanged;
+}
+
+// -----------------------------------------------------------------------
+
+uno::Reference< i18n::XCharacterClassification > MnemonicGenerator::GetCharClass()
+{
+ if ( !mxCharClass.is() )
+ mxCharClass = vcl::unohelper::CreateCharacterClassification();
+ return mxCharClass;
+}
+
+// -----------------------------------------------------------------------
+
+String MnemonicGenerator::EraseAllMnemonicChars( const String& rStr )
+{
+ String aStr = rStr;
+ xub_StrLen nLen = aStr.Len();
+ xub_StrLen i = 0;
+
+ while ( i < nLen )
+ {
+ if ( aStr.GetChar( i ) == '~' )
+ {
+ // check for CJK-style mnemonic
+ if( i > 0 && (i+2) < nLen )
+ {
+ sal_Unicode c = aStr.GetChar(i+1);
+ if( aStr.GetChar( i-1 ) == '(' &&
+ aStr.GetChar( i+2 ) == ')' &&
+ c >= MNEMONIC_RANGE_2_START && c <= MNEMONIC_RANGE_2_END )
+ {
+ aStr.Erase( i-1, 4 );
+ nLen -= 4;
+ i--;
+ continue;
+ }
+ }
+
+ // remove standard mnemonics
+ aStr.Erase( i, 1 );
+ nLen--;
+ }
+ else
+ i++;
+ }
+
+ return aStr;
+}
diff --git a/vcl/source/window/mnemonicengine.cxx b/vcl/source/window/mnemonicengine.cxx
new file mode 100644
index 000000000000..241aea1cf336
--- /dev/null
+++ b/vcl/source/window/mnemonicengine.cxx
@@ -0,0 +1,130 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/mnemonicengine.hxx>
+
+#include <vcl/i18nhelp.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ //====================================================================
+ //= MnemonicEngine_Data
+ //====================================================================
+ struct MnemonicEngine_Data
+ {
+ IMnemonicEntryList& rEntryList;
+
+ MnemonicEngine_Data( IMnemonicEntryList& _rEntryList )
+ :rEntryList( _rEntryList )
+ {
+ }
+ };
+
+ //--------------------------------------------------------------------
+ namespace
+ {
+ const void* lcl_getEntryForMnemonic( IMnemonicEntryList& _rEntryList, sal_Unicode _cMnemonic, bool& _rbAmbiguous )
+ {
+ _rbAmbiguous = false;
+
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ String sEntryText;
+ const void* pSearchEntry = _rEntryList.FirstSearchEntry( sEntryText );
+
+ const void* pFirstFoundEntry = NULL;
+ bool bCheckingAmbiguity = false;
+ const void* pStartedWith = pSearchEntry;
+ while ( pSearchEntry )
+ {
+ if ( rI18nHelper.MatchMnemonic( sEntryText, _cMnemonic ) )
+ {
+ if ( bCheckingAmbiguity )
+ {
+ // that's the second (at least) entry with this mnemonic
+ _rbAmbiguous = true;
+ return pFirstFoundEntry;
+ }
+
+ pFirstFoundEntry = pSearchEntry;
+ bCheckingAmbiguity = true;
+ }
+
+ pSearchEntry = _rEntryList.NextSearchEntry( pSearchEntry, sEntryText );
+ if ( pSearchEntry == pStartedWith )
+ break;
+ }
+
+ return pFirstFoundEntry;
+ }
+ }
+
+ //====================================================================
+ //= MnemonicEngine
+ //====================================================================
+ //--------------------------------------------------------------------
+ MnemonicEngine::MnemonicEngine( IMnemonicEntryList& _rEntryList )
+ :m_pData( new MnemonicEngine_Data( _rEntryList ) )
+ {
+ }
+
+ //--------------------------------------------------------------------
+ bool MnemonicEngine::HandleKeyEvent( const KeyEvent& _rKEvt )
+ {
+ BOOL bAccelKey = _rKEvt.GetKeyCode().IsMod2();
+ if ( !bAccelKey )
+ return false;
+
+ sal_Unicode cChar = _rKEvt.GetCharCode();
+ bool bAmbiguous = false;
+ const void* pEntry = lcl_getEntryForMnemonic( m_pData->rEntryList, cChar, bAmbiguous );
+ if ( !pEntry )
+ return false;
+
+ m_pData->rEntryList.SelectSearchEntry( pEntry );
+ if ( !bAmbiguous )
+ m_pData->rEntryList.ExecuteSearchEntry( pEntry );
+
+ // handled
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ MnemonicEngine::~MnemonicEngine()
+ {
+ }
+
+//........................................................................
+} // namespace vcl
+//........................................................................
diff --git a/vcl/source/window/mouseevent.cxx b/vcl/source/window/mouseevent.cxx
new file mode 100644
index 000000000000..4bfe08b3f3d8
--- /dev/null
+++ b/vcl/source/window/mouseevent.cxx
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <tools/debug.hxx>
+#include <vcl/event.hxx>
+
+/** inits this vcl KeyEvent with all settings from the given awt event **/
+MouseEvent::MouseEvent( const ::com::sun::star::awt::MouseEvent& rEvent )
+: maPos( rEvent.X, rEvent.Y )
+, mnMode( 0 )
+, mnClicks( static_cast< USHORT >( rEvent.ClickCount ) )
+, mnCode( 0 )
+{
+ if( rEvent.Modifiers )
+ {
+ if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::SHIFT) != 0 )
+ mnCode |= KEY_SHIFT;
+ if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD1) != 0 )
+ mnCode |= KEY_MOD1;
+ if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD2) != 0 )
+ mnCode |= KEY_MOD2;
+ if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD3) != 0 )
+ mnCode |= KEY_MOD3;
+ }
+
+ if( rEvent.Buttons )
+ {
+ if( (rEvent.Buttons & ::com::sun::star::awt::MouseButton::LEFT) != 0 )
+ mnCode |= MOUSE_LEFT;
+ if( (rEvent.Buttons & ::com::sun::star::awt::MouseButton::RIGHT) != 0 )
+ mnCode |= MOUSE_RIGHT;
+ if( (rEvent.Buttons & ::com::sun::star::awt::MouseButton::MIDDLE) != 0 )
+ mnCode |= MOUSE_MIDDLE;
+ }
+}
+
+/** fills out the given awt KeyEvent with all settings from this vcl event **/
+void MouseEvent::InitMouseEvent( ::com::sun::star::awt::MouseEvent& rEvent ) const
+{
+ rEvent.Modifiers = 0;
+ if ( IsShift() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::SHIFT;
+ if ( IsMod1() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD1;
+ if ( IsMod2() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD2;
+ if ( IsMod3() )
+ rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD3;
+
+ rEvent.Buttons = 0;
+ if ( IsLeft() )
+ rEvent.Buttons |= ::com::sun::star::awt::MouseButton::LEFT;
+ if ( IsRight() )
+ rEvent.Buttons |= ::com::sun::star::awt::MouseButton::RIGHT;
+ if ( IsMiddle() )
+ rEvent.Buttons |= ::com::sun::star::awt::MouseButton::MIDDLE;
+
+ rEvent.X = GetPosPixel().X();
+ rEvent.Y = GetPosPixel().Y();
+ rEvent.ClickCount = GetClicks();
+ rEvent.PopupTrigger = sal_False;
+}
diff --git a/vcl/source/window/msgbox.cxx b/vcl/source/window/msgbox.cxx
new file mode 100644
index 000000000000..7f7a65cd7fb9
--- /dev/null
+++ b/vcl/source/window/msgbox.cxx
@@ -0,0 +1,694 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/sound.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/button.hxx>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/mnemonic.hxx>
+#include <vcl/window.h>
+
+
+
+// =======================================================================
+
+static void ImplInitMsgBoxImageList()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maWinData.mpMsgBoxImgList )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ pSVData->maWinData.mpMsgBoxImgList = new ImageList(4);
+ pSVData->maWinData.mpMsgBoxHCImgList = new ImageList(4);
+ if( pResMgr )
+ {
+ Color aNonAlphaMask( 0xC0, 0xC0, 0xC0 );
+ pSVData->maWinData.mpMsgBoxImgList->InsertFromHorizontalBitmap
+ ( ResId( SV_RESID_BITMAP_MSGBOX, *pResMgr ), 4, &aNonAlphaMask );
+ pSVData->maWinData.mpMsgBoxHCImgList->InsertFromHorizontalBitmap
+ ( ResId( SV_RESID_BITMAP_MSGBOX_HC, *pResMgr ), 4, &aNonAlphaMask );
+ }
+ }
+}
+
+// =======================================================================
+
+void MessBox::ImplInitMessBoxData()
+{
+ mpFixedText = NULL;
+ mpFixedImage = NULL;
+ mnSoundType = 0;
+ mbHelpBtn = FALSE;
+ mbSound = TRUE;
+ mpCheckBox = NULL;
+ mbCheck = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void MessBox::ImplInitButtons()
+{
+ WinBits nStyle = GetStyle();
+ USHORT nOKFlags = BUTTONDIALOG_OKBUTTON;
+ USHORT nCancelFlags = BUTTONDIALOG_CANCELBUTTON;
+ USHORT nRetryFlags = 0;
+ USHORT nYesFlags = 0;
+ USHORT nNoFlags = 0;
+
+ if ( nStyle & WB_OK_CANCEL )
+ {
+ if ( nStyle & WB_DEF_CANCEL )
+ nCancelFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ else // WB_DEF_OK
+ nOKFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+
+ AddButton( BUTTON_OK, BUTTONID_OK, nOKFlags );
+ AddButton( BUTTON_CANCEL, BUTTONID_CANCEL, nCancelFlags );
+ }
+ else if ( nStyle & WB_YES_NO )
+ {
+ if ( nStyle & WB_DEF_YES )
+ nYesFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ else // WB_DEF_NO
+ nNoFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ nNoFlags |= BUTTONDIALOG_CANCELBUTTON;
+
+ AddButton( BUTTON_YES, BUTTONID_YES, nYesFlags );
+ AddButton( BUTTON_NO, BUTTONID_NO, nNoFlags );
+ }
+ else if ( nStyle & WB_YES_NO_CANCEL )
+ {
+ if ( nStyle & WB_DEF_YES )
+ nYesFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ else if ( nStyle & WB_DEF_NO )
+ nNoFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ else
+ nCancelFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+
+ AddButton( BUTTON_YES, BUTTONID_YES, nYesFlags );
+ AddButton( BUTTON_NO, BUTTONID_NO, nNoFlags );
+ AddButton( BUTTON_CANCEL, BUTTONID_CANCEL, nCancelFlags );
+ }
+ else if ( nStyle & WB_RETRY_CANCEL )
+ {
+ if ( nStyle & WB_DEF_CANCEL )
+ nCancelFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ else // WB_DEF_RETRY
+ nRetryFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+
+ AddButton( BUTTON_RETRY, BUTTONID_RETRY, nRetryFlags );
+ AddButton( BUTTON_CANCEL, BUTTONID_CANCEL, nCancelFlags );
+ }
+ else if ( nStyle & WB_ABORT_RETRY_IGNORE )
+ {
+ USHORT nAbortFlags = 0;
+ USHORT nIgnoreFlags = 0;
+
+ if ( nStyle & WB_DEF_CANCEL )
+ nAbortFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ else if ( nStyle & WB_DEF_RETRY )
+ nRetryFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+ else if ( nStyle & WB_DEF_IGNORE )
+ nIgnoreFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+
+ AddButton( BUTTON_ABORT, BUTTONID_CANCEL, nAbortFlags );
+ AddButton( BUTTON_RETRY, BUTTONID_RETRY, nRetryFlags );
+ AddButton( BUTTON_IGNORE, BUTTONID_IGNORE, nIgnoreFlags );
+ }
+ else if ( nStyle & WB_OK )
+ {
+ nOKFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON;
+
+ AddButton( BUTTON_OK, BUTTONID_OK, nOKFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MessBox::MessBox( WindowType ) :
+ ButtonDialog( WINDOW_MESSBOX )
+{
+ ImplInitMessBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+MessBox::MessBox( Window* pParent, WinBits nStyle,
+ const XubString& rTitle, const XubString& rMessage ) :
+ ButtonDialog( WINDOW_MESSBOX ),
+ maMessText( rMessage )
+{
+ ImplInitMessBoxData();
+ ImplInit( pParent, nStyle | WB_MOVEABLE | WB_HORZ | WB_CENTER );
+ ImplInitButtons();
+
+ if ( rTitle.Len() )
+ SetText( rTitle );
+}
+
+// -----------------------------------------------------------------------
+
+MessBox::MessBox( Window* pParent, const ResId& rResId ) :
+ ButtonDialog( WINDOW_MESSBOX )
+{
+ ImplInitMessBoxData();
+
+ GetRes( rResId.SetRT( RSC_MESSBOX ) );
+ USHORT nHiButtons = ReadShortRes();
+ USHORT nLoButtons = ReadShortRes();
+ USHORT nHiDefButton = ReadShortRes();
+ USHORT nLoDefButton = ReadShortRes();
+ USHORT nHiHelpId = ReadShortRes();
+ USHORT nLoHelpId = ReadShortRes();
+ /* USHORT bSysModal = */ ReadShortRes();
+ SetHelpId( ((ULONG)nHiHelpId << 16) + nLoHelpId );
+ WinBits nBits = (((ULONG)nHiButtons << 16) + nLoButtons) |
+ (((ULONG)nHiDefButton << 16) + nLoDefButton);
+ ImplInit( pParent, nBits | WB_MOVEABLE | WB_HORZ | WB_CENTER );
+
+ ImplLoadRes( rResId );
+ ImplInitButtons();
+}
+
+// -----------------------------------------------------------------------
+
+void MessBox::ImplLoadRes( const ResId& )
+{
+ SetText( ReadStringRes() );
+ SetMessText( ReadStringRes() );
+ SetHelpText( ReadStringRes() );
+}
+
+// -----------------------------------------------------------------------
+
+MessBox::~MessBox()
+{
+ if ( mpFixedText )
+ delete mpFixedText;
+ if ( mpFixedImage )
+ delete mpFixedImage;
+ if ( mpCheckBox )
+ delete mpCheckBox;
+}
+
+// -----------------------------------------------------------------------
+
+void MessBox::ImplPosControls()
+{
+ if ( GetHelpId() )
+ {
+ if ( !mbHelpBtn )
+ {
+ AddButton( BUTTON_HELP, BUTTONID_HELP, BUTTONDIALOG_HELPBUTTON, 3 );
+ mbHelpBtn = TRUE;
+ }
+ }
+ else
+ {
+ if ( mbHelpBtn )
+ {
+ RemoveButton( BUTTONID_HELP );
+ mbHelpBtn = FALSE;
+ }
+ }
+
+ XubString aMessText( maMessText );
+ TextRectInfo aTextInfo;
+ Rectangle aRect( 0, 0, 30000, 30000 );
+ Rectangle aFormatRect;
+ Point aTextPos( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+IMPL_MSGBOX_OFFSET_EXTRA_Y );
+ Size aImageSize;
+ Size aPageSize;
+ Size aFixedSize;
+ long nTitleWidth;
+ long nButtonSize = ImplGetButtonSize();
+ long nMaxWidth = GetDesktopRectPixel().GetWidth()-8;
+ long nMaxLineWidth;
+ long nWidth;
+ WinBits nWinStyle = WB_LEFT | WB_WORDBREAK | WB_NOLABEL | WB_INFO;
+ USHORT nTextStyle = TEXT_DRAW_MULTILINE | TEXT_DRAW_TOP | TEXT_DRAW_LEFT;
+
+ if ( mpFixedText )
+ delete mpFixedText;
+ if ( mpFixedImage )
+ {
+ delete mpFixedImage;
+ mpFixedImage = NULL;
+ }
+ if ( mpCheckBox )
+ {
+ mbCheck = mpCheckBox->IsChecked();
+ delete mpCheckBox;
+ mpCheckBox = NULL;
+ }
+
+
+ // Message-Text um Tabs bereinigen
+ XubString aTabStr( RTL_CONSTASCII_USTRINGPARAM( " " ) );
+ USHORT nIndex = 0;
+ while ( nIndex != STRING_NOTFOUND )
+ nIndex = aMessText.SearchAndReplace( '\t', aTabStr, nIndex );
+
+ // Wenn Fenster zu schmall, machen wir Dialog auch breiter
+ if ( mpWindowImpl->mbFrame )
+ nMaxWidth = 630;
+ else if ( nMaxWidth < 120 )
+ nMaxWidth = 120;
+
+ nMaxWidth -= mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder+4;
+
+ // MessageBox sollte min. so breit sein, das auch Title sichtbar ist
+ // Extra-Width for Closer, because Closer is set after this call
+ nTitleWidth = CalcTitleWidth();
+ nTitleWidth += mpWindowImpl->mnTopBorder;
+
+ nMaxWidth -= (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2);
+
+ // Wenn wir ein Image haben, dann deren Groesse ermitteln und das
+ // entsprechende Control anlegen und positionieren
+ aImageSize = maImage.GetSizePixel();
+ if ( aImageSize.Width() )
+ {
+ aImageSize.Width() += 4;
+ aImageSize.Height() += 4;
+ aTextPos.X() += aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE;
+ mpFixedImage = new FixedImage( this );
+ mpFixedImage->SetPosSizePixel( Point( IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_X,
+ IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_Y ),
+ aImageSize );
+ mpFixedImage->SetImage( maImage );
+ // forward the HC image
+ if( !!maImageHC )
+ mpFixedImage->SetModeImage( maImageHC, BMP_COLOR_HIGHCONTRAST );
+ mpFixedImage->Show();
+ nMaxWidth -= aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE;
+ }
+ else
+ aTextPos.X() += IMPL_MSGBOX_OFFSET_EXTRA_X;
+
+ // Maximale Zeilenlaenge ohne Wordbreak ermitteln
+ aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo );
+ nMaxLineWidth = aFormatRect.GetWidth();
+ nTextStyle |= TEXT_DRAW_WORDBREAK;
+
+ // Breite fuer Textformatierung ermitteln
+ if ( nMaxLineWidth > 450 )
+ nWidth = 450;
+ else if ( nMaxLineWidth > 300 )
+ nWidth = nMaxLineWidth+5;
+ else
+ nWidth = 300;
+ if ( nButtonSize > nWidth )
+ nWidth = nButtonSize-(aTextPos.X()-IMPL_DIALOG_OFFSET);
+ if ( nWidth > nMaxWidth )
+ nWidth = nMaxWidth;
+
+ aRect.Right() = nWidth;
+ aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo );
+ if ( aTextInfo.GetMaxLineWidth() > nWidth )
+ {
+ nWidth = aTextInfo.GetMaxLineWidth()+8;
+ aRect.Right() = nWidth;
+ aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo );
+ }
+
+ // Style fuer FixedText ermitteln
+ aPageSize.Width() = aImageSize.Width();
+ aFixedSize.Width() = aTextInfo.GetMaxLineWidth()+1;
+ aFixedSize.Height() = aFormatRect.GetHeight();
+ if ( aFixedSize.Height() < aImageSize.Height() )
+ {
+ nWinStyle |= WB_VCENTER;
+ aPageSize.Height() = aImageSize.Height();
+ aFixedSize.Height() = aImageSize.Height();
+ }
+ else
+ {
+ nWinStyle |= WB_TOP;
+ aPageSize.Height() = aFixedSize.Height();
+ }
+ if ( aImageSize.Width() )
+ aPageSize.Width() += IMPL_SEP_MSGBOX_IMAGE;
+ aPageSize.Width() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2);
+ aPageSize.Width() += aFixedSize.Width()+1;
+ aPageSize.Height() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2);
+
+ if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH )
+ aPageSize.Width() = IMPL_MINSIZE_MSGBOX_WIDTH;
+ if ( aPageSize.Width() < nTitleWidth )
+ aPageSize.Width() = nTitleWidth;
+
+ if ( maCheckBoxText.Len() )
+ {
+ Size aMinCheckboxSize ( aFixedSize );
+ if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH+80 )
+ {
+ aPageSize.Width() = IMPL_MINSIZE_MSGBOX_WIDTH+80;
+ aMinCheckboxSize.Width() += 80;
+ }
+
+ // #104492# auto mnemonics for CJK strings may increase the length, so measure the
+ // checkbox length including a temporary mnemonic, the correct auto mnemonic will be
+ // generated later in the dialog (see init_show)
+
+ String aMnemonicString( maCheckBoxText );
+ if( GetSettings().GetStyleSettings().GetAutoMnemonic() )
+ {
+ if( aMnemonicString == GetNonMnemonicString( maCheckBoxText ) )
+ {
+ // no mnemonic found -> create one
+ MnemonicGenerator aMnemonicGenerator;
+ aMnemonicGenerator.CreateMnemonic( aMnemonicString );
+ }
+ }
+
+ mpCheckBox = new CheckBox( this );
+ mpCheckBox->Check( mbCheck );
+ mpCheckBox->SetText( aMnemonicString );
+ mpCheckBox->SetStyle( mpCheckBox->GetStyle() | WB_WORDBREAK );
+ mpCheckBox->SetHelpId( GetHelpId() ); // DR: Check box and dialog have same HID
+
+ // align checkbox with message text
+ Size aSize = mpCheckBox->CalcMinimumSize( aMinCheckboxSize.Width() );
+
+ // now set the original non-mnemonic string
+ mpCheckBox->SetText( maCheckBoxText );
+
+ Point aPos( aTextPos );
+ aPos.Y() += aFixedSize.Height() + (IMPL_DIALOG_OFFSET)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2);
+
+ // increase messagebox
+ aPageSize.Height() += aSize.Height() + (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2);
+
+ mpCheckBox->SetPosSizePixel( aPos, aSize );
+ mpCheckBox->Show();
+ }
+
+ mpFixedText = new FixedText( this, nWinStyle );
+ mpFixedText->SetPosSizePixel( aTextPos, aFixedSize );
+ mpFixedText->SetText( aMessText );
+ mpFixedText->Show();
+ SetPageSizePixel( aPageSize );
+}
+
+// -----------------------------------------------------------------------
+
+void MessBox::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ ImplPosControls();
+ if ( mbSound && mnSoundType )
+ Sound::Beep( (SoundType)(mnSoundType-1), this );
+ }
+ ButtonDialog::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MessBox::GetCheckBoxState() const
+{
+ return mpCheckBox ? mpCheckBox->IsChecked() : mbCheck;
+}
+
+// -----------------------------------------------------------------------
+
+void MessBox::SetCheckBoxState( BOOL bCheck )
+{
+ if( mpCheckBox ) mpCheckBox->Check( bCheck );
+ mbCheck = bCheck;
+}
+
+// -----------------------------------------------------------------------
+
+void MessBox::SetDefaultCheckBoxText()
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ maCheckBoxText = XubString( ResId( SV_STDTEXT_DONTHINTAGAIN, *pResMgr ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL MessBox::SetModeImage( const Image& rImage, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ SetImage( rImage );
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ maImageHC = rImage;
+ else
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+const Image& MessBox::GetModeImage( BmpColorMode eMode ) const
+{
+ if( eMode == BMP_COLOR_HIGHCONTRAST )
+ return maImageHC;
+ else
+ return maImage;
+}
+
+// -----------------------------------------------------------------------
+
+void InfoBox::ImplInitInfoBoxData()
+{
+ // Default Text is the display title from the application
+ if ( !GetText().Len() )
+ SetText( Application::GetDisplayName() );
+
+ SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ?
+ InfoBox::GetStandardImageHC() : InfoBox::GetStandardImage() );
+ mnSoundType = ((USHORT)SOUND_INFO)+1;
+}
+
+// -----------------------------------------------------------------------
+
+InfoBox::InfoBox( Window* pParent, const XubString& rMessage ) :
+ MessBox( pParent, WB_OK | WB_DEF_OK, ImplGetSVEmptyStr(), rMessage )
+{
+ ImplInitInfoBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+InfoBox::InfoBox( Window* pParent, const ResId & rResId ) :
+ MessBox( pParent, rResId.SetRT( RSC_INFOBOX ) )
+{
+ ImplInitInfoBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+Image InfoBox::GetStandardImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 4 );
+}
+
+// -----------------------------------------------------------------------
+
+Image InfoBox::GetStandardImageHC()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->maWinData.mpMsgBoxHCImgList->GetImage( 4 );
+}
+
+// -----------------------------------------------------------------------
+
+void WarningBox::ImplInitWarningBoxData()
+{
+ // Default Text is the display title from the application
+ if ( !GetText().Len() )
+ SetText( Application::GetDisplayName() );
+
+ SetImage( WarningBox::GetStandardImage() );
+ mnSoundType = ((USHORT)SOUND_WARNING)+1;
+}
+
+// -----------------------------------------------------------------------
+
+WarningBox::WarningBox( Window* pParent, WinBits nStyle,
+ const XubString& rMessage ) :
+ MessBox( pParent, nStyle, ImplGetSVEmptyStr(), rMessage )
+{
+ ImplInitWarningBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+WarningBox::WarningBox( Window* pParent, const ResId& rResId ) :
+ MessBox( pParent, rResId.SetRT( RSC_WARNINGBOX ) )
+{
+ ImplInitWarningBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+void WarningBox::SetDefaultCheckBoxText()
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ maCheckBoxText = XubString( ResId( SV_STDTEXT_DONTWARNAGAIN, *pResMgr ) );
+}
+
+// -----------------------------------------------------------------------
+
+Image WarningBox::GetStandardImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 3 );
+}
+
+// -----------------------------------------------------------------------
+
+void ErrorBox::ImplInitErrorBoxData()
+{
+ // Default Text is the display title from the application
+ if ( !GetText().Len() )
+ SetText( Application::GetDisplayName() );
+
+ SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ?
+ ErrorBox::GetStandardImageHC() : ErrorBox::GetStandardImage() );
+ mnSoundType = ((USHORT)SOUND_ERROR)+1;
+}
+
+// -----------------------------------------------------------------------
+
+ErrorBox::ErrorBox( Window* pParent, WinBits nStyle,
+ const XubString& rMessage ) :
+ MessBox( pParent, nStyle, ImplGetSVEmptyStr(), rMessage )
+{
+ ImplInitErrorBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+ErrorBox::ErrorBox( Window* pParent, const ResId& rResId ) :
+ MessBox( pParent, rResId.SetRT( RSC_ERRORBOX ) )
+{
+ ImplInitErrorBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+Image ErrorBox::GetStandardImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 1 );
+}
+
+// -----------------------------------------------------------------------
+
+Image ErrorBox::GetStandardImageHC()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->maWinData.mpMsgBoxHCImgList->GetImage( 1 );
+}
+
+// -----------------------------------------------------------------------
+
+void QueryBox::ImplInitQueryBoxData()
+{
+ // Default Text is the display title from the application
+ if ( !GetText().Len() )
+ SetText( Application::GetDisplayName() );
+
+ SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ?
+ QueryBox::GetStandardImageHC() : QueryBox::GetStandardImage() );
+ mnSoundType = ((USHORT)SOUND_QUERY)+1;
+}
+
+// -----------------------------------------------------------------------
+
+QueryBox::QueryBox( Window* pParent, WinBits nStyle, const XubString& rMessage ) :
+ MessBox( pParent, nStyle, ImplGetSVEmptyStr(), rMessage )
+{
+ ImplInitQueryBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+QueryBox::QueryBox( Window* pParent, const ResId& rResId ) :
+ MessBox( pParent, rResId.SetRT( RSC_QUERYBOX ) )
+{
+ ImplInitQueryBoxData();
+}
+
+// -----------------------------------------------------------------------
+
+void QueryBox::SetDefaultCheckBoxText()
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ maCheckBoxText = XubString( ResId( SV_STDTEXT_DONTASKAGAIN, *pResMgr ) );
+}
+
+// -----------------------------------------------------------------------
+
+Image QueryBox::GetStandardImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 2 );
+}
+
+// -----------------------------------------------------------------------
+
+Image QueryBox::GetStandardImageHC()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->maWinData.mpMsgBoxHCImgList->GetImage( 2 );
+}
+
+// -----------------------------------------------------------------------
+
+Size MessBox::GetOptimalSize(WindowSizeType eType) const
+{
+ switch( eType ) {
+ case WINDOWSIZE_MINIMUM:
+ // FIXME: base me on the font size ?
+ return Size( 250, 100 );
+ default:
+ return Window::GetOptimalSize( eType );
+ }
+}
diff --git a/vcl/source/window/popupmenuwindow.cxx b/vcl/source/window/popupmenuwindow.cxx
new file mode 100644
index 000000000000..78ef0bcf1068
--- /dev/null
+++ b/vcl/source/window/popupmenuwindow.cxx
@@ -0,0 +1,79 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/popupmenuwindow.hxx"
+
+#include <limits>
+
+struct PopupMenuFloatingWindow::ImplData
+{
+ sal_uInt16 mnMenuStackLevel; // Store the stack level of a popup menu. 0 = top-level menu.
+
+ ImplData();
+ ~ImplData();
+};
+
+PopupMenuFloatingWindow::ImplData::ImplData() :
+ mnMenuStackLevel( ::std::numeric_limits<sal_uInt16>::max() )
+{
+}
+
+PopupMenuFloatingWindow::ImplData::~ImplData()
+{
+}
+
+// ============================================================================
+
+PopupMenuFloatingWindow::PopupMenuFloatingWindow( Window* pParent, WinBits nStyle ) :
+ FloatingWindow(pParent, nStyle),
+ mpImplData(new ImplData)
+{
+}
+
+PopupMenuFloatingWindow::~PopupMenuFloatingWindow()
+{
+ delete mpImplData;
+}
+
+sal_uInt16 PopupMenuFloatingWindow::GetMenuStackLevel() const
+{
+ return mpImplData->mnMenuStackLevel;
+}
+
+void PopupMenuFloatingWindow::SetMenuStackLevel( sal_uInt16 nLevel )
+{
+ mpImplData->mnMenuStackLevel = nLevel;
+}
+
+bool PopupMenuFloatingWindow::IsPopupMenu() const
+{
+ return mpImplData->mnMenuStackLevel != ::std::numeric_limits<sal_uInt16>::max();
+}
+
diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx
new file mode 100644
index 000000000000..d0fae33acf3b
--- /dev/null
+++ b/vcl/source/window/printdlg.cxx
@@ -0,0 +1,2603 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_vcl.hxx"
+
+#include "vcl/print.hxx"
+#include "vcl/prndlg.hxx"
+#include "vcl/dialog.hxx"
+#include "vcl/button.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/svids.hrc"
+#include "vcl/wall.hxx"
+#include "vcl/jobset.h"
+#include "vcl/status.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/arrange.hxx"
+#include "vcl/configsettings.hxx"
+#include "vcl/help.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/unohelp.hxx"
+
+#include "unotools/localedatawrapper.hxx"
+
+#include "rtl/ustrbuf.hxx"
+
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/container/XNameAccess.hpp"
+#include "com/sun/star/beans/PropertyValue.hpp"
+#include "com/sun/star/awt/Size.hpp"
+
+using namespace vcl;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::container;
+using namespace com::sun::star::beans;
+
+#define HELPID_PREFIX ".HelpId:vcl:PrintDialog"
+#define SMHID2( a, b ) SetSmartHelpId( SmartId( String( RTL_CONSTASCII_USTRINGPARAM( HELPID_PREFIX ":" a ":" b ) ), HID_PRINTDLG ) )
+#define SMHID1( a ) SetSmartHelpId( SmartId( String( RTL_CONSTASCII_USTRINGPARAM( HELPID_PREFIX ":" a ) ), HID_PRINTDLG ) )
+
+PrintDialog::PrintPreviewWindow::PrintPreviewWindow( Window* i_pParent, const ResId& i_rId )
+ : Window( i_pParent, i_rId )
+ , maOrigSize( 10, 10 )
+ , maPageVDev( *this )
+ , maToolTipString( String( VclResId( SV_PRINT_PRINTPREVIEW_TXT ) ) )
+{
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ if( useHCColorReplacement() )
+ maPageVDev.SetBackground( GetSettings().GetStyleSettings().GetWindowColor() );
+ else
+ maPageVDev.SetBackground( Color( COL_WHITE ) );
+}
+
+PrintDialog::PrintPreviewWindow::~PrintPreviewWindow()
+{
+}
+
+bool PrintDialog::PrintPreviewWindow::useHCColorReplacement() const
+{
+ bool bRet = false;
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ try
+ {
+ // get service provider
+ Reference< XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
+ // create configuration hierachical access name
+ if( xSMgr.is() )
+ {
+ try
+ {
+ Reference< XMultiServiceFactory > xConfigProvider(
+ Reference< XMultiServiceFactory >(
+ xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.configuration.ConfigurationProvider" ))),
+ UNO_QUERY )
+ );
+ if( xConfigProvider.is() )
+ {
+ Sequence< Any > aArgs(1);
+ PropertyValue aVal;
+ aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
+ aVal.Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Accessibility" ) );
+ aArgs.getArray()[0] <<= aVal;
+ Reference< XNameAccess > xConfigAccess(
+ Reference< XNameAccess >(
+ xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.configuration.ConfigurationAccess" )),
+ aArgs ),
+ UNO_QUERY )
+ );
+ if( xConfigAccess.is() )
+ {
+ try
+ {
+ sal_Bool bValue = sal_False;
+ Any aAny = xConfigAccess->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsForPagePreviews" ) ) );
+ if( aAny >>= bValue )
+ bRet = bool(bValue);
+ }
+ catch( NoSuchElementException& )
+ {
+ }
+ catch( WrappedTargetException& )
+ {
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ }
+ catch( WrappedTargetException& )
+ {
+ }
+ }
+ return bRet;
+}
+
+void PrintDialog::PrintPreviewWindow::DataChanged( const DataChangedEvent& i_rDCEvt )
+{
+ // react on settings changed
+ if( i_rDCEvt.GetType() == DATACHANGED_SETTINGS )
+ {
+ if( useHCColorReplacement() )
+ maPageVDev.SetBackground( GetSettings().GetStyleSettings().GetWindowColor() );
+ else
+ maPageVDev.SetBackground( Color( COL_WHITE ) );
+ }
+ Window::DataChanged( i_rDCEvt );
+}
+
+void PrintDialog::PrintPreviewWindow::Resize()
+{
+ Size aNewSize( GetSizePixel() );
+ // leave small space for decoration
+ aNewSize.Width() -= 2;
+ aNewSize.Height() -= 2;
+ Size aScaledSize;
+ double fScale = 1.0;
+
+ // #i106435# catch corner case of Size(0,0)
+ Size aOrigSize( maOrigSize );
+ if( aOrigSize.Width() < 1 )
+ aOrigSize.Width() = aNewSize.Width();
+ if( aOrigSize.Height() < 1 )
+ aOrigSize.Height() = aNewSize.Height();
+ if( aOrigSize.Width() > aOrigSize.Height() )
+ {
+ aScaledSize = Size( aNewSize.Width(), aNewSize.Width() * aOrigSize.Height() / aOrigSize.Width() );
+ if( aScaledSize.Height() > aNewSize.Height() )
+ fScale = double(aNewSize.Height())/double(aScaledSize.Height());
+ }
+ else
+ {
+ aScaledSize = Size( aNewSize.Height() * aOrigSize.Width() / aOrigSize.Height(), aNewSize.Height() );
+ if( aScaledSize.Width() > aNewSize.Width() )
+ fScale = double(aNewSize.Width())/double(aScaledSize.Width());
+ }
+ aScaledSize.Width() = long(aScaledSize.Width()*fScale);
+ aScaledSize.Height() = long(aScaledSize.Height()*fScale);
+
+ maPreviewSize = aScaledSize;
+
+ // #i104784# if we render the page too small then rounding issues result in
+ // layout artifacts looking really bad. So scale the page unto a device that is not
+ // full page size but not too small either. This also results in much better visual
+ // quality of the preview, e.g. when its height approaches the number of text lines
+ // find a good scaling factor
+ Size aPreviewMMSize( maPageVDev.PixelToLogic( aScaledSize, MapMode( MAP_100TH_MM ) ) );
+ double fZoom = double(maOrigSize.Height())/double(aPreviewMMSize.Height());
+ while( fZoom > 10 )
+ {
+ aScaledSize.Width() *= 2;
+ aScaledSize.Height() *= 2;
+ fZoom /= 2.0;
+ }
+
+ maPageVDev.SetOutputSizePixel( aScaledSize, FALSE );
+}
+
+void PrintDialog::PrintPreviewWindow::Paint( const Rectangle& )
+{
+ Size aSize( GetSizePixel() );
+ if( maReplacementString.getLength() != 0 )
+ {
+ // replacement is active
+ Push();
+ Rectangle aTextRect( Point( 0, 0 ), aSize );
+ DecorationView aVw( this );
+ aVw.DrawFrame( aTextRect, FRAME_DRAW_GROUP );
+ aTextRect.Left() += 2;
+ aTextRect.Top() += 2;
+ aTextRect.Right() -= 2;
+ aTextRect.Bottom() -= 2;
+ Font aFont( GetSettings().GetStyleSettings().GetLabelFont() );
+ SetZoomedPointFont( aFont );
+ DrawText( aTextRect, maReplacementString,
+ TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE
+ );
+ Pop();
+ }
+ else
+ {
+ GDIMetaFile aMtf( maMtf );
+
+ Point aOffset( (aSize.Width() - maPreviewSize.Width()) / 2,
+ (aSize.Height() - maPreviewSize.Height()) / 2 );
+
+ Size aVDevSize( maPageVDev.GetOutputSizePixel() );
+ const Size aLogicSize( maPageVDev.PixelToLogic( aVDevSize, MapMode( MAP_100TH_MM ) ) );
+ Size aOrigSize( maOrigSize );
+ if( aOrigSize.Width() < 1 )
+ aOrigSize.Width() = aLogicSize.Width();
+ if( aOrigSize.Height() < 1 )
+ aOrigSize.Height() = aLogicSize.Height();
+ double fScale = double(aLogicSize.Width())/double(aOrigSize.Width());
+
+
+ maPageVDev.Erase();
+ maPageVDev.Push();
+ maPageVDev.SetMapMode( MAP_100TH_MM );
+ aMtf.WindStart();
+ aMtf.Scale( fScale, fScale );
+ aMtf.WindStart();
+ aMtf.Play( &maPageVDev, Point( 0, 0 ), aLogicSize );
+ maPageVDev.Pop();
+
+ SetMapMode( MAP_PIXEL );
+ maPageVDev.SetMapMode( MAP_PIXEL );
+ DrawOutDev( aOffset, maPreviewSize, Point( 0, 0 ), aVDevSize, maPageVDev );
+
+ DecorationView aVw( this );
+ Rectangle aFrame( aOffset + Point( -1, -1 ), Size( maPreviewSize.Width() + 2, maPreviewSize.Height() + 2 ) );
+ aVw.DrawFrame( aFrame, FRAME_DRAW_GROUP );
+ }
+}
+
+void PrintDialog::PrintPreviewWindow::Command( const CommandEvent& rEvt )
+{
+ if( rEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pWheelData = rEvt.GetWheelData();
+ PrintDialog* pDlg = dynamic_cast<PrintDialog*>(GetParent());
+ if( pDlg )
+ {
+ if( pWheelData->GetDelta() > 0 )
+ pDlg->previewForward();
+ else if( pWheelData->GetDelta() < 0 )
+ pDlg->previewBackward();
+ /*
+ else
+ huh ?
+ */
+ }
+ }
+}
+
+void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile& i_rNewPreview,
+ const Size& i_rOrigSize,
+ const rtl::OUString& i_rReplacement,
+ sal_Int32 i_nDPIX,
+ sal_Int32 i_nDPIY
+ )
+{
+ rtl::OUStringBuffer aBuf( 256 );
+ aBuf.append( maToolTipString );
+ #if OSL_DEBUG_LEVEL > 0
+ aBuf.appendAscii( "\n---\nPageSize: " );
+ aBuf.append( sal_Int32( i_rOrigSize.Width()/100) );
+ aBuf.appendAscii( "mm x " );
+ aBuf.append( sal_Int32( i_rOrigSize.Height()/100) );
+ aBuf.appendAscii( "mm" );
+ #endif
+ SetQuickHelpText( aBuf.makeStringAndClear() );
+ maMtf = i_rNewPreview;
+ if( useHCColorReplacement() )
+ {
+ maMtf.ReplaceColors( Color( COL_BLACK ), Color( COL_WHITE ), 30 );
+ }
+
+ maOrigSize = i_rOrigSize;
+ maReplacementString = i_rReplacement;
+ maPageVDev.SetReferenceDevice( i_nDPIX, i_nDPIY );
+ maPageVDev.EnableOutput( TRUE );
+ Resize();
+ Invalidate();
+}
+
+PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow( Window* i_pParent )
+ : Window( i_pParent, WB_NOBORDER )
+ , mnOrderMode( 0 )
+ , mnRows( 1 )
+ , mnColumns( 1 )
+{
+ ImplInitSettings();
+}
+
+PrintDialog::ShowNupOrderWindow::~ShowNupOrderWindow()
+{
+}
+
+void PrintDialog::ShowNupOrderWindow::ImplInitSettings()
+{
+ SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
+}
+
+void PrintDialog::ShowNupOrderWindow::Paint( const Rectangle& i_rRect )
+{
+ Window::Paint( i_rRect );
+ SetMapMode( MAP_PIXEL );
+ SetTextColor( GetSettings().GetStyleSettings().GetFieldTextColor() );
+
+ int nPages = mnRows * mnColumns;
+ Font aFont( GetSettings().GetStyleSettings().GetFieldFont() );
+ aFont.SetSize( Size( 0, 24 ) );
+ SetFont( aFont );
+ Size aSampleTextSize( GetTextWidth( rtl::OUString::valueOf( sal_Int32(nPages+1) ) ), GetTextHeight() );
+
+ Size aOutSize( GetOutputSizePixel() );
+ Size aSubSize( aOutSize.Width() / mnColumns, aOutSize.Height() / mnRows );
+ // calculate font size: shrink the sample text so it fits
+ double fX = double(aSubSize.Width())/double(aSampleTextSize.Width());
+ double fY = double(aSubSize.Height())/double(aSampleTextSize.Height());
+ double fScale = (fX < fY) ? fX : fY;
+ long nFontHeight = long(24.0*fScale) - 3;
+ if( nFontHeight < 5 )
+ nFontHeight = 5;
+ aFont.SetSize( Size( 0, nFontHeight ) );
+ SetFont( aFont );
+ long nTextHeight = GetTextHeight();
+ for( int i = 0; i < nPages; i++ )
+ {
+ rtl::OUString aPageText( rtl::OUString::valueOf( sal_Int32(i+1) ) );
+ int nX = 0, nY = 0;
+ switch( mnOrderMode )
+ {
+ case SV_PRINT_PRT_NUP_ORDER_LRTD:
+ nX = (i % mnColumns); nY = (i / mnColumns);
+ break;
+ case SV_PRINT_PRT_NUP_ORDER_TDLR:
+ nX = (i / mnRows); nY = (i % mnRows);
+ break;
+ }
+ Size aTextSize( GetTextWidth( aPageText ), nTextHeight );
+ int nDeltaX = (aSubSize.Width() - aTextSize.Width()) / 2;
+ int nDeltaY = (aSubSize.Height() - aTextSize.Height()) / 2;
+ DrawText( Point( nX * aSubSize.Width() + nDeltaX,
+ nY * aSubSize.Height() + nDeltaY ),
+ aPageText );
+ }
+ DecorationView aVw( this );
+ aVw.DrawFrame( Rectangle( Point( 0, 0), aOutSize ), FRAME_DRAW_GROUP );
+}
+
+PrintDialog::NUpTabPage::NUpTabPage( Window* i_pParent, const ResId& rResId )
+ : TabPage( i_pParent, rResId )
+ , maNupLine( this, VclResId( SV_PRINT_PRT_NUP_LAYOUT_FL ) )
+ , maPagesBtn( this, VclResId( SV_PRINT_PRT_NUP_PAGES_BTN ) )
+ , maBrochureBtn( this, VclResId( SV_PRINT_PRT_NUP_BROCHURE_BTN ) )
+ , maPagesBoxTitleTxt( this, 0 )
+ , maNupPagesBox( this, VclResId( SV_PRINT_PRT_NUP_PAGES_BOX ) )
+ , maNupNumPagesTxt( this, VclResId( SV_PRINT_PRT_NUP_NUM_PAGES_TXT ) )
+ , maNupColEdt( this, VclResId( SV_PRINT_PRT_NUP_COLS_EDT ) )
+ , maNupTimesTxt( this, VclResId( SV_PRINT_PRT_NUP_TIMES_TXT ) )
+ , maNupRowsEdt( this, VclResId( SV_PRINT_PRT_NUP_ROWS_EDT ) )
+ , maPageMarginTxt1( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_1_TXT ) )
+ , maPageMarginEdt( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_EDT ) )
+ , maPageMarginTxt2( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_2_TXT ) )
+ , maSheetMarginTxt1( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_1_TXT ) )
+ , maSheetMarginEdt( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_EDT ) )
+ , maSheetMarginTxt2( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_2_TXT ) )
+ , maNupOrientationTxt( this, VclResId( SV_PRINT_PRT_NUP_ORIENTATION_TXT ) )
+ , maNupOrientationBox( this, VclResId( SV_PRINT_PRT_NUP_ORIENTATION_BOX ) )
+ , maNupOrderTxt( this, VclResId( SV_PRINT_PRT_NUP_ORDER_TXT ) )
+ , maNupOrderBox( this, VclResId( SV_PRINT_PRT_NUP_ORDER_BOX ) )
+ , maNupOrderWin( this )
+ , maBorderCB( this, VclResId( SV_PRINT_PRT_NUP_BORDER_CB ) )
+{
+ FreeResource();
+
+ maNupOrderWin.Show();
+ maPagesBtn.Check( TRUE );
+ maBrochureBtn.Show( FALSE );
+
+ // setup field units for metric fields
+ const LocaleDataWrapper& rLocWrap( maPageMarginEdt.GetLocaleDataWrapper() );
+ FieldUnit eUnit = FUNIT_MM;
+ USHORT nDigits = 0;
+ if( rLocWrap.getMeasurementSystemEnum() == MEASURE_US )
+ {
+ eUnit = FUNIT_INCH;
+ nDigits = 2;
+ }
+ // set units
+ maPageMarginEdt.SetUnit( eUnit );
+ maSheetMarginEdt.SetUnit( eUnit );
+
+ // set precision
+ maPageMarginEdt.SetDecimalDigits( nDigits );
+ maSheetMarginEdt.SetDecimalDigits( nDigits );
+
+ SMHID1( "NUpPage" );
+ maNupLine.SMHID2("NUpPage", "Layout");
+ maBrochureBtn.SMHID2("NUpPage", "Brochure" );
+ maPagesBtn.SMHID2( "NUpPage", "PagesPerSheet" );
+ maPagesBoxTitleTxt.SMHID2( "NUpPage", "PagesPerSheetLabel" );
+ maNupPagesBox.SMHID2( "NUpPage", "PagesPerSheetBox" );
+ maNupNumPagesTxt.SMHID2( "NUpPage", "Columns" );
+ maNupColEdt.SMHID2( "NUpPage", "ColumnsBox" );
+ maNupTimesTxt.SMHID2( "NUpPage", "Rows" );
+ maNupRowsEdt.SMHID2( "NUpPage", "RowsBox" );
+ maPageMarginTxt1.SMHID2( "NUpPage", "PageMargin" );
+ maPageMarginEdt.SMHID2( "NUpPage", "PageMarginBox" );
+ maPageMarginTxt2.SMHID2( "NUpPage", "PageMarginCont" );
+ maSheetMarginTxt1.SMHID2( "NUpPage", "SheetMargin" );
+ maSheetMarginEdt.SMHID2( "NUpPage", "SheetMarginBox" );
+ maSheetMarginTxt2.SMHID2( "NUpPage", "SheetMarginCont" );
+ maNupOrientationTxt.SMHID2( "NUpPage", "Orientation" );
+ maNupOrientationBox.SMHID2( "NUpPage", "OrientationBox" );
+ maNupOrderTxt.SMHID2( "NUpPage", "Order" );
+ maNupOrderBox.SMHID2( "NUpPage", "OrderBox" );
+ maBorderCB.SMHID2( "NUpPage", "BorderBox" );
+
+ setupLayout();
+}
+
+PrintDialog::NUpTabPage::~NUpTabPage()
+{
+}
+
+void PrintDialog::NUpTabPage::enableNupControls( bool bEnable )
+{
+ maNupPagesBox.Enable( TRUE );
+ maNupNumPagesTxt.Enable( bEnable );
+ maNupColEdt.Enable( bEnable );
+ maNupTimesTxt.Enable( bEnable );
+ maNupRowsEdt.Enable( bEnable );
+ maPageMarginTxt1.Enable( bEnable );
+ maPageMarginEdt.Enable( bEnable );
+ maPageMarginTxt2.Enable( bEnable );
+ maSheetMarginTxt1.Enable( bEnable );
+ maSheetMarginEdt.Enable( bEnable );
+ maSheetMarginTxt2.Enable( bEnable );
+ maNupOrientationTxt.Enable( bEnable );
+ maNupOrientationBox.Enable( bEnable );
+ maNupOrderTxt.Enable( bEnable );
+ maNupOrderBox.Enable( bEnable );
+ maNupOrderWin.Enable( bEnable );
+ maBorderCB.Enable( bEnable );
+}
+
+void PrintDialog::NUpTabPage::showAdvancedControls( bool i_bShow )
+{
+ maNupNumPagesTxt.Show( i_bShow );
+ maNupColEdt.Show( i_bShow );
+ maNupTimesTxt.Show( i_bShow );
+ maNupRowsEdt.Show( i_bShow );
+ maPageMarginTxt1.Show( i_bShow );
+ maPageMarginEdt.Show( i_bShow );
+ maPageMarginTxt2.Show( i_bShow );
+ maSheetMarginTxt1.Show( i_bShow );
+ maSheetMarginEdt.Show( i_bShow );
+ maSheetMarginTxt2.Show( i_bShow );
+ maNupOrientationTxt.Show( i_bShow );
+ maNupOrientationBox.Show( i_bShow );
+ maLayout.resize();
+}
+
+void PrintDialog::NUpTabPage::setupLayout()
+{
+ Size aBorder( LogicToPixel( Size( 6, 6 ), MapMode( MAP_APPFONT ) ) );
+ /* According to OOo style guide, the horizontal indentation of child
+ elements to their parent element should always be 6 map units. */
+ long nIndent = aBorder.Width();
+
+ maLayout.setParentWindow( this );
+ maLayout.setOuterBorder( aBorder.Width() );
+
+ maLayout.addWindow( &maNupLine );
+ boost::shared_ptr< vcl::RowOrColumn > xRow( new vcl::RowOrColumn( &maLayout, false ) );
+ maLayout.addChild( xRow );
+ boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( xRow.get() ) );
+ xRow->addChild( xIndent );
+
+ boost::shared_ptr< vcl::RowOrColumn > xShowNupCol( new vcl::RowOrColumn( xRow.get() ) );
+ xRow->addChild( xShowNupCol, -1 );
+ xShowNupCol->setMinimumSize( xShowNupCol->addWindow( &maNupOrderWin ), Size( 70, 70 ) );
+ boost::shared_ptr< vcl::Spacer > xSpacer( new vcl::Spacer( xShowNupCol.get() ) );
+ xShowNupCol->addChild( xSpacer );
+
+ boost::shared_ptr< vcl::LabelColumn > xMainCol( new vcl::LabelColumn( xIndent.get() ) );
+ xIndent->setChild( xMainCol );
+
+ size_t nPagesIndex = xMainCol->addRow( &maPagesBtn, &maNupPagesBox );
+ mxPagesBtnLabel = boost::dynamic_pointer_cast<vcl::LabeledElement>( xMainCol->getChild( nPagesIndex ) );
+
+ xRow.reset( new vcl::RowOrColumn( xMainCol.get(), false ) );
+ xMainCol->addRow( &maNupNumPagesTxt, xRow, nIndent );
+ xRow->addWindow( &maNupColEdt );
+ xRow->addWindow( &maNupTimesTxt );
+ xRow->addWindow( &maNupRowsEdt );
+
+ boost::shared_ptr< vcl::LabeledElement > xLab( new vcl::LabeledElement( xMainCol.get(), 2 ) );
+ xLab->setLabel( &maPageMarginEdt );
+ xLab->setElement( &maPageMarginTxt2 );
+ xMainCol->addRow( &maPageMarginTxt1, xLab, nIndent );
+
+ xLab.reset( new vcl::LabeledElement( xMainCol.get(), 2 ) );
+ xLab->setLabel( &maSheetMarginEdt );
+ xLab->setElement( &maSheetMarginTxt2 );
+ xMainCol->addRow( &maSheetMarginTxt1, xLab, nIndent );
+
+ xMainCol->addRow( &maNupOrientationTxt, &maNupOrientationBox, nIndent );
+ xMainCol->addRow( &maNupOrderTxt, &maNupOrderBox, nIndent );
+ xMainCol->setBorders( xMainCol->addWindow( &maBorderCB ), nIndent, 0, 0, 0 );
+
+ xSpacer.reset( new vcl::Spacer( xMainCol.get(), 0, Size( 10, aBorder.Width() ) ) );
+ xMainCol->addChild( xSpacer );
+
+ xRow.reset( new vcl::RowOrColumn( xMainCol.get(), false ) );
+ xMainCol->addRow( &maBrochureBtn, xRow );
+ // remember brochure row for dependencies
+ mxBrochureDep = xRow;
+
+ // initially advanced controls are not shown, rows=columns=1
+ showAdvancedControls( false );
+}
+
+void PrintDialog::NUpTabPage::Resize()
+{
+ maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetOutputSizePixel() ) );
+}
+
+void PrintDialog::NUpTabPage::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& i_rMPS )
+{
+ maSheetMarginEdt.SetValue( maSheetMarginEdt.Normalize( i_rMPS.nLeftMargin ), FUNIT_100TH_MM );
+ maPageMarginEdt.SetValue( maPageMarginEdt.Normalize( i_rMPS.nHorizontalSpacing ), FUNIT_100TH_MM );
+ maBorderCB.Check( i_rMPS.bDrawBorder );
+ maNupRowsEdt.SetValue( i_rMPS.nRows );
+ maNupColEdt.SetValue( i_rMPS.nColumns );
+}
+
+void PrintDialog::NUpTabPage::readFromSettings()
+{
+}
+
+void PrintDialog::NUpTabPage::storeToSettings()
+{
+}
+
+PrintDialog::JobTabPage::JobTabPage( Window* i_pParent, const ResId& rResId )
+ : TabPage( i_pParent, rResId )
+ , maPrinterFL( this, VclResId( SV_PRINT_PRINTERS_FL ) )
+ , maPrinters( this, VclResId( SV_PRINT_PRINTERS ) )
+ , maDetailsBtn( this, VclResId( SV_PRINT_DETAILS_BTN ) )
+ , maStatusLabel( this, VclResId( SV_PRINT_STATUS_TXT ) )
+ , maStatusTxt( this, 0 )
+ , maLocationLabel( this, VclResId( SV_PRINT_LOCATION_TXT ) )
+ , maLocationTxt( this, 0 )
+ , maCommentLabel( this, VclResId( SV_PRINT_COMMENT_TXT ) )
+ , maCommentTxt( this, 0 )
+ , maSetupButton( this, VclResId( SV_PRINT_PRT_SETUP ) )
+ , maCopies( this, VclResId( SV_PRINT_COPIES ) )
+ , maCopySpacer( this, WB_VERT )
+ , maCopyCount( this, VclResId( SV_PRINT_COPYCOUNT ) )
+ , maCopyCountField( this, VclResId( SV_PRINT_COPYCOUNT_FIELD ) )
+ , maCollateBox( this, VclResId( SV_PRINT_COLLATE ) )
+ , maCollateImage( this, VclResId( SV_PRINT_COLLATE_IMAGE ) )
+ , maCollateImg( VclResId( SV_PRINT_COLLATE_IMG ) )
+ , maCollateHCImg( VclResId( SV_PRINT_COLLATE_HC_IMG ) )
+ , maNoCollateImg( VclResId( SV_PRINT_NOCOLLATE_IMG ) )
+ , maNoCollateHCImg( VclResId( SV_PRINT_NOCOLLATE_HC_IMG ) )
+ , mnCollateUIMode( 0 )
+ , maLayout( NULL, true )
+{
+ FreeResource();
+
+ SMHID1( "JobPage" );
+ maPrinterFL.SMHID2( "JobPage", "Printer" );
+ maPrinters.SMHID2( "JobPage", "PrinterList" );
+ maDetailsBtn.SMHID2( "JobPage", "DetailsBtn" );
+ maStatusLabel.SMHID2( "JobPage", "StatusLabel" );
+ maStatusTxt.SMHID2( "JobPage", "StatusText" );
+ maLocationLabel.SMHID2( "JobPage", "LocationLabel" );
+ maLocationTxt.SMHID2( "JobPage", "LocationText" );
+ maCommentLabel.SMHID2( "JobPage", "CommentLabel" );
+ maCommentTxt.SMHID2( "JobPage", "CommentText" );
+ maSetupButton.SMHID2( "JobPage", "Properties" );
+ maCopies.SMHID2( "JobPage", "CopiesLine" );
+ maCopySpacer.SMHID2( "JobPage", "CopySpacer" );
+ maCopyCount.SMHID2( "JobPage", "CopiesText" );
+ maCopyCountField.SMHID2( "JobPage", "Copies" );
+ maCollateBox.SMHID2( "JobPage", "Collate" );
+ maCollateImage.SMHID2( "JobPage", "CollateImage" );
+
+ maCopySpacer.Show();
+ maStatusTxt.Show();
+ maCommentTxt.Show();
+ maLocationTxt.Show();
+
+ setupLayout();
+}
+
+PrintDialog::JobTabPage::~JobTabPage()
+{
+}
+
+void PrintDialog::JobTabPage::setupLayout()
+{
+ // HACK: this is not a dropdown box, but the dropdown line count
+ // sets the results of GetOptimalSize in a normal ListBox
+ maPrinters.SetDropDownLineCount( 4 );
+
+ Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) );
+
+ maLayout.setParentWindow( this );
+ maLayout.setOuterBorder( aBorder.Width() );
+
+ // add printer fixed line
+ maLayout.addWindow( &maPrinterFL );
+ // add print LB
+ maLayout.addWindow( &maPrinters, 3 );
+
+ // create a row for details button/text and properties button
+ boost::shared_ptr< vcl::RowOrColumn > xDetRow( new vcl::RowOrColumn( &maLayout, false ) );
+ maLayout.addChild( xDetRow );
+ xDetRow->addWindow( &maDetailsBtn );
+ xDetRow->addChild( new vcl::Spacer( xDetRow.get(), 2 ) );
+ xDetRow->addWindow( &maSetupButton );
+
+ // create an indent for details
+ boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( &maLayout ) );
+ maLayout.addChild( xIndent );
+ // remember details controls
+ mxDetails = xIndent;
+ // create a column for the details
+ boost::shared_ptr< vcl::LabelColumn > xLabelCol( new vcl::LabelColumn( xIndent.get(), aBorder.Height() ) );
+ xIndent->setChild( xLabelCol );
+ xLabelCol->addRow( &maStatusLabel, &maStatusTxt );
+ xLabelCol->addRow( &maLocationLabel, &maLocationTxt );
+ xLabelCol->addRow( &maCommentLabel, &maCommentTxt );
+
+ // add print range and copies columns
+ maLayout.addWindow( &maCopies );
+ boost::shared_ptr< vcl::RowOrColumn > xRangeRow( new vcl::RowOrColumn( &maLayout, false, aBorder.Width() ) );
+ maLayout.addChild( xRangeRow );
+
+ // create print range and add to range row
+ mxPrintRange.reset( new vcl::RowOrColumn( xRangeRow.get() ) );
+ xRangeRow->addChild( mxPrintRange );
+ xRangeRow->addWindow( &maCopySpacer );
+
+ boost::shared_ptr< vcl::RowOrColumn > xCopyCollateCol( new vcl::RowOrColumn( xRangeRow.get() ) );
+ xRangeRow->addChild( xCopyCollateCol );
+
+ // add copies row to copy/collate column
+ boost::shared_ptr< vcl::LabeledElement > xCopiesRow( new vcl::LabeledElement( xCopyCollateCol.get(), 2 ) );
+ xCopyCollateCol->addChild( xCopiesRow );
+ xCopiesRow->setLabel( &maCopyCount );
+ xCopiesRow->setElement( &maCopyCountField );
+ boost::shared_ptr< vcl::LabeledElement > xCollateRow( new vcl::LabeledElement( xCopyCollateCol.get(), 2 ) );
+ xCopyCollateCol->addChild( xCollateRow );
+ xCollateRow->setLabel( &maCollateBox );
+ xCollateRow->setElement( &maCollateImage );
+
+ // maDetailsBtn.SetStyle( maDetailsBtn.GetStyle() | (WB_SMALLSTYLE | WB_BEVELBUTTON) );
+ mxDetails->show( false, false );
+}
+
+void PrintDialog::JobTabPage::readFromSettings()
+{
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ rtl::OUString aValue;
+
+ #if 0
+ // do not actually make copy count persistent
+ // the assumption is that this would lead to a lot of unwanted copies
+ aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) );
+ sal_Int32 nVal = aValue.toInt32();
+ maCopyCountField.SetValue( sal_Int64(nVal > 1 ? nVal : 1) );
+ #endif
+
+ aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CollateBox" ) ) );
+ if( aValue.equalsIgnoreAsciiCaseAscii( "alwaysoff" ) )
+ {
+ mnCollateUIMode = 1;
+ maCollateBox.Check( FALSE );
+ maCollateBox.Enable( FALSE );
+ }
+ else
+ {
+ mnCollateUIMode = 0;
+ aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) );
+ maCollateBox.Check( aValue.equalsIgnoreAsciiCaseAscii( "true" ) );
+ }
+ Resize();
+}
+
+void PrintDialog::JobTabPage::storeToSettings()
+{
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ),
+ maCopyCountField.GetText() );
+ pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ),
+ rtl::OUString::createFromAscii( maCollateBox.IsChecked() ? "true" : "false" ) );
+}
+
+void PrintDialog::JobTabPage::Resize()
+{
+ maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) );
+}
+
+PrintDialog::OutputOptPage::OutputOptPage( Window* i_pParent, const ResId& i_rResId )
+ : TabPage( i_pParent, i_rResId )
+ , maOptionsLine( this, VclResId( SV_PRINT_OPT_PRINT_FL ) )
+ , maToFileBox( this, VclResId( SV_PRINT_OPT_TOFILE ) )
+ , maCollateSingleJobsBox( this, VclResId( SV_PRINT_OPT_SINGLEJOBS ) )
+ , maReverseOrderBox( this, VclResId( SV_PRINT_OPT_REVERSE ) )
+{
+ FreeResource();
+ SMHID1( "OptPage" );
+ maOptionsLine.SMHID2( "OptPage", "Options" );
+ maToFileBox.SMHID2( "OptPage", "ToFile" );
+ maCollateSingleJobsBox.SMHID2( "OptPage", "SingleJobs" );
+ maReverseOrderBox.SMHID2( "OptPage", "Reverse" );
+
+ setupLayout();
+}
+
+PrintDialog::OutputOptPage::~OutputOptPage()
+{
+}
+
+void PrintDialog::OutputOptPage::setupLayout()
+{
+ Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) );
+
+ maLayout.setParentWindow( this );
+ maLayout.setOuterBorder( aBorder.Width() );
+
+ maLayout.addWindow( &maOptionsLine );
+ boost::shared_ptr<vcl::Indenter> xIndent( new vcl::Indenter( &maLayout, aBorder.Width() ) );
+ maLayout.addChild( xIndent );
+ boost::shared_ptr<vcl::RowOrColumn> xCol( new vcl::RowOrColumn( xIndent.get(), aBorder.Height() ) );
+ xIndent->setChild( xCol );
+ mxOptGroup = xCol;
+ xCol->addWindow( &maToFileBox );
+ xCol->addWindow( &maCollateSingleJobsBox );
+ xCol->addWindow( &maReverseOrderBox );
+}
+
+void PrintDialog::OutputOptPage::readFromSettings()
+{
+ #if 0
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ rtl::OUString aValue;
+
+ aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ToFile" ) ) );
+ maToFileBox.Check( aValue.equalsIgnoreAsciiCaseAscii( "true" ) );
+ #endif
+}
+
+void PrintDialog::OutputOptPage::storeToSettings()
+{
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ToFile" ) ),
+ rtl::OUString::createFromAscii( maToFileBox.IsChecked() ? "true" : "false" ) );
+}
+
+void PrintDialog::OutputOptPage::Resize()
+{
+ maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) );
+}
+
+
+PrintDialog::PrintDialog( Window* i_pParent, const boost::shared_ptr<PrinterController>& i_rController )
+ : ModalDialog( i_pParent, VclResId( SV_DLG_PRINT ) )
+ , maOKButton( this, VclResId( SV_PRINT_OK ) )
+ , maCancelButton( this, VclResId( SV_PRINT_CANCEL ) )
+ , maHelpButton( this, VclResId( SV_PRINT_HELP ) )
+ , maPreviewWindow( this, VclResId( SV_PRINT_PAGE_PREVIEW ) )
+ , maPageEdit( this, VclResId( SV_PRINT_PAGE_EDIT ) )
+ , maNumPagesText( this, VclResId( SV_PRINT_PAGE_TXT ) )
+ , maBackwardBtn( this, VclResId( SV_PRINT_PAGE_BACKWARD ) )
+ , maForwardBtn( this, VclResId( SV_PRINT_PAGE_FORWARD ) )
+ , maTabCtrl( this, VclResId( SV_PRINT_TABCTRL ) )
+ , maNUpPage( &maTabCtrl, VclResId( SV_PRINT_TAB_NUP ) )
+ , maJobPage( &maTabCtrl, VclResId( SV_PRINT_TAB_JOB ) )
+ , maOptionsPage( &maTabCtrl, VclResId( SV_PRINT_TAB_OPT ) )
+ , maButtonLine( this, VclResId( SV_PRINT_BUTTONLINE ) )
+ , maPController( i_rController )
+ , maNoPageStr( String( VclResId( SV_PRINT_NOPAGES ) ) )
+ , mnCurPage( 0 )
+ , mnCachedPages( 0 )
+ , maPrintToFileText( String( VclResId( SV_PRINT_TOFILE_TXT ) ) )
+ , maDefPrtText( String( VclResId( SV_PRINT_DEFPRT_TXT ) ) )
+ , mbShowLayoutPage( sal_True )
+{
+ FreeResource();
+
+ // save printbutton text, gets exchanged occasionally with print to file
+ maPrintText = maOKButton.GetText();
+
+ // setup preview controls
+ maForwardBtn.SetStyle( maForwardBtn.GetStyle() | WB_BEVELBUTTON );
+ maBackwardBtn.SetStyle( maBackwardBtn.GetStyle() | WB_BEVELBUTTON );
+
+ // insert the job (general) tab page first
+ maTabCtrl.InsertPage( SV_PRINT_TAB_JOB, maJobPage.GetText() );
+ maTabCtrl.SetTabPage( SV_PRINT_TAB_JOB, &maJobPage );
+
+ // set symbols on forward and backward button
+ maBackwardBtn.SetSymbol( SYMBOL_PREV );
+ maForwardBtn.SetSymbol( SYMBOL_NEXT );
+ maBackwardBtn.ImplSetSmallSymbol( TRUE );
+ maForwardBtn.ImplSetSmallSymbol( TRUE );
+
+ maPageStr = maNumPagesText.GetText();
+
+ // init reverse print
+ maOptionsPage.maReverseOrderBox.Check( maPController->getReversePrint() );
+
+ // get the first page
+ preparePreview( true, true );
+
+ // fill printer listbox
+ const std::vector< rtl::OUString >& rQueues( Printer::GetPrinterQueues() );
+ for( std::vector< rtl::OUString >::const_iterator it = rQueues.begin();
+ it != rQueues.end(); ++it )
+ {
+ maJobPage.maPrinters.InsertEntry( *it );
+ }
+ // select current printer
+ if( maJobPage.maPrinters.GetEntryPos( maPController->getPrinter()->GetName() ) != LISTBOX_ENTRY_NOTFOUND )
+ {
+ maJobPage.maPrinters.SelectEntry( maPController->getPrinter()->GetName() );
+ }
+ else
+ {
+ // fall back to last printer
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ String aValue( pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinter" ) ) ) );
+ if( maJobPage.maPrinters.GetEntryPos( aValue ) != LISTBOX_ENTRY_NOTFOUND )
+ {
+ maJobPage.maPrinters.SelectEntry( aValue );
+ maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( aValue ) ) );
+ }
+ else
+ {
+ // fall back to default printer
+ maJobPage.maPrinters.SelectEntry( Printer::GetDefaultPrinterName() );
+ maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( Printer::GetDefaultPrinterName() ) ) );
+ }
+ }
+ // update the text fields for the printer
+ updatePrinterText();
+
+ // set a select handler
+ maJobPage.maPrinters.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) );
+
+ // setup sizes for N-Up
+ Size aNupSize( maPController->getPrinter()->PixelToLogic(
+ maPController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) );
+ if( maPController->getPrinter()->GetOrientation() == ORIENTATION_LANDSCAPE )
+ {
+ maNupLandscapeSize = aNupSize;
+ maNupPortraitSize = Size( aNupSize.Height(), aNupSize.Width() );
+ }
+ else
+ {
+ maNupPortraitSize = aNupSize;
+ maNupLandscapeSize = Size( aNupSize.Height(), aNupSize.Width() );
+ }
+ maNUpPage.initFromMultiPageSetup( maPController->getMultipage() );
+
+
+ // setup click handler on the various buttons
+ maOKButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) );
+ #if OSL_DEBUG_LEVEL > 1
+ maCancelButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) );
+ #endif
+ maHelpButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maForwardBtn.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maBackwardBtn.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maJobPage.maCollateBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maJobPage.maSetupButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maJobPage.maDetailsBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maNUpPage.maBorderCB.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maOptionsPage.maToFileBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maOptionsPage.maReverseOrderBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maOptionsPage.maCollateSingleJobsBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
+ maNUpPage.maPagesBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
+
+ // setup modify hdl
+ maPageEdit.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) );
+ maJobPage.maCopyCountField.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) );
+ maNUpPage.maNupRowsEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) );
+ maNUpPage.maNupColEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) );
+ maNUpPage.maPageMarginEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) );
+ maNUpPage.maSheetMarginEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) );
+
+ // setup select hdl
+ maNUpPage.maNupPagesBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) );
+ maNUpPage.maNupOrientationBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) );
+ maNUpPage.maNupOrderBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) );
+
+ // setup the layout
+ setupLayout();
+
+ // setup optional UI options set by application
+ setupOptionalUI();
+
+ // set change handler for UI options
+ maPController->setOptionChangeHdl( LINK( this, PrintDialog, UIOptionsChanged ) );
+
+ // set min size pixel to current size
+ Size aOutSize( GetOutputSizePixel() );
+ SetMinOutputSizePixel( aOutSize );
+
+ // if there is space enough, enlarge the preview so it gets roughly as
+ // high as the tab control
+ if( aOutSize.Width() < 768 )
+ {
+ Size aJobPageSize( getJobPageSize() );
+ Size aTabSize( maTabCtrl.GetSizePixel() );
+ if( aJobPageSize.Width() < 1 )
+ aJobPageSize.Width() = aTabSize.Width();
+ if( aJobPageSize.Height() < 1 )
+ aJobPageSize.Height() = aTabSize.Height();
+ long nOptPreviewWidth = aTabSize.Height() * aJobPageSize.Width() / aJobPageSize.Height();
+ // add space for borders
+ nOptPreviewWidth += 15;
+ if( aOutSize.Width() - aTabSize.Width() < nOptPreviewWidth )
+ {
+ aOutSize.Width() = aTabSize.Width() + nOptPreviewWidth;
+ if( aOutSize.Width() > 768 ) // don't enlarge the dialog too much
+ aOutSize.Width() = 768;
+ SetOutputSizePixel( aOutSize );
+ }
+ }
+
+ // set HelpIDs
+ SMHID1( "Dialog" );
+ maOKButton.SMHID1( "OK" );
+ maCancelButton.SMHID1( "Cancel" );
+ maHelpButton.SMHID1( "Help" );
+ maPreviewWindow.SMHID1( "Preview" );
+ maNumPagesText.SMHID1( "NumPagesText" );
+ maPageEdit.SMHID1( "PageEdit" );
+ maForwardBtn.SMHID1( "ForwardBtn" );
+ maBackwardBtn.SMHID1( "BackwardBtn" );
+ maTabCtrl.SMHID1( "TabPages" );
+
+ // append further tab pages
+ if( mbShowLayoutPage )
+ {
+ maTabCtrl.InsertPage( SV_PRINT_TAB_NUP, maNUpPage.GetText() );
+ maTabCtrl.SetTabPage( SV_PRINT_TAB_NUP, &maNUpPage );
+ }
+ maTabCtrl.InsertPage( SV_PRINT_TAB_OPT, maOptionsPage.GetText() );
+ maTabCtrl.SetTabPage( SV_PRINT_TAB_OPT, &maOptionsPage );
+
+ // restore settings from last run
+ readFromSettings();
+
+ // setup dependencies
+ checkControlDependencies();
+
+}
+
+PrintDialog::~PrintDialog()
+{
+ while( ! maControls.empty() )
+ {
+ delete maControls.front();
+ maControls.pop_front();
+ }
+}
+
+void PrintDialog::setupLayout()
+{
+ Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) );
+
+ maLayout.setParentWindow( this );
+
+ boost::shared_ptr< vcl::RowOrColumn > xPreviewAndTab( new vcl::RowOrColumn( &maLayout, false ) );
+ size_t nIndex = maLayout.addChild( xPreviewAndTab, 5 );
+ maLayout.setBorders( nIndex, aBorder.Width(), aBorder.Width(), aBorder.Width(), 0 );
+
+ // setup column for preview and sub controls
+ boost::shared_ptr< vcl::RowOrColumn > xPreview( new vcl::RowOrColumn( xPreviewAndTab.get() ) );
+ xPreviewAndTab->addChild( xPreview, 5 );
+ xPreview->addWindow( &maPreviewWindow, 5 );
+ // get a row for the preview controls
+ mxPreviewCtrls.reset( new vcl::RowOrColumn( xPreview.get(), false ) );
+ nIndex = xPreview->addChild( mxPreviewCtrls );
+ boost::shared_ptr< vcl::Spacer > xSpacer( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) );
+ mxPreviewCtrls->addChild( xSpacer );
+ mxPreviewCtrls->addWindow( &maPageEdit );
+ mxPreviewCtrls->addWindow( &maNumPagesText );
+ xSpacer.reset( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) );
+ mxPreviewCtrls->addChild( xSpacer );
+ mxPreviewCtrls->addWindow( &maBackwardBtn );
+ mxPreviewCtrls->addWindow( &maForwardBtn );
+ xSpacer.reset( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) );
+ mxPreviewCtrls->addChild( xSpacer );
+
+ // continue with the tab ctrl
+ xPreviewAndTab->addWindow( &maTabCtrl );
+
+ // add the button line
+ maLayout.addWindow( &maButtonLine );
+
+ // add the row for the buttons
+ boost::shared_ptr< vcl::RowOrColumn > xButtons( new vcl::RowOrColumn( &maLayout, false ) );
+ nIndex = maLayout.addChild( xButtons );
+ maLayout.setBorders( nIndex, aBorder.Width(), 0, aBorder.Width(), aBorder.Width() );
+
+ Size aMinSize( maCancelButton.GetSizePixel() );
+ // insert help button
+ xButtons->setMinimumSize( xButtons->addWindow( &maHelpButton ), aMinSize );
+ // insert a spacer, cancel and OK buttons are right aligned
+ xSpacer.reset( new vcl::Spacer( xButtons.get(), 2 ) );
+ xButtons->addChild( xSpacer );
+ xButtons->setMinimumSize( xButtons->addWindow( &maOKButton ), aMinSize );
+ xButtons->setMinimumSize( xButtons->addWindow( &maCancelButton ), aMinSize );
+}
+
+void PrintDialog::readFromSettings()
+{
+ maJobPage.readFromSettings();
+ maNUpPage.readFromSettings();
+ maOptionsPage.readFromSettings();
+
+ // read last selected tab page; if it exists, actiavte it
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ rtl::OUString aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPage" ) ) );
+ USHORT nCount = maTabCtrl.GetPageCount();
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ USHORT nPageId = maTabCtrl.GetPageId( i );
+ if( aValue.equals( maTabCtrl.GetPageText( nPageId ) ) )
+ {
+ maTabCtrl.SelectTabPage( nPageId );
+ break;
+ }
+ }
+ maOKButton.SetText( maOptionsPage.maToFileBox.IsChecked() ? maPrintToFileText : maPrintText );
+}
+
+void PrintDialog::storeToSettings()
+{
+ maJobPage.storeToSettings();
+ maNUpPage.storeToSettings();
+ maOptionsPage.storeToSettings();
+
+ // store last selected printer
+ SettingsConfigItem* pItem = SettingsConfigItem::get();
+ pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinter" ) ),
+ maJobPage.maPrinters.GetSelectEntry() );
+
+ pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPage" ) ),
+ maTabCtrl.GetPageText( maTabCtrl.GetCurPageId() ) );
+ pItem->Commit();
+}
+
+bool PrintDialog::isPrintToFile()
+{
+ return maOptionsPage.maToFileBox.IsChecked();
+}
+
+int PrintDialog::getCopyCount()
+{
+ return static_cast<int>(maJobPage.maCopyCountField.GetValue());
+}
+
+bool PrintDialog::isCollate()
+{
+ return maJobPage.maCopyCountField.GetValue() > 1 ? maJobPage.maCollateBox.IsChecked() : FALSE;
+}
+
+bool PrintDialog::isSingleJobs()
+{
+ return maOptionsPage.maCollateSingleJobsBox.IsChecked();
+}
+
+static void setSmartId( Window* i_pWindow, const char* i_pType, sal_Int32 i_nId = -1, const rtl::OUString& i_rPropName = rtl::OUString() )
+{
+ rtl::OUStringBuffer aBuf( 256 );
+ aBuf.appendAscii( HELPID_PREFIX );
+ if( i_rPropName.getLength() )
+ {
+ aBuf.append( sal_Unicode( ':' ) );
+ aBuf.append( i_rPropName );
+ }
+ if( i_pType )
+ {
+ aBuf.append( sal_Unicode( ':' ) );
+ aBuf.appendAscii( i_pType );
+ }
+ if( i_nId >= 0 )
+ {
+ aBuf.append( sal_Unicode( ':' ) );
+ aBuf.append( i_nId );
+ }
+ i_pWindow->SetSmartHelpId( SmartId( aBuf.makeStringAndClear(), HID_PRINTDLG ) );
+}
+
+static void setHelpText( Window* /*i_pWindow*/, const Sequence< rtl::OUString >& /*i_rHelpTexts*/, sal_Int32 /*i_nIndex*/ )
+{
+ // without a help text set and the correct smartID,
+ // help texts will be retrieved from the online help system
+
+ // passed help texts for optional UI is used only for native dialogs which currently
+ // cannot access the same (rather implicit) mechanism
+ #if 0
+ if( i_nIndex >= 0 && i_nIndex < i_rHelpTexts.getLength() )
+ i_pWindow->SetHelpText( i_rHelpTexts.getConstArray()[i_nIndex] );
+ #endif
+}
+
+void updateMaxSize( const Size& i_rCheckSize, Size& o_rMaxSize )
+{
+ if( i_rCheckSize.Width() > o_rMaxSize.Width() )
+ o_rMaxSize.Width() = i_rCheckSize.Width();
+ if( i_rCheckSize.Height() > o_rMaxSize.Height() )
+ o_rMaxSize.Height() = i_rCheckSize.Height();
+}
+
+void PrintDialog::setupOptionalUI()
+{
+ Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) );
+
+ std::vector<vcl::RowOrColumn*> aDynamicColumns;
+ vcl::RowOrColumn* pCurColumn = 0;
+
+ Window* pCurParent = 0, *pDynamicPageParent = 0;
+ USHORT nOptPageId = 9, nCurSubGroup = 0;
+ bool bOnStaticPage = false;
+ bool bSubgroupOnStaticPage = false;
+
+ std::multimap< rtl::OUString, vcl::RowOrColumn* > aPropertyToDependencyRowMap;
+
+ const Sequence< PropertyValue >& rOptions( maPController->getUIOptions() );
+ for( int i = 0; i < rOptions.getLength(); i++ )
+ {
+ Sequence< beans::PropertyValue > aOptProp;
+ rOptions[i].Value >>= aOptProp;
+
+ // extract ui element
+ bool bEnabled = true;
+ rtl::OUString aCtrlType;
+ rtl::OUString aText;
+ rtl::OUString aPropertyName;
+ Sequence< rtl::OUString > aChoices;
+ Sequence< rtl::OUString > aHelpTexts;
+ sal_Int64 nMinValue = 0, nMaxValue = 0;
+ sal_Int32 nCurHelpText = 0;
+ rtl::OUString aGroupingHint;
+ rtl::OUString aDependsOnName;
+ sal_Int32 nDependsOnValue = 0;
+ sal_Bool bUseDependencyRow = sal_False;
+
+ for( int n = 0; n < aOptProp.getLength(); n++ )
+ {
+ const beans::PropertyValue& rEntry( aOptProp[ n ] );
+ if( rEntry.Name.equalsAscii( "Text" ) )
+ {
+ rEntry.Value >>= aText;
+ }
+ else if( rEntry.Name.equalsAscii( "ControlType" ) )
+ {
+ rEntry.Value >>= aCtrlType;
+ }
+ else if( rEntry.Name.equalsAscii( "Choices" ) )
+ {
+ rEntry.Value >>= aChoices;
+ }
+ else if( rEntry.Name.equalsAscii( "Property" ) )
+ {
+ PropertyValue aVal;
+ rEntry.Value >>= aVal;
+ aPropertyName = aVal.Name;
+ }
+ else if( rEntry.Name.equalsAscii( "Enabled" ) )
+ {
+ sal_Bool bValue = sal_True;
+ rEntry.Value >>= bValue;
+ bEnabled = bValue;
+ }
+ else if( rEntry.Name.equalsAscii( "GroupingHint" ) )
+ {
+ rEntry.Value >>= aGroupingHint;
+ }
+ else if( rEntry.Name.equalsAscii( "DependsOnName" ) )
+ {
+ rEntry.Value >>= aDependsOnName;
+ }
+ else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) )
+ {
+ rEntry.Value >>= nDependsOnValue;
+ }
+ else if( rEntry.Name.equalsAscii( "AttachToDependency" ) )
+ {
+ rEntry.Value >>= bUseDependencyRow;
+ }
+ else if( rEntry.Name.equalsAscii( "MinValue" ) )
+ {
+ rEntry.Value >>= nMinValue;
+ }
+ else if( rEntry.Name.equalsAscii( "MaxValue" ) )
+ {
+ rEntry.Value >>= nMaxValue;
+ }
+ else if( rEntry.Name.equalsAscii( "HelpText" ) )
+ {
+ if( ! (rEntry.Value >>= aHelpTexts) )
+ {
+ rtl::OUString aHelpText;
+ if( (rEntry.Value >>= aHelpText) )
+ {
+ aHelpTexts.realloc( 1 );
+ *aHelpTexts.getArray() = aHelpText;
+ }
+ }
+ }
+ else if( rEntry.Name.equalsAscii( "HintNoLayoutPage" ) )
+ {
+ sal_Bool bNoLayoutPage = sal_False;
+ rEntry.Value >>= bNoLayoutPage;
+ mbShowLayoutPage = ! bNoLayoutPage;
+ }
+ }
+
+ // bUseDependencyRow should only be true if a dependency exists
+ bUseDependencyRow = bUseDependencyRow && (aDependsOnName.getLength() != 0);
+
+ // is it necessary to switch between static and dynamic pages ?
+ bool bSwitchPage = false;
+ if( aGroupingHint.getLength() )
+ bSwitchPage = true;
+ else if( aCtrlType.equalsAscii( "Subgroup" ) || (bOnStaticPage && ! bSubgroupOnStaticPage ) )
+ bSwitchPage = true;
+ if( bSwitchPage )
+ {
+ // restore to dynamic
+ pCurParent = pDynamicPageParent;
+ pCurColumn = aDynamicColumns.empty() ? NULL : aDynamicColumns.back();
+ bOnStaticPage = false;
+ bSubgroupOnStaticPage = false;
+
+ if( aGroupingHint.equalsAscii( "PrintRange" ) )
+ {
+ pCurColumn = maJobPage.mxPrintRange.get();
+ pCurParent = &maJobPage; // set job page as current parent
+ bOnStaticPage = true;
+ }
+ else if( aGroupingHint.equalsAscii( "OptionsPage" ) )
+ {
+ pCurColumn = &maOptionsPage.maLayout;
+ pCurParent = &maOptionsPage; // set options page as current parent
+ bOnStaticPage = true;
+ }
+ else if( aGroupingHint.equalsAscii( "OptionsPageOptGroup" ) )
+ {
+ pCurColumn = maOptionsPage.mxOptGroup.get();
+ pCurParent = &maOptionsPage; // set options page as current parent
+ bOnStaticPage = true;
+ }
+ else if( aGroupingHint.equalsAscii( "LayoutPage" ) )
+ {
+ pCurColumn = &maNUpPage.maLayout;
+ pCurParent = &maNUpPage; // set layout page as current parent
+ bOnStaticPage = true;
+ }
+ else if( aGroupingHint.getLength() )
+ {
+ pCurColumn = &maJobPage.maLayout;
+ pCurParent = &maJobPage; // set job page as current parent
+ bOnStaticPage = true;
+ }
+ }
+
+ if( aCtrlType.equalsAscii( "Group" ) ||
+ ( ! pCurParent && ! (bOnStaticPage || aGroupingHint.getLength() ) ) )
+ {
+ // add new tab page
+ TabPage* pNewGroup = new TabPage( &maTabCtrl );
+ maControls.push_front( pNewGroup );
+ pDynamicPageParent = pCurParent = pNewGroup;
+ pNewGroup->SetText( aText );
+ maTabCtrl.InsertPage( ++nOptPageId, aText );
+ maTabCtrl.SetTabPage( nOptPageId, pNewGroup );
+
+ // set help id
+ setSmartId( pNewGroup, "TabPage", nOptPageId );
+ // set help text
+ setHelpText( pNewGroup, aHelpTexts, 0 );
+
+ // reset subgroup counter
+ nCurSubGroup = 0;
+
+ aDynamicColumns.push_back( new vcl::RowOrColumn( NULL, true, aBorder.Width() ) );
+ pCurColumn = aDynamicColumns.back();
+ pCurColumn->setParentWindow( pNewGroup );
+ pCurColumn->setOuterBorder( aBorder.Width() );
+ bSubgroupOnStaticPage = false;
+ bOnStaticPage = false;
+ }
+ else if( aCtrlType.equalsAscii( "Subgroup" ) && (pCurParent || aGroupingHint.getLength() ) )
+ {
+ bSubgroupOnStaticPage = (aGroupingHint.getLength() != 0);
+ // create group FixedLine
+ if( ! aGroupingHint.equalsAscii( "PrintRange" ) ||
+ ! pCurColumn->countElements() == 0
+ )
+ {
+ Window* pNewSub = NULL;
+ if( aGroupingHint.equalsAscii( "PrintRange" ) )
+ pNewSub = new FixedText( pCurParent, WB_VCENTER );
+ else
+ pNewSub = new FixedLine( pCurParent );
+ maControls.push_front( pNewSub );
+ pNewSub->SetText( aText );
+ pNewSub->Show();
+
+ // set help id
+ setSmartId( pNewSub, "FixedLine", sal_Int32( nCurSubGroup++ ) );
+ // set help text
+ setHelpText( pNewSub, aHelpTexts, 0 );
+ // add group to current column
+ pCurColumn->addWindow( pNewSub );
+ }
+
+ // add an indent to the current column
+ vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn, aBorder.Width() );
+ pCurColumn->addChild( pIndent );
+ // and create a column inside the indent
+ pCurColumn = new vcl::RowOrColumn( pIndent );
+ pIndent->setChild( pCurColumn );
+ }
+ // EVIL
+ else if( aCtrlType.equalsAscii( "Bool" ) &&
+ aGroupingHint.equalsAscii( "LayoutPage" ) &&
+ aPropertyName.equalsAscii( "PrintProspect" )
+ )
+ {
+ maNUpPage.maBrochureBtn.SetText( aText );
+ maNUpPage.maBrochureBtn.Show();
+ setHelpText( &maNUpPage.maBrochureBtn, aHelpTexts, 0 );
+
+ sal_Bool bVal = sal_False;
+ PropertyValue* pVal = maPController->getValue( aPropertyName );
+ if( pVal )
+ pVal->Value >>= bVal;
+ maNUpPage.maBrochureBtn.Check( bVal );
+ maNUpPage.maBrochureBtn.Enable( maPController->isUIOptionEnabled( aPropertyName ) && pVal != NULL );
+ maNUpPage.maBrochureBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
+
+ maPropertyToWindowMap[ aPropertyName ].push_back( &maNUpPage.maBrochureBtn );
+ maControlToPropertyMap[&maNUpPage.maBrochureBtn] = aPropertyName;
+
+ aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, maNUpPage.mxBrochureDep.get() ) );
+ }
+ else
+ {
+ vcl::RowOrColumn* pSaveCurColumn = pCurColumn;
+
+ if( bUseDependencyRow )
+ {
+ // find the correct dependency row (if any)
+ std::pair< std::multimap< rtl::OUString, vcl::RowOrColumn* >::iterator,
+ std::multimap< rtl::OUString, vcl::RowOrColumn* >::iterator > aDepRange;
+ aDepRange = aPropertyToDependencyRowMap.equal_range( aDependsOnName );
+ if( aDepRange.first != aDepRange.second )
+ {
+ while( nDependsOnValue && aDepRange.first != aDepRange.second )
+ {
+ nDependsOnValue--;
+ ++aDepRange.first;
+ }
+ if( aDepRange.first != aPropertyToDependencyRowMap.end() )
+ {
+ pCurColumn = aDepRange.first->second;
+ maReverseDependencySet.insert( aPropertyName );
+ }
+ }
+ }
+ if( aCtrlType.equalsAscii( "Bool" ) && pCurParent )
+ {
+ // add a check box
+ CheckBox* pNewBox = new CheckBox( pCurParent );
+ maControls.push_front( pNewBox );
+ pNewBox->SetText( aText );
+ pNewBox->Show();
+
+ sal_Bool bVal = sal_False;
+ PropertyValue* pVal = maPController->getValue( aPropertyName );
+ if( pVal )
+ pVal->Value >>= bVal;
+ pNewBox->Check( bVal );
+ pNewBox->SetToggleHdl( LINK( this, PrintDialog, UIOption_CheckHdl ) );
+
+ maPropertyToWindowMap[ aPropertyName ].push_back( pNewBox );
+ maControlToPropertyMap[pNewBox] = aPropertyName;
+
+ // set help id
+ setSmartId( pNewBox, "CheckBox", -1, aPropertyName );
+ // set help text
+ setHelpText( pNewBox, aHelpTexts, 0 );
+
+ vcl::RowOrColumn* pDependencyRow = new vcl::RowOrColumn( pCurColumn, false );
+ pCurColumn->addChild( pDependencyRow );
+ aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pDependencyRow ) );
+
+ // add checkbox to current column
+ pDependencyRow->addWindow( pNewBox );
+ }
+ else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent )
+ {
+ vcl::RowOrColumn* pRadioColumn = pCurColumn;
+ if( aText.getLength() )
+ {
+ // add a FixedText:
+ FixedText* pHeading = new FixedText( pCurParent );
+ maControls.push_front( pHeading );
+ pHeading->SetText( aText );
+ pHeading->Show();
+
+ // set help id
+ setSmartId( pHeading, "FixedText", -1, aPropertyName );
+ // set help text
+ setHelpText( pHeading, aHelpTexts, nCurHelpText++ );
+ // add fixed text to current column
+ pCurColumn->addWindow( pHeading );
+ // add an indent to the current column
+ vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn, 15 );
+ pCurColumn->addChild( pIndent );
+ // and create a column inside the indent
+ pRadioColumn = new vcl::RowOrColumn( pIndent );
+ pIndent->setChild( pRadioColumn );
+ }
+ // iterate options
+ sal_Int32 nSelectVal = 0;
+ PropertyValue* pVal = maPController->getValue( aPropertyName );
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= nSelectVal;
+ for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
+ {
+ boost::shared_ptr<vcl::LabeledElement> pLabel( new vcl::LabeledElement( pRadioColumn, 1 ) );
+ pRadioColumn->addChild( pLabel );
+ boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pLabel.get(), false ) );
+ pLabel->setElement( pDependencyRow );
+ aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pDependencyRow.get() ) );
+
+ RadioButton* pBtn = new RadioButton( pCurParent, m == 0 ? WB_GROUP : 0 );
+ maControls.push_front( pBtn );
+ pBtn->SetText( aChoices[m] );
+ pBtn->Check( m == nSelectVal );
+ pBtn->SetToggleHdl( LINK( this, PrintDialog, UIOption_RadioHdl ) );
+ pBtn->Show();
+ maPropertyToWindowMap[ aPropertyName ].push_back( pBtn );
+ maControlToPropertyMap[pBtn] = aPropertyName;
+ maControlToNumValMap[pBtn] = m;
+
+ // set help id
+ setSmartId( pBtn, "RadioButton", m, aPropertyName );
+ // set help text
+ setHelpText( pBtn, aHelpTexts, nCurHelpText++ );
+ // add the radio button to the column
+ pLabel->setLabel( pBtn );
+ }
+ }
+ else if( ( aCtrlType.equalsAscii( "List" ) ||
+ aCtrlType.equalsAscii( "Range" ) ||
+ aCtrlType.equalsAscii( "Edit" )
+ ) && pCurParent )
+ {
+ // create a row in the current column
+ vcl::RowOrColumn* pFieldColumn = new vcl::RowOrColumn( pCurColumn, false );
+ pCurColumn->addChild( pFieldColumn );
+ aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pFieldColumn ) );
+
+ vcl::LabeledElement* pLabel = NULL;
+ if( aText.getLength() )
+ {
+ // add a FixedText:
+ FixedText* pHeading = new FixedText( pCurParent, WB_VCENTER );
+ maControls.push_front( pHeading );
+ pHeading->SetText( aText );
+ pHeading->Show();
+
+ // set help id
+ setSmartId( pHeading, "FixedText", -1, aPropertyName );
+
+ // add to row
+ pLabel = new vcl::LabeledElement( pFieldColumn, 2 );
+ pFieldColumn->addChild( pLabel );
+ pLabel->setLabel( pHeading );
+ }
+
+ if( aCtrlType.equalsAscii( "List" ) )
+ {
+ ListBox* pList = new ListBox( pCurParent, WB_DROPDOWN | WB_BORDER );
+ maControls.push_front( pList );
+
+ // iterate options
+ for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
+ {
+ pList->InsertEntry( aChoices[m] );
+ }
+ sal_Int32 nSelectVal = 0;
+ PropertyValue* pVal = maPController->getValue( aPropertyName );
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= nSelectVal;
+ pList->SelectEntryPos( static_cast<USHORT>(nSelectVal) );
+ pList->SetSelectHdl( LINK( this, PrintDialog, UIOption_SelectHdl ) );
+ pList->SetDropDownLineCount( static_cast<USHORT>(aChoices.getLength()) );
+ pList->Show();
+
+ // set help id
+ setSmartId( pList, "ListBox", -1, aPropertyName );
+ // set help text
+ setHelpText( pList, aHelpTexts, 0 );
+
+ maPropertyToWindowMap[ aPropertyName ].push_back( pList );
+ maControlToPropertyMap[pList] = aPropertyName;
+
+ // finish the pair
+ if( pLabel )
+ pLabel->setElement( pList );
+ else
+ pFieldColumn->addWindow( pList );
+ }
+ else if( aCtrlType.equalsAscii( "Range" ) )
+ {
+ NumericField* pField = new NumericField( pCurParent, WB_BORDER | WB_SPIN );
+ maControls.push_front( pField );
+
+ // set min/max and current value
+ if( nMinValue != nMaxValue )
+ {
+ pField->SetMin( nMinValue );
+ pField->SetMax( nMaxValue );
+ }
+ sal_Int64 nCurVal = 0;
+ PropertyValue* pVal = maPController->getValue( aPropertyName );
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= nCurVal;
+ pField->SetValue( nCurVal );
+ pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) );
+ pField->Show();
+
+ // set help id
+ setSmartId( pField, "NumericField", -1, aPropertyName );
+ // set help text
+ setHelpText( pField, aHelpTexts, 0 );
+
+ maPropertyToWindowMap[ aPropertyName ].push_back( pField );
+ maControlToPropertyMap[pField] = aPropertyName;
+
+ // add to row
+ if( pLabel )
+ pLabel->setElement( pField );
+ else
+ pFieldColumn->addWindow( pField );
+ }
+ else if( aCtrlType.equalsAscii( "Edit" ) )
+ {
+ Edit* pField = new Edit( pCurParent, WB_BORDER );
+ maControls.push_front( pField );
+
+ rtl::OUString aCurVal;
+ PropertyValue* pVal = maPController->getValue( aPropertyName );
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= aCurVal;
+ pField->SetText( aCurVal );
+ pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) );
+ pField->Show();
+
+ // set help id
+ setSmartId( pField, "Edit", -1, aPropertyName );
+ // set help text
+ setHelpText( pField, aHelpTexts, 0 );
+
+ maPropertyToWindowMap[ aPropertyName ].push_back( pField );
+ maControlToPropertyMap[pField] = aPropertyName;
+
+ // add to row
+ if( pLabel )
+ pLabel->setElement( pField );
+ else
+ pFieldColumn->addWindow( pField, 2 );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "Unsupported UI option" );
+ }
+
+ pCurColumn = pSaveCurColumn;
+ }
+ }
+
+ // #i106506# if no brochure button, then the singular Pages radio button
+ // makes no sense, so replace it by a FixedText label
+ if( ! maNUpPage.maBrochureBtn.IsVisible() )
+ {
+ if( maNUpPage.mxPagesBtnLabel.get() )
+ {
+ maNUpPage.maPagesBoxTitleTxt.SetText( maNUpPage.maPagesBtn.GetText() );
+ maNUpPage.maPagesBoxTitleTxt.Show( TRUE );
+ maNUpPage.mxPagesBtnLabel->setLabel( &maNUpPage.maPagesBoxTitleTxt );
+ maNUpPage.maPagesBtn.Show( FALSE );
+ }
+ }
+
+ // update enable states
+ checkOptionalControlDependencies();
+
+ // print range empty (currently math only) -> hide print range and spacer line
+ if( maJobPage.mxPrintRange->countElements() == 0 )
+ {
+ maJobPage.mxPrintRange->show( false, false );
+ maJobPage.maCopySpacer.Show( FALSE );
+ }
+
+#ifdef WNT
+ // FIXME: the GetNativeControlRegion call on Windows has some issues
+ // (which skew the results of GetOptimalSize())
+ // however fixing this thoroughly needs to take interaction with paint into
+ // acoount, making the right fix less simple. Fix this the right way
+ // at some point. For now simply add some space at the lowest element
+ size_t nIndex = maJobPage.maLayout.countElements();
+ if( nIndex > 0 ) // sanity check
+ maJobPage.maLayout.setBorders( nIndex-1, 0, 0, 0, aBorder.Width() );
+#endif
+
+ // create auto mnemomnics now so they can be calculated in layout
+ ImplWindowAutoMnemonic( &maJobPage );
+ ImplWindowAutoMnemonic( &maNUpPage );
+ ImplWindowAutoMnemonic( &maOptionsPage );
+ ImplWindowAutoMnemonic( this );
+
+ // calculate job page
+ Size aMaxSize = maJobPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED );
+ // and layout page
+ updateMaxSize( maNUpPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize );
+ // and options page
+ updateMaxSize( maOptionsPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize );
+
+ for( std::vector< vcl::RowOrColumn* >::iterator it = aDynamicColumns.begin();
+ it != aDynamicColumns.end(); ++it )
+ {
+ Size aPageSize( (*it)->getOptimalSize( WINDOWSIZE_PREFERRED ) );
+ updateMaxSize( aPageSize, aMaxSize );
+ }
+
+ // resize dialog if necessary
+ Size aTabSize = maTabCtrl.GetTabPageSizePixel();
+ maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() );
+ if( aMaxSize.Height() > aTabSize.Height() || aMaxSize.Width() > aTabSize.Width() )
+ {
+ Size aCurSize( GetOutputSizePixel() );
+ if( aMaxSize.Height() > aTabSize.Height() )
+ {
+ aCurSize.Height() += aMaxSize.Height() - aTabSize.Height();
+ aTabSize.Height() = aMaxSize.Height();
+ }
+ if( aMaxSize.Width() > aTabSize.Width() )
+ {
+ aCurSize.Width() += aMaxSize.Width() - aTabSize.Width();
+ // and the tab ctrl needs more space, too
+ aTabSize.Width() = aMaxSize.Width();
+ }
+ maTabCtrl.SetTabPageSizePixel( aTabSize );
+ maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() );
+ }
+
+ // and finally arrange controls
+ for( std::vector< vcl::RowOrColumn* >::iterator it = aDynamicColumns.begin();
+ it != aDynamicColumns.end(); ++it )
+ {
+ (*it)->setManagedArea( Rectangle( Point(), aTabSize ) );
+ delete *it;
+ *it = NULL;
+ }
+ maJobPage.Resize();
+ maNUpPage.Resize();
+ maOptionsPage.Resize();
+
+ Size aSz = maLayout.getOptimalSize( WINDOWSIZE_PREFERRED );
+ SetOutputSizePixel( aSz );
+}
+
+void PrintDialog::DataChanged( const DataChangedEvent& i_rDCEvt )
+{
+ // react on settings changed
+ if( i_rDCEvt.GetType() == DATACHANGED_SETTINGS )
+ checkControlDependencies();
+ ModalDialog::DataChanged( i_rDCEvt );
+}
+
+void PrintDialog::checkControlDependencies()
+{
+ if( maJobPage.maCopyCountField.GetValue() > 1 )
+ maJobPage.maCollateBox.Enable( maJobPage.mnCollateUIMode == 0 );
+ else
+ maJobPage.maCollateBox.Enable( FALSE );
+
+ Image aImg( maJobPage.maCollateBox.IsChecked() ? maJobPage.maCollateImg : maJobPage.maNoCollateImg );
+ Image aHCImg( maJobPage.maCollateBox.IsChecked() ? maJobPage.maCollateHCImg : maJobPage.maNoCollateHCImg );
+ bool bHC = GetSettings().GetStyleSettings().GetHighContrastMode();
+
+ Size aImgSize( aImg.GetSizePixel() );
+ Size aHCImgSize( aHCImg.GetSizePixel() );
+
+ if( aHCImgSize.Width() > aImgSize.Width() )
+ aImgSize.Width() = aHCImgSize.Width();
+ if( aHCImgSize.Height() > aImgSize.Height() )
+ aImgSize.Height() = aHCImgSize.Height();
+
+ // adjust size of image
+ maJobPage.maCollateImage.SetSizePixel( aImgSize );
+ maJobPage.maCollateImage.SetImage( bHC ? aHCImg : aImg );
+ maJobPage.maCollateImage.SetModeImage( aHCImg, BMP_COLOR_HIGHCONTRAST );
+ maJobPage.maLayout.resize();
+
+ // enable setup button only for printers that can be setup
+ bool bHaveSetup = maPController->getPrinter()->HasSupport( SUPPORT_SETUPDIALOG );
+ maJobPage.maSetupButton.Enable( bHaveSetup );
+ if( bHaveSetup )
+ {
+ if( ! maJobPage.maSetupButton.IsVisible() )
+ {
+ Point aPrinterPos( maJobPage.maPrinters.GetPosPixel() );
+ Point aSetupPos( maJobPage.maSetupButton.GetPosPixel() );
+ Size aPrinterSize( maJobPage.maPrinters.GetSizePixel() );
+ aPrinterSize.Width() = aSetupPos.X() - aPrinterPos.X() - LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ).Width();
+ maJobPage.maPrinters.SetSizePixel( aPrinterSize );
+ maJobPage.maSetupButton.Show();
+ maLayout.resize();
+ }
+ }
+ else
+ {
+ if( maJobPage.maSetupButton.IsVisible() )
+ {
+ Point aPrinterPos( maJobPage.maPrinters.GetPosPixel() );
+ Point aSetupPos( maJobPage.maSetupButton.GetPosPixel() );
+ Size aPrinterSize( maJobPage.maPrinters.GetSizePixel() );
+ Size aSetupSize( maJobPage.maSetupButton.GetSizePixel() );
+ aPrinterSize.Width() = aSetupPos.X() + aSetupSize.Width() - aPrinterPos.X();
+ maJobPage.maPrinters.SetSizePixel( aPrinterSize );
+ maJobPage.maSetupButton.Hide();
+ maLayout.resize();
+ }
+ }
+}
+
+void PrintDialog::checkOptionalControlDependencies()
+{
+ for( std::map< Window*, rtl::OUString >::iterator it = maControlToPropertyMap.begin();
+ it != maControlToPropertyMap.end(); ++it )
+ {
+ bool bShouldbeEnabled = maPController->isUIOptionEnabled( it->second );
+ if( ! bShouldbeEnabled )
+ {
+ // enable controls that are directly attached to a dependency anyway
+ // if the normally disabled controls get modified, change the dependency
+ // so the control would be enabled
+ // example: in print range "Print All" is selected, "Page Range" is then of course
+ // not selected and the Edit for the Page Range would be disabled
+ // as a convenience we should enable the Edit anyway and automatically select
+ // "Page Range" instead of "Print All" if the Edit gets modified
+ if( maReverseDependencySet.find( it->second ) != maReverseDependencySet.end() )
+ {
+ rtl::OUString aDep( maPController->getDependency( it->second ) );
+ // if the dependency is at least enabled, then enable this control anyway
+ if( aDep.getLength() && maPController->isUIOptionEnabled( aDep ) )
+ bShouldbeEnabled = true;
+ }
+ }
+
+ bool bIsEnabled = it->first->IsEnabled();
+ // Enable does not do a change check first, so can be less cheap than expected
+ if( bShouldbeEnabled != bIsEnabled )
+ it->first->Enable( bShouldbeEnabled );
+ }
+}
+
+static rtl::OUString searchAndReplace( const rtl::OUString& i_rOrig, const char* i_pRepl, sal_Int32 i_nReplLen, const rtl::OUString& i_rRepl )
+{
+ sal_Int32 nPos = i_rOrig.indexOfAsciiL( i_pRepl, i_nReplLen );
+ if( nPos != -1 )
+ {
+ rtl::OUStringBuffer aBuf( i_rOrig.getLength() );
+ aBuf.append( i_rOrig.getStr(), nPos );
+ aBuf.append( i_rRepl );
+ if( nPos + i_nReplLen < i_rOrig.getLength() )
+ aBuf.append( i_rOrig.getStr() + nPos + i_nReplLen );
+ return aBuf.makeStringAndClear();
+ }
+ return i_rOrig;
+}
+
+void PrintDialog::updatePrinterText()
+{
+ String aDefPrt( Printer::GetDefaultPrinterName() );
+ const QueueInfo* pInfo = Printer::GetQueueInfo( maJobPage.maPrinters.GetSelectEntry(), true );
+ if( pInfo )
+ {
+ maJobPage.maLocationTxt.SetText( pInfo->GetLocation() );
+ maJobPage.maCommentTxt.SetText( pInfo->GetComment() );
+ // FIXME: status text
+ rtl::OUString aStatus;
+ if( aDefPrt == pInfo->GetPrinterName() )
+ aStatus = maDefPrtText;
+ maJobPage.maStatusTxt.SetText( aStatus );
+ }
+ else
+ {
+ maJobPage.maLocationTxt.SetText( String() );
+ maJobPage.maCommentTxt.SetText( String() );
+ maJobPage.maStatusTxt.SetText( String() );
+ }
+}
+
+void PrintDialog::setPreviewText( sal_Int32 )
+{
+ rtl::OUString aNewText( searchAndReplace( maPageStr, "%n", 2, rtl::OUString::valueOf( mnCachedPages ) ) );
+ maNumPagesText.SetText( aNewText );
+
+ // if layout is already established the refresh layout of
+ // preview controls since text length may have changes
+ if( mxPreviewCtrls.get() )
+ mxPreviewCtrls->setManagedArea( mxPreviewCtrls->getManagedArea() );
+}
+
+void PrintDialog::preparePreview( bool i_bNewPage, bool i_bMayUseCache )
+{
+ // page range may have changed depending on options
+ sal_Int32 nPages = maPController->getFilteredPageCount();
+ mnCachedPages = nPages;
+
+ if( mnCurPage >= nPages )
+ mnCurPage = nPages-1;
+ if( mnCurPage < 0 )
+ mnCurPage = 0;
+
+ setPreviewText( mnCurPage );
+
+ maPageEdit.SetMin( 1 );
+ maPageEdit.SetMax( nPages );
+
+ if( i_bNewPage )
+ {
+ const MapMode aMapMode( MAP_100TH_MM );
+ GDIMetaFile aMtf;
+ boost::shared_ptr<Printer> aPrt( maPController->getPrinter() );
+ if( nPages > 0 )
+ {
+ PrinterController::PageSize aPageSize =
+ maPController->getFilteredPageFile( mnCurPage, aMtf, i_bMayUseCache );
+ if( ! aPageSize.bFullPaper )
+ {
+ Point aOff( aPrt->PixelToLogic( aPrt->GetPageOffsetPixel(), aMapMode ) );
+ aMtf.Move( aOff.X(), aOff.Y() );
+ }
+ }
+
+ Size aCurPageSize = aPrt->PixelToLogic( aPrt->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) );
+ maPreviewWindow.setPreview( aMtf, aCurPageSize, nPages > 0 ? rtl::OUString() : maNoPageStr,
+ aPrt->ImplGetDPIX(), aPrt->ImplGetDPIY()
+ );
+
+ maForwardBtn.Enable( mnCurPage < nPages-1 );
+ maBackwardBtn.Enable( mnCurPage != 0 );
+ maPageEdit.Enable( nPages > 1 );
+ }
+}
+
+Size PrintDialog::getJobPageSize()
+{
+ if( maFirstPageSize.Width() == 0 && maFirstPageSize.Height() == 0)
+ {
+ maFirstPageSize = maNupPortraitSize;
+ GDIMetaFile aMtf;
+ if( maPController->getPageCountProtected() > 0 )
+ {
+ PrinterController::PageSize aPageSize = maPController->getPageFile( 0, aMtf, true );
+ maFirstPageSize = aPageSize.aSize;
+ }
+ }
+ return maFirstPageSize;
+}
+
+void PrintDialog::updateNupFromPages()
+{
+ long nPages = long(maNUpPage.maNupPagesBox.GetEntryData(maNUpPage.maNupPagesBox.GetSelectEntryPos()));
+ int nRows = int(maNUpPage.maNupRowsEdt.GetValue());
+ int nCols = int(maNUpPage.maNupColEdt.GetValue());
+ long nPageMargin = long(maNUpPage.maPageMarginEdt.Denormalize(maNUpPage.maPageMarginEdt.GetValue( FUNIT_100TH_MM )));
+ long nSheetMargin = long(maNUpPage.maSheetMarginEdt.Denormalize(maNUpPage.maSheetMarginEdt.GetValue( FUNIT_100TH_MM )));
+ bool bCustom = false;
+
+ if( nPages == 1 )
+ {
+ nRows = nCols = 1;
+ nSheetMargin = 0;
+ nPageMargin = 0;
+ }
+ else if( nPages == 2 || nPages == 4 || nPages == 6 || nPages == 9 || nPages == 16 )
+ {
+ Size aJobPageSize( getJobPageSize() );
+ bool bPortrait = aJobPageSize.Width() < aJobPageSize.Height();
+ if( nPages == 2 )
+ {
+ if( bPortrait )
+ nRows = 1, nCols = 2;
+ else
+ nRows = 2, nCols = 1;
+ }
+ else if( nPages == 4 )
+ nRows = nCols = 2;
+ else if( nPages == 6 )
+ {
+ if( bPortrait )
+ nRows = 2, nCols = 3;
+ else
+ nRows = 3, nCols = 2;
+ }
+ else if( nPages == 9 )
+ nRows = nCols = 3;
+ else if( nPages == 16 )
+ nRows = nCols = 4;
+ nPageMargin = 0;
+ nSheetMargin = 0;
+ }
+ else
+ bCustom = true;
+
+ if( nPages > 1 )
+ {
+ // set upper limits for margins based on job page size and rows/columns
+ Size aSize( getJobPageSize() );
+
+ // maximum sheet distance: 1/2 sheet
+ long nHorzMax = aSize.Width()/2;
+ long nVertMax = aSize.Height()/2;
+ if( nSheetMargin > nHorzMax )
+ nSheetMargin = nHorzMax;
+ if( nSheetMargin > nVertMax )
+ nSheetMargin = nVertMax;
+
+ maNUpPage.maSheetMarginEdt.SetMax(
+ maNUpPage.maSheetMarginEdt.Normalize(
+ nHorzMax > nVertMax ? nVertMax : nHorzMax ), FUNIT_100TH_MM );
+
+ // maximum page distance
+ nHorzMax = (aSize.Width() - 2*nSheetMargin);
+ if( nCols > 1 )
+ nHorzMax /= (nCols-1);
+ nVertMax = (aSize.Height() - 2*nSheetMargin);
+ if( nRows > 1 )
+ nHorzMax /= (nRows-1);
+
+ if( nPageMargin > nHorzMax )
+ nPageMargin = nHorzMax;
+ if( nPageMargin > nVertMax )
+ nPageMargin = nVertMax;
+
+ maNUpPage.maPageMarginEdt.SetMax(
+ maNUpPage.maSheetMarginEdt.Normalize(
+ nHorzMax > nVertMax ? nVertMax : nHorzMax ), FUNIT_100TH_MM );
+ }
+
+ maNUpPage.maNupRowsEdt.SetValue( nRows );
+ maNUpPage.maNupColEdt.SetValue( nCols );
+ maNUpPage.maPageMarginEdt.SetValue( maNUpPage.maPageMarginEdt.Normalize( nPageMargin ), FUNIT_100TH_MM );
+ maNUpPage.maSheetMarginEdt.SetValue( maNUpPage.maSheetMarginEdt.Normalize( nSheetMargin ), FUNIT_100TH_MM );
+
+ maNUpPage.showAdvancedControls( bCustom );
+ if( bCustom )
+ {
+ // see if we have to enlarge the dialog to make the tab page fit
+ Size aCurSize( maNUpPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ) );
+ Size aTabSize( maTabCtrl.GetTabPageSizePixel() );
+ if( aTabSize.Height() < aCurSize.Height() )
+ {
+ Size aDlgSize( GetSizePixel() );
+ aDlgSize.Height() += aCurSize.Height() - aTabSize.Height();
+ SetSizePixel( aDlgSize );
+ }
+ }
+
+ updateNup();
+}
+
+void PrintDialog::updateNup()
+{
+ int nRows = int(maNUpPage.maNupRowsEdt.GetValue());
+ int nCols = int(maNUpPage.maNupColEdt.GetValue());
+ long nPageMargin = long(maNUpPage.maPageMarginEdt.Denormalize(maNUpPage.maPageMarginEdt.GetValue( FUNIT_100TH_MM )));
+ long nSheetMargin = long(maNUpPage.maSheetMarginEdt.Denormalize(maNUpPage.maSheetMarginEdt.GetValue( FUNIT_100TH_MM )));
+
+ PrinterController::MultiPageSetup aMPS;
+ aMPS.nRows = nRows;
+ aMPS.nColumns = nCols;
+ aMPS.nRepeat = 1;
+ aMPS.nLeftMargin =
+ aMPS.nTopMargin =
+ aMPS.nRightMargin =
+ aMPS.nBottomMargin = nSheetMargin;
+
+ aMPS.nHorizontalSpacing =
+ aMPS.nVerticalSpacing = nPageMargin;
+
+ aMPS.bDrawBorder = maNUpPage.maBorderCB.IsChecked();
+
+ int nOrderMode = int(sal_IntPtr(maNUpPage.maNupOrderBox.GetEntryData(
+ maNUpPage.maNupOrderBox.GetSelectEntryPos() )));
+ if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_LRTD )
+ aMPS.nOrder = PrinterController::LRTB;
+ else if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_TDLR )
+ aMPS.nOrder = PrinterController::TBLR;
+
+ int nOrientationMode = int(sal_IntPtr(maNUpPage.maNupOrientationBox.GetEntryData(
+ maNUpPage.maNupOrientationBox.GetSelectEntryPos() )));
+ if( nOrientationMode == SV_PRINT_PRT_NUP_ORIENTATION_LANDSCAPE )
+ aMPS.aPaperSize = maNupLandscapeSize;
+ else if( nOrientationMode == SV_PRINT_PRT_NUP_ORIENTATION_PORTRAIT )
+ aMPS.aPaperSize = maNupPortraitSize;
+ else // automatic mode
+ {
+ // get size of first real page to see if it is portrait or landscape
+ // we assume same page sizes for all the pages for this
+ Size aPageSize = getJobPageSize();
+
+ Size aMultiSize( aPageSize.Width() * nCols, aPageSize.Height() * nRows );
+ if( aMultiSize.Width() > aMultiSize.Height() ) // fits better on landscape
+ aMPS.aPaperSize = maNupLandscapeSize;
+ else
+ aMPS.aPaperSize = maNupPortraitSize;
+ }
+
+ maPController->setMultipage( aMPS );
+
+ maNUpPage.maNupOrderWin.setValues( nOrderMode, nCols, nRows );
+
+ preparePreview( true, true );
+}
+
+IMPL_LINK( PrintDialog, SelectHdl, ListBox*, pBox )
+{
+ if( pBox == &maJobPage.maPrinters )
+ {
+ String aNewPrinter( pBox->GetSelectEntry() );
+ // set new printer
+ maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( aNewPrinter ) ) );
+ // update text fields
+ updatePrinterText();
+ }
+ else if( pBox == &maNUpPage.maNupOrientationBox || pBox == &maNUpPage.maNupOrderBox )
+ {
+ updateNup();
+ }
+ else if( pBox == &maNUpPage.maNupPagesBox )
+ {
+ if( !maNUpPage.maPagesBtn.IsChecked() )
+ maNUpPage.maPagesBtn.Check();
+ updateNupFromPages();
+ }
+
+ return 0;
+}
+
+IMPL_LINK( PrintDialog, ClickHdl, Button*, pButton )
+{
+ if( pButton == &maOKButton || pButton == &maCancelButton )
+ {
+ storeToSettings();
+ EndDialog( pButton == &maOKButton );
+ }
+ else if( pButton == &maHelpButton )
+ {
+ // start help system
+ Help* pHelp = Application::GetHelp();
+ if( pHelp )
+ {
+ // FIXME: find out proper help URL and use here
+ pHelp->Start( HID_PRINTDLG, GetParent() );
+ }
+ }
+ else if( pButton == &maForwardBtn )
+ {
+ previewForward();
+ }
+ else if( pButton == &maBackwardBtn )
+ {
+ previewBackward();
+ }
+ else if( pButton == &maOptionsPage.maToFileBox )
+ {
+ maOKButton.SetText( maOptionsPage.maToFileBox.IsChecked() ? maPrintToFileText : maPrintText );
+ maLayout.resize();
+ }
+ else if( pButton == &maNUpPage.maBrochureBtn )
+ {
+ PropertyValue* pVal = getValueForWindow( pButton );
+ if( pVal )
+ {
+ sal_Bool bVal = maNUpPage.maBrochureBtn.IsChecked();
+ pVal->Value <<= bVal;
+
+ checkOptionalControlDependencies();
+
+ // update preview and page settings
+ preparePreview();
+ }
+ if( maNUpPage.maBrochureBtn.IsChecked() )
+ {
+ maNUpPage.maNupPagesBox.SelectEntryPos( 0 );
+ updateNupFromPages();
+ maNUpPage.showAdvancedControls( false );
+ maNUpPage.enableNupControls( false );
+ }
+ }
+ else if( pButton == &maNUpPage.maPagesBtn )
+ {
+ maNUpPage.enableNupControls( true );
+ updateNupFromPages();
+ }
+ else if( pButton == &maJobPage.maDetailsBtn )
+ {
+ bool bShow = maJobPage.maDetailsBtn.IsChecked();
+ maJobPage.mxDetails->show( bShow );
+ if( bShow )
+ {
+ maDetailsCollapsedSize = GetOutputSizePixel();
+ // enlarge dialog if necessary
+ Size aMinSize( maJobPage.maLayout.getOptimalSize( WINDOWSIZE_MINIMUM ) );
+ Size aCurSize( maJobPage.GetSizePixel() );
+ if( aCurSize.Height() < aMinSize.Height() )
+ {
+ Size aDlgSize( GetOutputSizePixel() );
+ aDlgSize.Height() += aMinSize.Height() - aCurSize.Height();
+ SetOutputSizePixel( aDlgSize );
+ }
+ maDetailsExpandedSize = GetOutputSizePixel();
+ }
+ else if( maDetailsCollapsedSize.Width() > 0 &&
+ maDetailsCollapsedSize.Height() > 0 )
+ {
+ // if the user did not resize the dialog
+ // make it smaller again on collapsing the details
+ Size aDlgSize( GetOutputSizePixel() );
+ if( aDlgSize == maDetailsExpandedSize &&
+ aDlgSize.Height() > maDetailsCollapsedSize.Height() )
+ {
+ SetOutputSizePixel( maDetailsCollapsedSize );
+ }
+ }
+ }
+ else if( pButton == &maJobPage.maCollateBox )
+ {
+ maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ),
+ makeAny( sal_Bool(isCollate()) ) );
+ checkControlDependencies();
+ }
+ else if( pButton == &maOptionsPage.maReverseOrderBox )
+ {
+ sal_Bool bChecked = maOptionsPage.maReverseOrderBox.IsChecked();
+ maPController->setReversePrint( bChecked );
+ maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintReverse" ) ),
+ makeAny( bChecked ) );
+ preparePreview( true, true );
+ }
+ else if( pButton == &maNUpPage.maBorderCB )
+ {
+ updateNup();
+ }
+ else
+ {
+ if( pButton == &maJobPage.maSetupButton )
+ {
+ maPController->setupPrinter( this );
+ preparePreview( true, true );
+ }
+ checkControlDependencies();
+ }
+ return 0;
+}
+
+IMPL_LINK( PrintDialog, ModifyHdl, Edit*, pEdit )
+{
+ checkControlDependencies();
+ if( pEdit == &maNUpPage.maNupRowsEdt || pEdit == &maNUpPage.maNupColEdt ||
+ pEdit == &maNUpPage.maSheetMarginEdt || pEdit == &maNUpPage.maPageMarginEdt
+ )
+ {
+ updateNupFromPages();
+ }
+ else if( pEdit == &maPageEdit )
+ {
+ mnCurPage = sal_Int32( maPageEdit.GetValue() - 1 );
+ preparePreview( true, true );
+ }
+ else if( pEdit == &maJobPage.maCopyCountField )
+ {
+ maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ),
+ makeAny( sal_Int32(maJobPage.maCopyCountField.GetValue()) ) );
+ maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ),
+ makeAny( sal_Bool(isCollate()) ) );
+ }
+ return 0;
+}
+
+IMPL_LINK( PrintDialog, UIOptionsChanged, void*, EMPTYARG )
+{
+ checkOptionalControlDependencies();
+ return 0;
+}
+
+PropertyValue* PrintDialog::getValueForWindow( Window* i_pWindow ) const
+{
+ PropertyValue* pVal = NULL;
+ std::map< Window*, rtl::OUString >::const_iterator it = maControlToPropertyMap.find( i_pWindow );
+ if( it != maControlToPropertyMap.end() )
+ {
+ pVal = maPController->getValue( it->second );
+ DBG_ASSERT( pVal, "property value not found" );
+ }
+ else
+ {
+ DBG_ERROR( "changed control not in property map" );
+ }
+ return pVal;
+}
+
+void PrintDialog::updateWindowFromProperty( const rtl::OUString& i_rProperty )
+{
+ beans::PropertyValue* pValue = maPController->getValue( i_rProperty );
+ std::map< rtl::OUString, std::vector< Window* > >::const_iterator it = maPropertyToWindowMap.find( i_rProperty );
+ if( pValue && it != maPropertyToWindowMap.end() )
+ {
+ const std::vector< Window* >& rWindows( it->second );
+ if( ! rWindows.empty() )
+ {
+ sal_Bool bVal = sal_False;
+ sal_Int32 nVal = -1;
+ if( pValue->Value >>= bVal )
+ {
+ // we should have a CheckBox for this one
+ CheckBox* pBox = dynamic_cast< CheckBox* >( rWindows.front() );
+ if( pBox )
+ {
+ pBox->Check( bVal );
+ }
+ else if( i_rProperty.equalsAscii( "PrintProspect" ) )
+ {
+ // EVIL special case
+ if( bVal )
+ maNUpPage.maBrochureBtn.Check();
+ else
+ maNUpPage.maPagesBtn.Check();
+ }
+ else
+ {
+ DBG_ASSERT( 0, "missing a checkbox" );
+ }
+ }
+ else if( pValue->Value >>= nVal )
+ {
+ // this could be a ListBox or a RadioButtonGroup
+ ListBox* pList = dynamic_cast< ListBox* >( rWindows.front() );
+ if( pList )
+ {
+ pList->SelectEntryPos( static_cast< USHORT >(nVal) );
+ }
+ else if( nVal >= 0 && nVal < sal_Int32(rWindows.size() ) )
+ {
+ RadioButton* pBtn = dynamic_cast< RadioButton* >( rWindows[nVal] );
+ DBG_ASSERT( pBtn, "unexpected control for property" );
+ if( pBtn )
+ pBtn->Check();
+ }
+ }
+ }
+ }
+}
+
+void PrintDialog::makeEnabled( Window* i_pWindow )
+{
+ std::map< Window*, rtl::OUString >::const_iterator it = maControlToPropertyMap.find( i_pWindow );
+ if( it != maControlToPropertyMap.end() )
+ {
+ rtl::OUString aDependency( maPController->makeEnabled( it->second ) );
+ if( aDependency.getLength() )
+ updateWindowFromProperty( aDependency );
+ }
+}
+
+IMPL_LINK( PrintDialog, UIOption_CheckHdl, CheckBox*, i_pBox )
+{
+ PropertyValue* pVal = getValueForWindow( i_pBox );
+ if( pVal )
+ {
+ makeEnabled( i_pBox );
+
+ sal_Bool bVal = i_pBox->IsChecked();
+ pVal->Value <<= bVal;
+
+ checkOptionalControlDependencies();
+
+ // update preview and page settings
+ preparePreview();
+ }
+ return 0;
+}
+
+IMPL_LINK( PrintDialog, UIOption_RadioHdl, RadioButton*, i_pBtn )
+{
+ // this handler gets called for all radiobuttons that get unchecked, too
+ // however we only want one notificaction for the new value (that is for
+ // the button that gets checked)
+ if( i_pBtn->IsChecked() )
+ {
+ PropertyValue* pVal = getValueForWindow( i_pBtn );
+ std::map< Window*, sal_Int32 >::const_iterator it = maControlToNumValMap.find( i_pBtn );
+ if( pVal && it != maControlToNumValMap.end() )
+ {
+ makeEnabled( i_pBtn );
+
+ sal_Int32 nVal = it->second;
+ pVal->Value <<= nVal;
+
+ checkOptionalControlDependencies();
+
+ // update preview and page settings
+ preparePreview();
+ }
+ }
+ return 0;
+}
+
+IMPL_LINK( PrintDialog, UIOption_SelectHdl, ListBox*, i_pBox )
+{
+ PropertyValue* pVal = getValueForWindow( i_pBox );
+ if( pVal )
+ {
+ makeEnabled( i_pBox );
+
+ sal_Int32 nVal( i_pBox->GetSelectEntryPos() );
+ pVal->Value <<= nVal;
+
+ checkOptionalControlDependencies();
+
+ // update preview and page settings
+ preparePreview();
+ }
+ return 0;
+}
+
+IMPL_LINK( PrintDialog, UIOption_ModifyHdl, Edit*, i_pBox )
+{
+ PropertyValue* pVal = getValueForWindow( i_pBox );
+ if( pVal )
+ {
+ makeEnabled( i_pBox );
+
+ NumericField* pNum = dynamic_cast<NumericField*>(i_pBox);
+ MetricField* pMetric = dynamic_cast<MetricField*>(i_pBox);
+ if( pNum )
+ {
+ sal_Int64 nVal = pNum->GetValue();
+ pVal->Value <<= nVal;
+ }
+ else if( pMetric )
+ {
+ sal_Int64 nVal = pMetric->GetValue();
+ pVal->Value <<= nVal;
+ }
+ else
+ {
+ rtl::OUString aVal( i_pBox->GetText() );
+ pVal->Value <<= aVal;
+ }
+
+ checkOptionalControlDependencies();
+
+ // update preview and page settings
+ preparePreview();
+ }
+ return 0;
+}
+
+void PrintDialog::Command( const CommandEvent& rEvt )
+{
+ if( rEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pWheelData = rEvt.GetWheelData();
+ if( pWheelData->GetDelta() > 0 )
+ previewForward();
+ else if( pWheelData->GetDelta() < 0 )
+ previewBackward();
+ /*
+ else
+ huh ?
+ */
+ }
+}
+
+void PrintDialog::Resize()
+{
+ maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) );
+ // and do the preview; however the metafile does not need to be gotten anew
+ preparePreview( false );
+
+ // do an invalidate for the benefit of the grouping elements
+ Invalidate();
+}
+
+void PrintDialog::previewForward()
+{
+ maPageEdit.Up();
+}
+
+void PrintDialog::previewBackward()
+{
+ maPageEdit.Down();
+}
+
+// -----------------------------------------------------------------------------
+//
+// PrintProgressDialog
+//
+// -----------------------------------------------------------------------------
+
+PrintProgressDialog::PrintProgressDialog( Window* i_pParent, int i_nMax ) :
+ ModelessDialog( i_pParent, VclResId( SV_DLG_PRINT_PROGRESS ) ),
+ maText( this, VclResId( SV_PRINT_PROGRESS_TEXT ) ),
+ maButton( this, VclResId( SV_PRINT_PROGRESS_CANCEL ) ),
+ mbCanceled( false ),
+ mnCur( 0 ),
+ mnMax( i_nMax ),
+ mnProgressHeight( 15 ),
+ mbNativeProgress( false )
+{
+ FreeResource();
+
+ if( mnMax < 1 )
+ mnMax = 1;
+
+ maStr = maText.GetText();
+
+ maButton.SetClickHdl( LINK( this, PrintProgressDialog, ClickHdl ) );
+
+}
+
+PrintProgressDialog::~PrintProgressDialog()
+{
+}
+
+IMPL_LINK( PrintProgressDialog, ClickHdl, Button*, pButton )
+{
+ if( pButton == &maButton )
+ mbCanceled = true;
+
+ return 0;
+}
+
+void PrintProgressDialog::implCalcProgressRect()
+{
+ if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aValue;
+ Rectangle aControlRegion( Point(), Size( 100, mnProgressHeight ) );
+ Rectangle aNativeControlRegion, aNativeContentRegion;
+ if( GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
+ CTRL_STATE_ENABLED, aValue, rtl::OUString(),
+ aNativeControlRegion, aNativeContentRegion ) )
+ {
+ mnProgressHeight = aNativeControlRegion.GetHeight();
+ }
+ mbNativeProgress = true;
+ }
+ maProgressRect = Rectangle( Point( 10, maText.GetPosPixel().Y() + maText.GetSizePixel().Height() + 8 ),
+ Size( GetSizePixel().Width() - 20, mnProgressHeight ) );
+}
+
+void PrintProgressDialog::setProgress( int i_nCurrent, int i_nMax )
+{
+ if( maProgressRect.IsEmpty() )
+ implCalcProgressRect();
+
+ mnCur = i_nCurrent;
+ if( i_nMax != -1 )
+ mnMax = i_nMax;
+
+ if( mnMax < 1 )
+ mnMax = 1;
+
+ rtl::OUString aNewText( searchAndReplace( maStr, "%p", 2, rtl::OUString::valueOf( mnCur ) ) );
+ aNewText = searchAndReplace( aNewText, "%n", 2, rtl::OUString::valueOf( mnMax ) );
+ maText.SetText( aNewText );
+
+ // update progress
+ Invalidate( maProgressRect, INVALIDATE_UPDATE );
+}
+
+void PrintProgressDialog::tick()
+{
+ if( mnCur < mnMax )
+ setProgress( ++mnCur );
+}
+
+void PrintProgressDialog::reset()
+{
+ setProgress( 0 );
+}
+
+void PrintProgressDialog::Paint( const Rectangle& )
+{
+ if( maProgressRect.IsEmpty() )
+ implCalcProgressRect();
+
+ Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Color aPrgsColor = rStyleSettings.GetHighlightColor();
+ if ( aPrgsColor == rStyleSettings.GetFaceColor() )
+ aPrgsColor = rStyleSettings.GetDarkShadowColor();
+ SetLineColor();
+ SetFillColor( aPrgsColor );
+
+ const long nOffset = 3;
+ const long nWidth = 3*mnProgressHeight/2;
+ const long nFullWidth = nWidth + nOffset;
+ const long nMaxCount = maProgressRect.GetWidth() / nFullWidth;
+ DrawProgress( this, maProgressRect.TopLeft(),
+ nOffset,
+ nWidth,
+ mnProgressHeight,
+ static_cast<USHORT>(0),
+ static_cast<USHORT>(10000*mnCur/mnMax),
+ static_cast<USHORT>(10000/nMaxCount),
+ maProgressRect
+ );
+ Pop();
+
+ if( ! mbNativeProgress )
+ {
+ DecorationView aDecoView( this );
+ Rectangle aFrameRect( maProgressRect );
+ aFrameRect.Left() -= nOffset;
+ aFrameRect.Right() += nOffset;
+ aFrameRect.Top() -= nOffset;
+ aFrameRect.Bottom() += nOffset;
+ aDecoView.DrawFrame( aFrameRect );
+ }
+}
+
diff --git a/vcl/source/window/scrwnd.cxx b/vcl/source/window/scrwnd.cxx
new file mode 100644
index 000000000000..735add842518
--- /dev/null
+++ b/vcl/source/window/scrwnd.cxx
@@ -0,0 +1,420 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// #include <math.h>
+#include <limits.h>
+#include <tools/time.hxx>
+#include <tools/debug.hxx>
+
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+#include <vcl/svdata.hxx>
+#ifndef _VCL_TIMER_HXX
+#include <vcl/timer.hxx>
+#endif
+#ifndef _VCL_EVENT_HXX
+#include <vcl/event.hxx>
+#endif
+#ifndef _VCL_SCRWND_HXX
+#include <scrwnd.hxx>
+#endif
+
+#include <math.h>
+#include <limits.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define WHEEL_WIDTH 25
+#define WHEEL_RADIUS ((WHEEL_WIDTH) >> 1 )
+#define MAX_TIME 300
+#define MIN_TIME 20
+#define DEF_TIMEOUT 50
+
+// -------------------
+// - ImplWheelWindow -
+// -------------------
+
+ImplWheelWindow::ImplWheelWindow( Window* pParent ) :
+ FloatingWindow ( pParent, 0 ),
+ mnRepaintTime ( 1UL ),
+ mnTimeout ( DEF_TIMEOUT ),
+ mnWheelMode ( WHEELMODE_NONE ),
+ mnActDist ( 0UL ),
+ mnActDeltaX ( 0L ),
+ mnActDeltaY ( 0L )
+{
+ // we need a parent
+ DBG_ASSERT( pParent, "ImplWheelWindow::ImplWheelWindow(): Parent not set!" );
+
+ const Size aSize( pParent->GetOutputSizePixel() );
+ const USHORT nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
+ const BOOL bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
+ const BOOL bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;
+
+ // calculate maximum speed distance
+ mnMaxWidth = (ULONG) ( 0.4 * hypot( (double) aSize.Width(), aSize.Height() ) );
+
+ // create wheel window
+ SetTitleType( FLOATWIN_TITLE_NONE );
+ ImplCreateImageList();
+ ResMgr* pResMgr = ImplGetResMgr();
+ Bitmap aBmp;
+ if( pResMgr )
+ aBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLMSK, *pResMgr ) );
+ ImplSetRegion( aBmp );
+
+ // set wheel mode
+ if( bHorz && bVert )
+ ImplSetWheelMode( WHEELMODE_VH );
+ else if( bHorz )
+ ImplSetWheelMode( WHEELMODE_H );
+ else
+ ImplSetWheelMode( WHEELMODE_V );
+
+ // init timer
+ mpTimer = new Timer;
+ mpTimer->SetTimeoutHdl( LINK( this, ImplWheelWindow, ImplScrollHdl ) );
+ mpTimer->SetTimeout( mnTimeout );
+ mpTimer->Start();
+
+ CaptureMouse();
+}
+
+// ------------------------------------------------------------------------
+
+ImplWheelWindow::~ImplWheelWindow()
+{
+ ImplStop();
+ delete mpTimer;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::ImplStop()
+{
+ ReleaseMouse();
+ mpTimer->Stop();
+ Show(FALSE);
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::ImplSetRegion( const Bitmap& rRegionBmp )
+{
+ Point aPos( GetPointerPosPixel() );
+ const Size aSize( rRegionBmp.GetSizePixel() );
+ Point aPoint;
+ const Rectangle aRect( aPoint, aSize );
+
+ maCenter = maLastMousePos = aPos;
+ aPos.X() -= aSize.Width() >> 1;
+ aPos.Y() -= aSize.Height() >> 1;
+
+ SetPosSizePixel( aPos, aSize );
+ SetWindowRegionPixel( rRegionBmp.CreateRegion( COL_BLACK, aRect ) );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::ImplCreateImageList()
+{
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ maImgList.InsertFromHorizontalBitmap
+ ( ResId( SV_RESID_BITMAP_SCROLLBMP, *pResMgr ), 6, NULL );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::ImplSetWheelMode( ULONG nWheelMode )
+{
+ if( nWheelMode != mnWheelMode )
+ {
+ mnWheelMode = nWheelMode;
+
+ if( WHEELMODE_NONE == mnWheelMode )
+ {
+ if( IsVisible() )
+ Hide();
+ }
+ else
+ {
+ if( !IsVisible() )
+ Show();
+
+ ImplDrawWheel();
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::ImplDrawWheel()
+{
+ USHORT nId;
+
+ switch( mnWheelMode )
+ {
+ case( WHEELMODE_VH ): nId = 1; break;
+ case( WHEELMODE_V ): nId = 2; break;
+ case( WHEELMODE_H ): nId = 3; break;
+ case( WHEELMODE_SCROLL_VH ):nId = 4; break;
+ case( WHEELMODE_SCROLL_V ): nId = 5; break;
+ case( WHEELMODE_SCROLL_H ): nId = 6; break;
+ default: nId = 0; break;
+ }
+
+ if( nId )
+ DrawImage( Point(), maImgList.GetImage( nId ) );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::ImplRecalcScrollValues()
+{
+ if( mnActDist < WHEEL_RADIUS )
+ {
+ mnActDeltaX = mnActDeltaY = 0L;
+ mnTimeout = DEF_TIMEOUT;
+ }
+ else
+ {
+ ULONG nCurTime;
+
+ // calc current time
+ if( mnMaxWidth )
+ {
+ const double fExp = ( (double) mnActDist / mnMaxWidth ) * log10( (double) MAX_TIME / MIN_TIME );
+ nCurTime = (ULONG) ( MAX_TIME / pow( 10., fExp ) );
+ }
+ else
+ nCurTime = MAX_TIME;
+
+ if( !nCurTime )
+ nCurTime = 1UL;
+
+ if( mnRepaintTime <= nCurTime )
+ mnTimeout = nCurTime - mnRepaintTime;
+ else
+ {
+ long nMult = mnRepaintTime / nCurTime;
+
+ if( !( mnRepaintTime % nCurTime ) )
+ mnTimeout = 0UL;
+ else
+ mnTimeout = ++nMult * nCurTime - mnRepaintTime;
+
+ double fValX = (double) mnActDeltaX * nMult;
+ double fValY = (double) mnActDeltaY * nMult;
+
+ if( fValX > LONG_MAX )
+ mnActDeltaX = LONG_MAX;
+ else if( fValX < LONG_MIN )
+ mnActDeltaX = LONG_MIN;
+ else
+ mnActDeltaX = (long) fValX;
+
+ if( fValY > LONG_MAX )
+ mnActDeltaY = LONG_MAX;
+ else if( fValY < LONG_MIN )
+ mnActDeltaY = LONG_MIN;
+ else
+ mnActDeltaY = (long) fValY;
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+PointerStyle ImplWheelWindow::ImplGetMousePointer( long nDistX, long nDistY )
+{
+ PointerStyle eStyle;
+ const USHORT nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
+ const BOOL bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
+ const BOOL bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;
+
+ if( bHorz || bVert )
+ {
+ if( mnActDist < WHEEL_RADIUS )
+ {
+ if( bHorz && bVert )
+ eStyle = POINTER_AUTOSCROLL_NSWE;
+ else if( bHorz )
+ eStyle = POINTER_AUTOSCROLL_WE;
+ else
+ eStyle = POINTER_AUTOSCROLL_NS;
+ }
+ else
+ {
+ double fAngle = atan2( (double) -nDistY, nDistX ) / F_PI180;
+
+ if( fAngle < 0.0 )
+ fAngle += 360.;
+
+ if( bHorz && bVert )
+ {
+ if( fAngle >= 22.5 && fAngle <= 67.5 )
+ eStyle = POINTER_AUTOSCROLL_NE;
+ else if( fAngle >= 67.5 && fAngle <= 112.5 )
+ eStyle = POINTER_AUTOSCROLL_N;
+ else if( fAngle >= 112.5 && fAngle <= 157.5 )
+ eStyle = POINTER_AUTOSCROLL_NW;
+ else if( fAngle >= 157.5 && fAngle <= 202.5 )
+ eStyle = POINTER_AUTOSCROLL_W;
+ else if( fAngle >= 202.5 && fAngle <= 247.5 )
+ eStyle = POINTER_AUTOSCROLL_SW;
+ else if( fAngle >= 247.5 && fAngle <= 292.5 )
+ eStyle = POINTER_AUTOSCROLL_S;
+ else if( fAngle >= 292.5 && fAngle <= 337.5 )
+ eStyle = POINTER_AUTOSCROLL_SE;
+ else
+ eStyle = POINTER_AUTOSCROLL_E;
+ }
+ else if( bHorz )
+ {
+ if( fAngle >= 270. || fAngle <= 90. )
+ eStyle = POINTER_AUTOSCROLL_E;
+ else
+ eStyle = POINTER_AUTOSCROLL_W;
+ }
+ else
+ {
+ if( fAngle >= 0. && fAngle <= 180. )
+ eStyle = POINTER_AUTOSCROLL_N;
+ else
+ eStyle = POINTER_AUTOSCROLL_S;
+ }
+ }
+ }
+ else
+ eStyle = POINTER_ARROW;
+
+ return eStyle;
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::Paint( const Rectangle& )
+{
+ ImplDrawWheel();
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ FloatingWindow::MouseMove( rMEvt );
+
+ const Point aMousePos( OutputToScreenPixel( rMEvt.GetPosPixel() ) );
+ const long nDistX = aMousePos.X() - maCenter.X();
+ const long nDistY = aMousePos.Y() - maCenter.Y();
+
+ mnActDist = (ULONG) hypot( (double) nDistX, nDistY );
+
+ const PointerStyle eActStyle = ImplGetMousePointer( nDistX, nDistY );
+ const USHORT nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
+ const BOOL bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
+ const BOOL bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;
+ const BOOL bOuter = mnActDist > WHEEL_RADIUS;
+
+ if( bOuter && ( maLastMousePos != aMousePos ) )
+ {
+ switch( eActStyle )
+ {
+ case( POINTER_AUTOSCROLL_N ): mnActDeltaX = +0L, mnActDeltaY = +1L; break;
+ case( POINTER_AUTOSCROLL_S ): mnActDeltaX = +0L, mnActDeltaY = -1L; break;
+ case( POINTER_AUTOSCROLL_W ): mnActDeltaX = +1L, mnActDeltaY = +0L; break;
+ case( POINTER_AUTOSCROLL_E ): mnActDeltaX = -1L, mnActDeltaY = +0L; break;
+ case( POINTER_AUTOSCROLL_NW ): mnActDeltaX = +1L, mnActDeltaY = +1L; break;
+ case( POINTER_AUTOSCROLL_NE ): mnActDeltaX = -1L, mnActDeltaY = +1L; break;
+ case( POINTER_AUTOSCROLL_SW ): mnActDeltaX = +1L, mnActDeltaY = -1L; break;
+ case( POINTER_AUTOSCROLL_SE ): mnActDeltaX = -1L, mnActDeltaY = -1L; break;
+
+ default:
+ break;
+ }
+ }
+
+ ImplRecalcScrollValues();
+ maLastMousePos = aMousePos;
+ SetPointer( eActStyle );
+
+ if( bHorz && bVert )
+ ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_VH : WHEELMODE_VH );
+ else if( bHorz )
+ ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_H : WHEELMODE_H );
+ else
+ ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_V : WHEELMODE_V );
+}
+
+// ------------------------------------------------------------------------
+
+void ImplWheelWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ if( mnActDist > WHEEL_RADIUS )
+ GetParent()->EndAutoScroll();
+ else
+ FloatingWindow::MouseButtonUp( rMEvt );
+}
+
+// ------------------------------------------------------------------------
+
+IMPL_LINK( ImplWheelWindow, ImplScrollHdl, Timer*, EMPTYARG )
+{
+ if ( mnActDeltaX || mnActDeltaY )
+ {
+ Window* pWindow = GetParent();
+ const Point aMousePos( pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() ) );
+ Point aCmdMousePos( pWindow->ImplFrameToOutput( aMousePos ) );
+ CommandScrollData aScrollData( mnActDeltaX, mnActDeltaY );
+ CommandEvent aCEvt( aCmdMousePos, COMMAND_AUTOSCROLL, TRUE, &aScrollData );
+ NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
+
+ if ( !ImplCallPreNotify( aNCmdEvt ) )
+ {
+ const ULONG nTime = Time::GetSystemTicks();
+ ImplDelData aDel( this );
+ pWindow->Command( aCEvt );
+ if( aDel.IsDead() )
+ return 0;
+ mnRepaintTime = Max( Time::GetSystemTicks() - nTime, 1UL );
+ ImplRecalcScrollValues();
+ }
+ }
+
+ if ( mnTimeout != mpTimer->GetTimeout() )
+ mpTimer->SetTimeout( mnTimeout );
+ mpTimer->Start();
+
+ return 0L;
+}
diff --git a/vcl/source/window/scrwnd.hxx b/vcl/source/window/scrwnd.hxx
new file mode 100644
index 000000000000..d808fa73e321
--- /dev/null
+++ b/vcl/source/window/scrwnd.hxx
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include <vcl/floatwin.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/image.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define WHEELMODE_NONE 0x00000000UL
+#define WHEELMODE_VH 0x00000001UL
+#define WHEELMODE_V 0x00000002UL
+#define WHEELMODE_H 0x00000004UL
+#define WHEELMODE_SCROLL_VH 0x00000008UL
+#define WHEELMODE_SCROLL_V 0x00000010UL
+#define WHEELMODE_SCROLL_H 0x00000020UL
+
+// -------------------
+// - ImplWheelWindow -
+// -------------------
+
+class Timer;
+
+class ImplWheelWindow : public FloatingWindow
+{
+private:
+
+ ImageList maImgList;
+ Bitmap maWheelBmp;
+ CommandScrollData maCommandScrollData;
+ Point maLastMousePos;
+ Point maCenter;
+ Timer* mpTimer;
+ ULONG mnRepaintTime;
+ ULONG mnTimeout;
+ ULONG mnWheelMode;
+ ULONG mnMaxWidth;
+ ULONG mnActWidth;
+ ULONG mnActDist;
+ long mnActDeltaX;
+ long mnActDeltaY;
+
+ void ImplCreateImageList();
+ void ImplSetRegion( const Bitmap& rRegionBmp );
+ using Window::ImplGetMousePointer;
+ PointerStyle ImplGetMousePointer( long nDistX, long nDistY );
+ void ImplDrawWheel();
+ void ImplRecalcScrollValues();
+
+ DECL_LINK( ImplScrollHdl, Timer* pTimer );
+
+protected:
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+
+public:
+
+ ImplWheelWindow( Window* pParent );
+ ~ImplWheelWindow();
+
+ void ImplStop();
+ void ImplSetWheelMode( ULONG nWheelMode );
+ ULONG ImplGetWheelMode() const { return mnWheelMode; }
+};
diff --git a/vcl/source/window/seleng.cxx b/vcl/source/window/seleng.cxx
new file mode 100644
index 000000000000..d4ee01c26d61
--- /dev/null
+++ b/vcl/source/window/seleng.cxx
@@ -0,0 +1,491 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/ref.hxx>
+#include <vcl/window.hxx>
+#include <vcl/seleng.hxx>
+#include <tools/debug.hxx>
+
+
+
+
+inline BOOL SelectionEngine::ShouldDeselect( BOOL bModifierKey1 ) const
+{
+// return !( eSelMode == MULTIPLE_SELECTION && bModifierKey1 );
+ return eSelMode != MULTIPLE_SELECTION || !bModifierKey1;
+}
+
+
+// TODO: FunctionSet::SelectAtPoint raus
+
+/*************************************************************************
+|*
+|* SelectionEngine::SelectionEngine()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+SelectionEngine::SelectionEngine( Window* pWindow, FunctionSet* pFuncSet ) :
+ pWin( pWindow )
+{
+ eSelMode = SINGLE_SELECTION;
+ pFunctionSet = pFuncSet;
+ nFlags = SELENG_EXPANDONMOVE;
+ nLockedMods = 0;
+
+ aWTimer.SetTimeoutHdl( LINK( this, SelectionEngine, ImpWatchDog ) );
+ aWTimer.SetTimeout( SELENG_AUTOREPEAT_INTERVAL );
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::~SelectionEngine()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+SelectionEngine::~SelectionEngine()
+{
+ aWTimer.Stop();
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::ImpWatchDog()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+IMPL_LINK( SelectionEngine, ImpWatchDog, Timer*, EMPTYARG )
+{
+ if ( !aArea.IsInside( aLastMove.GetPosPixel() ) )
+ SelMouseMove( aLastMove );
+ return 0;
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::SetSelectionMode()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+void SelectionEngine::SetSelectionMode( SelectionMode eMode )
+{
+ eSelMode = eMode;
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::ActivateDragMode()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+void SelectionEngine::ActivateDragMode()
+{
+ DBG_ERRORFILE( "SelectionEngine::ActivateDragMode not implemented" );
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::CursorPosChanging()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung GT 2002-04-04
+|*
+*************************************************************************/
+
+void SelectionEngine::CursorPosChanging( BOOL bShift, BOOL bMod1 )
+{
+ if ( !pFunctionSet )
+ return;
+
+ if ( bShift && eSelMode != SINGLE_SELECTION )
+ {
+ if ( IsAddMode() )
+ {
+ if ( !(nFlags & SELENG_HAS_ANCH) )
+ {
+ pFunctionSet->CreateAnchor();
+ nFlags |= SELENG_HAS_ANCH;
+ }
+ }
+ else
+ {
+ if ( !(nFlags & SELENG_HAS_ANCH) )
+ {
+ if( ShouldDeselect( bMod1 ) )
+ pFunctionSet->DeselectAll();
+ pFunctionSet->CreateAnchor();
+ nFlags |= SELENG_HAS_ANCH;
+ }
+ }
+ }
+ else
+ {
+ if ( IsAddMode() )
+ {
+ if ( nFlags & SELENG_HAS_ANCH )
+ {
+ // pFunctionSet->CreateCursor();
+ pFunctionSet->DestroyAnchor();
+ nFlags &= (~SELENG_HAS_ANCH);
+ }
+ }
+ else
+ {
+ if( ShouldDeselect( bMod1 ) )
+ pFunctionSet->DeselectAll();
+ else
+ pFunctionSet->DestroyAnchor();
+ nFlags &= (~SELENG_HAS_ANCH);
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::SelMouseButtonDown()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 07.06.95
+|*
+*************************************************************************/
+
+BOOL SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt )
+{
+ nFlags &= (~SELENG_CMDEVT);
+ if ( !pFunctionSet || !pWin )
+ return FALSE;
+ const bool bRightClickCursorPositioning =
+ rMEvt.IsRight() && rMEvt.GetClicks() == 1 && !IsInSelection();
+ if ( (rMEvt.GetClicks() > 1 || rMEvt.IsRight()) && !bRightClickCursorPositioning )
+ return FALSE;
+
+ USHORT nModifier = rMEvt.GetModifier() | nLockedMods;
+ if ( nModifier & KEY_MOD2 )
+ return FALSE;
+ // in SingleSelection: Control-Taste filtern (damit auch
+ // mit Ctrl-Click ein D&D gestartet werden kann)
+ if ( nModifier == KEY_MOD1 && eSelMode == SINGLE_SELECTION )
+ nModifier = 0;
+
+ Point aPos = rMEvt.GetPosPixel();
+ aLastMove = rMEvt;
+
+ pWin->CaptureMouse();
+ nFlags |= SELENG_IN_SEL;
+
+ switch ( nModifier )
+ {
+ case 0: // KEY_NO_KEY
+ {
+ BOOL bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
+ nFlags &= (~SELENG_IN_ADD);
+ if ( (nFlags & SELENG_DRG_ENAB) && bSelAtPoint )
+ {
+ nFlags |= SELENG_WAIT_UPEVT;
+ nFlags &= ~(SELENG_IN_SEL);
+ pWin->ReleaseMouse();
+ return TRUE; //auf STARTDRAG-Command-Event warten
+ }
+ if ( eSelMode != SINGLE_SELECTION )
+ {
+ if( !IsAddMode() )
+ pFunctionSet->DeselectAll();
+ else
+ pFunctionSet->DestroyAnchor();
+ nFlags &= (~SELENG_HAS_ANCH); // bHasAnchor = FALSE;
+ }
+ pFunctionSet->SetCursorAtPoint( aPos );
+ // Sonderbehandlung Single-Selection, damit Select+Drag
+ // in einem Zug moeglich ist
+ if (eSelMode == SINGLE_SELECTION && (nFlags & SELENG_DRG_ENAB))
+ nFlags |= SELENG_WAIT_UPEVT;
+ return TRUE;
+ }
+
+ case KEY_SHIFT:
+ if ( eSelMode == SINGLE_SELECTION )
+ {
+ pWin->ReleaseMouse();
+ nFlags &= (~SELENG_IN_SEL);
+ return FALSE;
+ }
+ if ( nFlags & SELENG_ADD_ALW )
+ nFlags |= SELENG_IN_ADD;
+ else
+ nFlags &= (~SELENG_IN_ADD);
+
+ if( !(nFlags & SELENG_HAS_ANCH) )
+ {
+ if ( !(nFlags & SELENG_IN_ADD) )
+ pFunctionSet->DeselectAll();
+ pFunctionSet->CreateAnchor();
+ nFlags |= SELENG_HAS_ANCH;
+ }
+ pFunctionSet->SetCursorAtPoint( aPos );
+ return TRUE;
+
+ case KEY_MOD1:
+ // Control nur bei Mehrfachselektion erlaubt
+ if ( eSelMode != MULTIPLE_SELECTION )
+ {
+ nFlags &= (~SELENG_IN_SEL);
+ pWin->ReleaseMouse();
+ return TRUE; // Mausclick verschlucken
+ }
+ if ( nFlags & SELENG_HAS_ANCH )
+ {
+ // pFunctionSet->CreateCursor();
+ pFunctionSet->DestroyAnchor();
+ nFlags &= (~SELENG_HAS_ANCH);
+ }
+ if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
+ {
+ pFunctionSet->DeselectAtPoint( aPos );
+ pFunctionSet->SetCursorAtPoint( aPos, TRUE );
+ }
+ else
+ {
+ pFunctionSet->SetCursorAtPoint( aPos );
+ }
+ return TRUE;
+
+ case KEY_SHIFT + KEY_MOD1:
+ if ( eSelMode != MULTIPLE_SELECTION )
+ {
+ pWin->ReleaseMouse();
+ nFlags &= (~SELENG_IN_SEL);
+ return FALSE;
+ }
+ nFlags |= SELENG_IN_ADD; //bIsInAddMode = TRUE;
+ if ( !(nFlags & SELENG_HAS_ANCH) )
+ {
+ pFunctionSet->CreateAnchor();
+ nFlags |= SELENG_HAS_ANCH;
+ }
+ pFunctionSet->SetCursorAtPoint( aPos );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::SelMouseButtonUp()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+BOOL SelectionEngine::SelMouseButtonUp( const MouseEvent& /* rMEvt */ )
+{
+ aWTimer.Stop();
+ //DbgOut("Up");
+ if( !pFunctionSet || !pWin )
+ {
+ nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
+ return FALSE;
+ }
+ pWin->ReleaseMouse();
+
+ if( (nFlags & SELENG_WAIT_UPEVT) && !(nFlags & SELENG_CMDEVT) &&
+ eSelMode != SINGLE_SELECTION)
+ {
+ // MouseButtonDown in Sel aber kein CommandEvent eingetrudelt
+ // ==> deselektieren
+ USHORT nModifier = aLastMove.GetModifier() | nLockedMods;
+ if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
+ {
+ if( !(nModifier & KEY_SHIFT) )
+ {
+ pFunctionSet->DestroyAnchor();
+ nFlags &= (~SELENG_HAS_ANCH); // nix Anker
+ }
+ pFunctionSet->DeselectAtPoint( aLastMove.GetPosPixel() );
+ nFlags &= (~SELENG_HAS_ANCH); // nix Anker
+ pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel(), TRUE );
+ }
+ else
+ {
+ pFunctionSet->DeselectAll();
+ nFlags &= (~SELENG_HAS_ANCH); // nix Anker
+ pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel() );
+ }
+ }
+
+ nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
+ return TRUE;
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::SelMouseMove()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+BOOL SelectionEngine::SelMouseMove( const MouseEvent& rMEvt )
+{
+
+ if ( !pFunctionSet || !(nFlags & SELENG_IN_SEL) ||
+ (nFlags & (SELENG_CMDEVT | SELENG_WAIT_UPEVT)) )
+ return FALSE;
+
+ if( !(nFlags & SELENG_EXPANDONMOVE) )
+ return FALSE; // auf DragEvent warten!
+
+ aLastMove = rMEvt;
+ // wenn die Maus ausserhalb der Area steht, dann wird die
+ // Frequenz des SetCursorAtPoint() nur durch den Timer bestimmt
+ if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() ))
+ return TRUE;
+
+
+ aWTimer.Start();
+ if ( eSelMode != SINGLE_SELECTION )
+ {
+ if ( !(nFlags & SELENG_HAS_ANCH) )
+ {
+ pFunctionSet->CreateAnchor();
+ //DbgOut("Move:Creating anchor");
+ nFlags |= SELENG_HAS_ANCH;
+ }
+ }
+
+ //DbgOut("Move:SetCursor");
+ pFunctionSet->SetCursorAtPoint( rMEvt.GetPosPixel() );
+
+ return TRUE;
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::SetWindow()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 10.10.94
+|* Letzte Aenderung OV 10.10.94
+|*
+*************************************************************************/
+
+void SelectionEngine::SetWindow( Window* pNewWin )
+{
+ if( pNewWin != pWin )
+ {
+ if ( pWin && (nFlags & SELENG_IN_SEL) )
+ pWin->ReleaseMouse();
+ pWin = pNewWin;
+ if ( pWin && ( nFlags & SELENG_IN_SEL ) )
+ pWin->CaptureMouse();
+ }
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::Reset()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 07.07.95
+|* Letzte Aenderung OV 07.07.95
+|*
+*************************************************************************/
+
+void SelectionEngine::Reset()
+{
+ aWTimer.Stop();
+ if ( nFlags & SELENG_IN_SEL )
+ pWin->ReleaseMouse();
+ nFlags &= ~(SELENG_HAS_ANCH | SELENG_IN_SEL);
+ nLockedMods = 0;
+}
+
+/*************************************************************************
+|*
+|* SelectionEngine::Command()
+|*
+|* Beschreibung SELENG.SDW
+|* Ersterstellung OV 07.07.95
+|* Letzte Aenderung OV 07.07.95
+|*
+*************************************************************************/
+
+void SelectionEngine::Command( const CommandEvent& rCEvt )
+{
+ // Timer aWTimer ist beim Aufspannen einer Selektion aktiv
+ if ( !pFunctionSet || !pWin || aWTimer.IsActive() )
+ return;
+ aWTimer.Stop();
+ nFlags |= SELENG_CMDEVT;
+ if ( rCEvt.GetCommand() == COMMAND_STARTDRAG )
+ {
+ if ( nFlags & SELENG_DRG_ENAB )
+ {
+ DBG_ASSERT( rCEvt.IsMouseEvent(), "STARTDRAG: Not a MouseEvent" );
+ if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) )
+ {
+ aLastMove = MouseEvent( rCEvt.GetMousePosPixel(),
+ aLastMove.GetClicks(), aLastMove.GetMode(),
+ aLastMove.GetButtons(), aLastMove.GetModifier() );
+ pFunctionSet->BeginDrag();
+ nFlags &= ~(SELENG_CMDEVT|SELENG_WAIT_UPEVT|SELENG_IN_SEL);
+ }
+ else
+ nFlags &= ~SELENG_CMDEVT;
+ }
+ else
+ nFlags &= ~SELENG_CMDEVT;
+ }
+}
diff --git a/vcl/source/window/split.cxx b/vcl/source/window/split.cxx
new file mode 100644
index 000000000000..b4553a4cf8a7
--- /dev/null
+++ b/vcl/source/window/split.cxx
@@ -0,0 +1,806 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/event.hxx>
+#include <vcl/split.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <vcl/gradient.hxx>
+#include <tools/poly.hxx>
+#include <vcl/lineinfo.hxx>
+#include <rtl/instance.hxx>
+#include <vcl/window.h>
+
+namespace
+{
+ struct ImplBlackWall
+ : public rtl::StaticWithInit<Wallpaper, ImplBlackWall> {
+ Wallpaper operator () () {
+ return Wallpaper(COL_BLACK);
+ }
+ };
+ struct ImplWhiteWall
+ : public rtl::StaticWithInit<Wallpaper, ImplWhiteWall> {
+ Wallpaper operator () () {
+ return Wallpaper(COL_LIGHTGRAY);
+ }
+ };
+}
+
+// =======================================================================
+
+void Splitter::ImplInitSplitterData()
+{
+ ImplGetWindowImpl()->mbSplitter = TRUE;
+ mpRefWin = NULL;
+ mnSplitPos = 0;
+ mnLastSplitPos = 0;
+ mnStartSplitPos = 0;
+ mbDragFull = FALSE;
+ mbKbdSplitting = FALSE;
+ mbInKeyEvent = 0;
+ mnKeyboardStepSize = SPLITTER_DEFAULTSTEPSIZE;
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::ImplInit( Window* pParent, WinBits nWinStyle )
+{
+ Window::ImplInit( pParent, nWinStyle, NULL );
+
+ mpRefWin = pParent;
+
+ const StyleSettings& rSettings = GetSettings().GetStyleSettings();
+ long nA = rSettings.GetScrollBarSize();
+ long nB = rSettings.GetSplitSize();
+
+ PointerStyle ePointerStyle;
+
+ if ( nWinStyle & WB_HSCROLL )
+ {
+ ePointerStyle = POINTER_HSPLIT;
+ mbHorzSplit = TRUE;
+ SetSizePixel( Size( nB, nA ) );
+ }
+ else
+ {
+ ePointerStyle = POINTER_VSPLIT;
+ mbHorzSplit = FALSE;
+ SetSizePixel( Size( nA, nB ) );
+ }
+
+ SetPointer( Pointer( ePointerStyle ) );
+
+ if( GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
+ SetBackground( ImplWhiteWall::get() );
+ else
+ SetBackground( ImplBlackWall::get() );
+
+ TaskPaneList *pTList = GetSystemWindow()->GetTaskPaneList();
+ pTList->AddWindow( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::ImplSplitMousePos( Point& rPos )
+{
+ if ( mbHorzSplit )
+ {
+ if ( rPos.X() > maDragRect.Right()-1 )
+ rPos.X() = maDragRect.Right()-1;
+ if ( rPos.X() < maDragRect.Left()+1 )
+ rPos.X() = maDragRect.Left()+1;
+ }
+ else
+ {
+ if ( rPos.Y() > maDragRect.Bottom()-1 )
+ rPos.Y() = maDragRect.Bottom()-1;
+ if ( rPos.Y() < maDragRect.Top()+1 )
+ rPos.Y() = maDragRect.Top()+1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::ImplDrawSplitter()
+{
+ Rectangle aInvRect( maDragRect );
+
+ if ( mbHorzSplit )
+ {
+ aInvRect.Left() = maDragPos.X() - 1;
+ aInvRect.Right() = maDragPos.X() + 1;
+ }
+ else
+ {
+ aInvRect.Top() = maDragPos.Y() - 1;
+ aInvRect.Bottom() = maDragPos.Y() + 1;
+ }
+
+ mpRefWin->InvertTracking( mpRefWin->PixelToLogic(aInvRect), SHOWTRACK_SPLIT );
+}
+
+// -----------------------------------------------------------------------
+
+Splitter::Splitter( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_SPLITTER )
+{
+ ImplInitSplitterData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+Splitter::Splitter( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_SPLITTER )
+{
+ ImplInitSplitterData();
+ rResId.SetRT( RSC_SPLITTER );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+Splitter::~Splitter()
+{
+ TaskPaneList *pTList = GetSystemWindow()->GetTaskPaneList();
+ pTList->RemoveWindow( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::SetKeyboardStepSize( long nStepSize )
+{
+ mnKeyboardStepSize = nStepSize;
+}
+
+// -----------------------------------------------------------------------
+
+long Splitter::GetKeyboardStepSize() const
+{
+ return mnKeyboardStepSize;
+}
+
+// -----------------------------------------------------------------------
+
+Splitter* Splitter::ImplFindSibling()
+{
+ // look for another splitter with the same parent but different orientation
+ Window *pWin = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
+ Splitter *pSplitter = NULL;
+ while( pWin )
+ {
+ if( pWin->ImplIsSplitter() )
+ {
+ pSplitter = (Splitter*) pWin;
+ if( pSplitter != this && IsHorizontal() != pSplitter->IsHorizontal() )
+ return pSplitter;
+ }
+ pWin = pWin->GetWindow( WINDOW_NEXT );
+ }
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Splitter::ImplSplitterActive()
+{
+ // is splitter in document or at scrollbar handle ?
+
+ BOOL bActive = TRUE;
+ const StyleSettings& rSettings = GetSettings().GetStyleSettings();
+ long nA = rSettings.GetScrollBarSize();
+ long nB = rSettings.GetSplitSize();
+
+ Size aSize = GetOutputSize();
+ if ( mbHorzSplit )
+ {
+ if( aSize.Width() == nB && aSize.Height() == nA )
+ bActive = FALSE;
+ }
+ else
+ {
+ if( aSize.Width() == nA && aSize.Height() == nB )
+ bActive = FALSE;
+ }
+ return bActive;
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.GetClicks() == 2 )
+ {
+ if ( mnLastSplitPos != mnSplitPos )
+ {
+ StartSplit();
+ Point aPos = rMEvt.GetPosPixel();
+ if ( mbHorzSplit )
+ aPos.X() = mnLastSplitPos;
+ else
+ aPos.Y() = mnLastSplitPos;
+ ImplSplitMousePos( aPos );
+ Splitting( aPos );
+ ImplSplitMousePos( aPos );
+ long nTemp = mnSplitPos;
+ if ( mbHorzSplit )
+ SetSplitPosPixel( aPos.X() );
+ else
+ SetSplitPosPixel( aPos.Y() );
+ mnLastSplitPos = nTemp;
+ Split();
+ EndSplit();
+ }
+ }
+ else
+ StartDrag();
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::Tracking( const TrackingEvent& rTEvt )
+{
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ if ( !mbDragFull )
+ ImplDrawSplitter();
+
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ long nNewPos;
+ if ( mbHorzSplit )
+ nNewPos = maDragPos.X();
+ else
+ nNewPos = maDragPos.Y();
+ if ( nNewPos != mnStartSplitPos )
+ {
+ SetSplitPosPixel( nNewPos );
+ mnLastSplitPos = 0;
+ Split();
+ }
+ EndSplit();
+ }
+ else if ( mbDragFull )
+ {
+ SetSplitPosPixel( mnStartSplitPos );
+ Split();
+ }
+ mnStartSplitPos = 0;
+ }
+ else
+ {
+ //Point aNewPos = mpRefWin->ScreenToOutputPixel( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
+ Point aNewPos = mpRefWin->NormalizedScreenToOutputPixel( OutputToNormalizedScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
+ ImplSplitMousePos( aNewPos );
+ Splitting( aNewPos );
+ ImplSplitMousePos( aNewPos );
+
+ if ( mbHorzSplit )
+ {
+ if ( aNewPos.X() == maDragPos.X() )
+ return;
+ }
+ else
+ {
+ if ( aNewPos.Y() == maDragPos.Y() )
+ return;
+ }
+
+ if ( mbDragFull )
+ {
+ maDragPos = aNewPos;
+ long nNewPos;
+ if ( mbHorzSplit )
+ nNewPos = maDragPos.X();
+ else
+ nNewPos = maDragPos.Y();
+ if ( nNewPos != mnSplitPos )
+ {
+ SetSplitPosPixel( nNewPos );
+ mnLastSplitPos = 0;
+ Split();
+ }
+
+ GetParent()->Update();
+ }
+ else
+ {
+ ImplDrawSplitter();
+ maDragPos = aNewPos;
+ ImplDrawSplitter();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::ImplKbdTracking( KeyCode aKeyCode )
+{
+ USHORT nCode = aKeyCode.GetCode();
+ if ( nCode == KEY_ESCAPE || nCode == KEY_RETURN )
+ {
+ if( !mbKbdSplitting )
+ return;
+ else
+ mbKbdSplitting = FALSE;
+
+ if ( nCode != KEY_ESCAPE )
+ {
+ long nNewPos;
+ if ( mbHorzSplit )
+ nNewPos = maDragPos.X();
+ else
+ nNewPos = maDragPos.Y();
+ if ( nNewPos != mnStartSplitPos )
+ {
+ SetSplitPosPixel( nNewPos );
+ mnLastSplitPos = 0;
+ Split();
+ }
+ }
+ else
+ {
+ SetSplitPosPixel( mnStartSplitPos );
+ Split();
+ EndSplit();
+ }
+ mnStartSplitPos = 0;
+ }
+ else
+ {
+ Point aNewPos;
+ Size aSize = mpRefWin->GetOutputSize();
+ Point aPos = GetPosPixel();
+ // depending on the position calc allows continous moves or snaps to row/columns
+ // continous mode is active when position is at the origin or end of the splitter
+ // otherwise snap mode is active
+ // default here is snap, holding shift sets continous mode
+ if( mbHorzSplit )
+ aNewPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aKeyCode.IsShift() ? 0 : aSize.Height()/2);
+ else
+ aNewPos = Point( aKeyCode.IsShift() ? 0 : aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos );
+
+ Point aOldWindowPos = GetPosPixel();
+
+ int maxiter = 500; // avoid endless loop
+ int delta=0;
+ int delta_step = mbHorzSplit ? aSize.Width()/10 : aSize.Height()/10;
+
+ // use the specified step size if it was set
+ if( mnKeyboardStepSize != SPLITTER_DEFAULTSTEPSIZE )
+ delta_step = mnKeyboardStepSize;
+
+ while( maxiter-- && aOldWindowPos == GetPosPixel() )
+ {
+ // inc/dec position until application performs changes
+ // thus a single key press really moves the splitter
+ if( aKeyCode.IsShift() )
+ delta++;
+ else
+ delta += delta_step;
+
+ switch( nCode )
+ {
+ case KEY_LEFT:
+ aNewPos.X()-=delta;
+ break;
+ case KEY_RIGHT:
+ aNewPos.X()+=delta;
+ break;
+ case KEY_UP:
+ aNewPos.Y()-=delta;
+ break;
+ case KEY_DOWN:
+ aNewPos.Y()+=delta;
+ break;
+ default:
+ maxiter = 0; // leave loop
+ break;
+ }
+ ImplSplitMousePos( aNewPos );
+ Splitting( aNewPos );
+ ImplSplitMousePos( aNewPos );
+
+ if ( mbHorzSplit )
+ {
+ if ( aNewPos.X() == maDragPos.X() )
+ continue;
+ }
+ else
+ {
+ if ( aNewPos.Y() == maDragPos.Y() )
+ continue;
+ }
+
+ maDragPos = aNewPos;
+ long nNewPos;
+ if ( mbHorzSplit )
+ nNewPos = maDragPos.X();
+ else
+ nNewPos = maDragPos.Y();
+ if ( nNewPos != mnSplitPos )
+ {
+ SetSplitPosPixel( nNewPos );
+ mnLastSplitPos = 0;
+ Split();
+ }
+ GetParent()->Update();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::StartSplit()
+{
+ maStartSplitHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::Split()
+{
+ maSplitHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::EndSplit()
+{
+ if ( maEndSplitHdl.IsSet() )
+ maEndSplitHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::Splitting( Point& /* rSplitPos */ )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::SetDragRectPixel( const Rectangle& rDragRect, Window* _pRefWin )
+{
+ maDragRect = rDragRect;
+ if ( !_pRefWin )
+ mpRefWin = GetParent();
+ else
+ mpRefWin = _pRefWin;
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::SetSplitPosPixel( long nNewPos )
+{
+ mnSplitPos = nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::SetLastSplitPosPixel( long nNewPos )
+{
+ mnLastSplitPos = nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::StartDrag()
+{
+ if ( IsTracking() )
+ return;
+
+ StartSplit();
+
+ // Tracking starten
+ StartTracking();
+
+ // Start-Positon ermitteln
+ maDragPos = mpRefWin->GetPointerPosPixel();
+ ImplSplitMousePos( maDragPos );
+ Splitting( maDragPos );
+ ImplSplitMousePos( maDragPos );
+ if ( mbHorzSplit )
+ mnStartSplitPos = maDragPos.X();
+ else
+ mnStartSplitPos = maDragPos.Y();
+
+ mbDragFull = (Application::GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT) != 0;
+ if ( !mbDragFull )
+ ImplDrawSplitter();
+}
+
+
+// -----------------------------------------------------------------------
+
+void Splitter::ImplStartKbdSplitting()
+{
+ if( mbKbdSplitting )
+ return;
+
+ mbKbdSplitting = TRUE;
+
+ StartSplit();
+
+ // determine start position
+ // because we have no mouse position we take either the position
+ // of the splitter window or the last split position
+ // the other coordinate is just the center of the reference window
+ Size aSize = mpRefWin->GetOutputSize();
+ Point aPos = GetPosPixel();
+ if( mbHorzSplit )
+ maDragPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aSize.Height()/2 );
+ else
+ maDragPos = Point( aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos );
+ ImplSplitMousePos( maDragPos );
+ Splitting( maDragPos );
+ ImplSplitMousePos( maDragPos );
+ if ( mbHorzSplit )
+ mnStartSplitPos = maDragPos.X();
+ else
+ mnStartSplitPos = maDragPos.Y();
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::ImplRestoreSplitter()
+{
+ // set splitter in the center of the ref window
+ StartSplit();
+ Size aSize = mpRefWin->GetOutputSize();
+ Point aPos = Point( aSize.Width()/2 , aSize.Height()/2);
+ if ( mnLastSplitPos != mnSplitPos && mnLastSplitPos > 5 )
+ {
+ // restore last pos if it was a useful position (>5)
+ if ( mbHorzSplit )
+ aPos.X() = mnLastSplitPos;
+ else
+ aPos.Y() = mnLastSplitPos;
+ }
+
+ ImplSplitMousePos( aPos );
+ Splitting( aPos );
+ ImplSplitMousePos( aPos );
+ long nTemp = mnSplitPos;
+ if ( mbHorzSplit )
+ SetSplitPosPixel( aPos.X() );
+ else
+ SetSplitPosPixel( aPos.Y() );
+ mnLastSplitPos = nTemp;
+ Split();
+ EndSplit();
+}
+
+
+// -----------------------------------------------------------------------
+
+void Splitter::GetFocus()
+{
+ if( !ImplSplitterActive() )
+ ImplRestoreSplitter();
+
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::LoseFocus()
+{
+ if( mbKbdSplitting )
+ {
+ KeyCode aReturnKey( KEY_RETURN );
+ ImplKbdTracking( aReturnKey );
+ mbKbdSplitting = FALSE;
+ }
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::KeyInput( const KeyEvent& rKEvt )
+{
+ if( mbInKeyEvent )
+ return;
+
+ mbInKeyEvent = 1;
+
+ Splitter *pSibling = ImplFindSibling();
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+ USHORT nCode = aKeyCode.GetCode();
+ switch ( nCode )
+ {
+ case KEY_UP:
+ case KEY_DOWN:
+ if( !mbHorzSplit )
+ {
+ ImplStartKbdSplitting();
+ ImplKbdTracking( aKeyCode );
+ }
+ else
+ {
+ if( pSibling )
+ {
+ pSibling->GrabFocus();
+ pSibling->KeyInput( rKEvt );
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ case KEY_LEFT:
+ if( mbHorzSplit )
+ {
+ ImplStartKbdSplitting();
+ ImplKbdTracking( aKeyCode );
+ }
+ else
+ {
+ if( pSibling )
+ {
+ pSibling->GrabFocus();
+ pSibling->KeyInput( rKEvt );
+ }
+ }
+ break;
+
+ case KEY_DELETE:
+ if( ImplSplitterActive() )
+ {
+ if( mbKbdSplitting )
+ {
+ KeyCode aKey( KEY_ESCAPE );
+ ImplKbdTracking( aKey );
+ }
+
+ StartSplit();
+ Point aPos;
+ if ( mbHorzSplit )
+ aPos.X() = 0;
+ else
+ aPos.Y() = 0;
+ ImplSplitMousePos( aPos );
+ Splitting( aPos );
+ ImplSplitMousePos( aPos );
+ long nTemp = mnSplitPos;
+ if ( mbHorzSplit )
+ SetSplitPosPixel( aPos.X() );
+ else
+ SetSplitPosPixel( aPos.Y() );
+ mnLastSplitPos = nTemp;
+ Split();
+ EndSplit();
+
+ // Shift-Del deletes both splitters
+ if( aKeyCode.IsShift() && pSibling )
+ pSibling->KeyInput( rKEvt );
+
+ GrabFocusToDocument();
+ }
+ break;
+
+ case KEY_ESCAPE:
+ if( mbKbdSplitting )
+ ImplKbdTracking( aKeyCode );
+ else
+ GrabFocusToDocument();
+ break;
+
+ case KEY_RETURN:
+ ImplKbdTracking( aKeyCode );
+ GrabFocusToDocument();
+ break;
+ default: // let any key input fix the splitter
+ Window::KeyInput( rKEvt );
+ GrabFocusToDocument();
+ break;
+ }
+ mbInKeyEvent = 0;
+}
+
+// -----------------------------------------------------------------------
+
+long Splitter::Notify( NotifyEvent& rNEvt )
+{
+ return Window::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+ if( rDCEvt.GetType() == DATACHANGED_SETTINGS )
+ {
+ Color oldFaceColor = ((AllSettings *) rDCEvt.GetData())->GetStyleSettings().GetFaceColor();
+ Color newFaceColor = Application::GetSettings().GetStyleSettings().GetFaceColor();
+ if( oldFaceColor.IsDark() != newFaceColor.IsDark() )
+ {
+ if( newFaceColor.IsDark() )
+ SetBackground( ImplWhiteWall::get() );
+ else
+ SetBackground( ImplBlackWall::get() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Splitter::Paint( const Rectangle& rPaintRect )
+{
+ if( HasFocus() || mbKbdSplitting )
+ {
+ Color oldFillCol = GetFillColor();
+ Color oldLineCol = GetLineColor();
+
+ SetLineColor();
+ SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
+ DrawRect( rPaintRect );
+
+ Color aSelectionBorderCol( GetSettings().GetStyleSettings().GetActiveColor() );
+ SetFillColor( aSelectionBorderCol );
+ SetLineColor();
+
+ Polygon aPoly( rPaintRect );
+ PolyPolygon aPolyPoly( aPoly );
+ DrawTransparent( aPolyPoly, 85 );
+
+ SetLineColor( aSelectionBorderCol );
+ SetFillColor();
+
+ if( mbKbdSplitting )
+ {
+ LineInfo aInfo( LINE_DASH );
+ //aInfo.SetDashLen( 2 );
+ //aInfo.SetDashCount( 1 );
+ aInfo.SetDistance( 1 );
+ aInfo.SetDotLen( 2 );
+ aInfo.SetDotCount( 1 );
+
+ DrawPolyLine( aPoly, aInfo );
+ }
+ else
+ DrawRect( rPaintRect );
+
+ SetFillColor( oldFillCol);
+ SetLineColor( oldLineCol);
+ }
+ else
+ {
+ Window::Paint( rPaintRect );
+ }
+}
diff --git a/vcl/source/window/splitwin.cxx b/vcl/source/window/splitwin.cxx
new file mode 100644
index 000000000000..689c56cbe619
--- /dev/null
+++ b/vcl/source/window/splitwin.cxx
@@ -0,0 +1,3877 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <tools/list.hxx>
+#include <tools/debug.hxx>
+#include <tools/rcid.h>
+#include <vcl/event.hxx>
+#include <vcl/wall.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/symbol.hxx>
+#ifndef _SV_SVIDS_HRC
+#include <vcl/svids.hrc>
+#endif
+#include <vcl/image.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/help.hxx>
+#include <vcl/splitwin.hxx>
+
+
+
+// =======================================================================
+
+// Achtung: Darf keine Objekte enthalten, da mit memmove/memcpy gearbeitet wird
+struct ImplSplitItem
+{
+ long mnSize;
+ long mnPixSize;
+ long mnLeft;
+ long mnTop;
+ long mnWidth;
+ long mnHeight;
+ long mnSplitPos;
+ long mnSplitSize;
+ long mnOldSplitPos;
+ long mnOldSplitSize;
+ long mnOldWidth;
+ long mnOldHeight;
+ ImplSplitSet* mpSet;
+ Window* mpWindow;
+ Window* mpOrgParent;
+ USHORT mnId;
+ SplitWindowItemBits mnBits;
+ BOOL mbFixed;
+ BOOL mbSubSize;
+};
+
+struct ImplSplitSet
+{
+ ImplSplitItem* mpItems;
+ Wallpaper* mpWallpaper;
+ Bitmap* mpBitmap;
+ long mnLastSize;
+ long mnSplitSize;
+ USHORT mnItems;
+ USHORT mnId;
+ BOOL mbCalcPix;
+};
+
+#define SPLITWIN_SPLITSIZE 3
+#define SPLITWIN_SPLITSIZEEX 4
+#define SPLITWIN_SPLITSIZEEXLN 6
+#define SPLITWIN_SPLITSIZEAUTOHIDE 36
+#define SPLITWIN_SPLITSIZEFADE 36
+
+#define SPLIT_HORZ ((USHORT)0x0001)
+#define SPLIT_VERT ((USHORT)0x0002)
+#define SPLIT_WINDOW ((USHORT)0x0004)
+#define SPLIT_NOSPLIT ((USHORT)0x8000)
+
+// -----------------------------------------------------------------------
+
+DECLARE_LIST( ImplSplitList, SplitWindow* )
+
+// =======================================================================
+
+static void ImplCalcBorder( WindowAlign eAlign, BOOL bNoAlign,
+ long& rLeft, long& rTop,
+ long& rRight, long& rBottom )
+{
+ if ( bNoAlign )
+ {
+ rLeft = 2;
+ rTop = 2;
+ rRight = 2;
+ rBottom = 2;
+ }
+ else
+ {
+ if ( eAlign == WINDOWALIGN_TOP )
+ {
+ rLeft = 2;
+ rTop = 2;
+ rRight = 2;
+ rBottom = 0;
+ }
+ else if ( eAlign == WINDOWALIGN_LEFT )
+ {
+ rLeft = 2;
+ rTop = 2;
+ rRight = 0;
+ rBottom = 2;
+ }
+ else if ( eAlign == WINDOWALIGN_BOTTOM )
+ {
+ rLeft = 2;
+ rTop = 0;
+ rRight = 2;
+ rBottom = 2;
+ }
+ else
+ {
+ rLeft = 0;
+ rTop = 2;
+ rRight = 2;
+ rBottom = 2;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawBorder( SplitWindow* pWin )
+{
+ const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
+ long nDX = pWin->mnDX;
+ long nDY = pWin->mnDY;
+
+ if ( pWin->mbNoAlign )
+ {
+ DecorationView aDecoView( pWin );
+ Point aTmpPoint;
+ Rectangle aRect( aTmpPoint, Size( nDX, nDY ) );
+ aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN );
+ }
+ else
+ {/*
+ if ( pWin->meAlign == WINDOWALIGN_BOTTOM )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ else
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 0, 1 ), Point( nDX-1, 1 ) );
+ if ( (pWin->meAlign == WINDOWALIGN_LEFT) || (pWin->meAlign == WINDOWALIGN_RIGHT) )
+ {
+ if ( pWin->meAlign == WINDOWALIGN_LEFT )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ else
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ }
+ }*/
+ if ( pWin->meAlign == WINDOWALIGN_BOTTOM )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
+ pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) );
+ pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) );
+
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) );
+ pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
+ }
+ else if ( pWin->meAlign == WINDOWALIGN_TOP )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) );
+ pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) );
+ pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-1 ) );
+
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 1, 1 ), Point( nDX-3, 1 ) );
+ pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-1 ) );
+ pWin->DrawLine( Point( nDX-1, 1 ), Point( nDX-1, nDY-1 ) );
+ }
+ else if ( pWin->meAlign == WINDOWALIGN_LEFT )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) );
+ pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
+
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 1, 1 ), Point( nDX-1, 1 ) );
+ pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) );
+ pWin->DrawLine( Point( 1, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ else
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, 0 ), Point( nDX-2, 0 ) );
+ pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) );
+
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 0, 1 ), Point( nDX-3, 1 ) );
+ pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawBorderLine( SplitWindow* pWin )
+{
+ if ( pWin->mbFadeOut || pWin->mbAutoHide )
+ {
+ const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
+ long nDX = pWin->mnDX;
+ long nDY = pWin->mnDY;
+
+ if ( pWin->meAlign == WINDOWALIGN_LEFT )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, 0 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, nDY-3 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN, nDY-4 ) );
+ }
+ else if ( pWin->meAlign == WINDOWALIGN_RIGHT )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( SPLITWIN_SPLITSIZEEXLN-1, 0 ), Point( SPLITWIN_SPLITSIZEEXLN-1, nDY-3 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( SPLITWIN_SPLITSIZEEXLN, 1 ), Point( SPLITWIN_SPLITSIZEEXLN, nDY-4 ) );
+ }
+ else if ( pWin->meAlign == WINDOWALIGN_TOP )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-3, nDY-SPLITWIN_SPLITSIZEEXLN-1 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 1, nDY-SPLITWIN_SPLITSIZEEXLN ), Point( nDX-4, nDY-SPLITWIN_SPLITSIZEEXLN ) );
+ }
+ else if ( pWin->meAlign == WINDOWALIGN_BOTTOM )
+ {
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-3, SPLITWIN_SPLITSIZEEXLN-1 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 1, SPLITWIN_SPLITSIZEEXLN ), Point( nDX-4, SPLITWIN_SPLITSIZEEXLN ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static ImplSplitSet* ImplFindSet( ImplSplitSet* pSet, USHORT nId )
+{
+ if ( pSet->mnId == nId )
+ return pSet;
+
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnId == nId )
+ return pItems[i].mpSet;
+ }
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet )
+ {
+ ImplSplitSet* pFindSet = ImplFindSet( pItems[i].mpSet, nId );
+ if ( pFindSet )
+ return pFindSet;
+ }
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplSplitSet* ImplFindItem( ImplSplitSet* pSet, USHORT nId, USHORT& rPos )
+{
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnId == nId )
+ {
+ rPos = i;
+ return pSet;
+ }
+ }
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet )
+ {
+ ImplSplitSet* pFindSet = ImplFindItem( pItems[i].mpSet, nId, rPos );
+ if ( pFindSet )
+ return pFindSet;
+ }
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplFindItem( ImplSplitSet* pSet, Window* pWindow )
+{
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpWindow == pWindow )
+ return pItems[i].mnId;
+ else
+ {
+ if ( pItems[i].mpSet )
+ {
+ USHORT nId = ImplFindItem( pItems[i].mpSet, pWindow );
+ if ( nId )
+ return nId;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplFindItem( ImplSplitSet* pSet, const Point& rPos,
+ BOOL bRows, BOOL bDown = TRUE )
+{
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnWidth && pItems[i].mnHeight )
+ {
+ // Wegen ICC auftrennen
+ Point aPoint( pItems[i].mnLeft, pItems[i].mnTop );
+ Size aSize( pItems[i].mnWidth, pItems[i].mnHeight );
+ Rectangle aRect( aPoint, aSize );
+ if ( bRows )
+ {
+ if ( bDown )
+ aRect.Bottom() += pSet->mnSplitSize;
+ else
+ aRect.Top() -= pSet->mnSplitSize;
+ }
+ else
+ {
+ if ( bDown )
+ aRect.Right() += pSet->mnSplitSize;
+ else
+ aRect.Left() -= pSet->mnSplitSize;
+ }
+
+ if ( aRect.IsInside( rPos ) )
+ {
+ if ( pItems[i].mpSet && pItems[i].mpSet->mpItems )
+ {
+ return ImplFindItem( pItems[i].mpSet, rPos,
+ ((pItems[i].mnBits & SWIB_COLSET) == 0) );
+ }
+ else
+ return pItems[i].mnId;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDeleteSet( ImplSplitSet* pSet )
+{
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet )
+ ImplDeleteSet( pItems[i].mpSet );
+ }
+
+ if ( pSet->mpWallpaper )
+ delete pSet->mpWallpaper;
+
+ if ( pSet->mpBitmap )
+ delete pSet->mpBitmap;
+
+ delete [] pItems;
+ delete pSet;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSetSplitSize( ImplSplitSet* pSet, long nNewSize )
+{
+ pSet->mnSplitSize = nNewSize;
+ for ( USHORT i = 0; i < pSet->mnItems; i++ )
+ {
+ if ( pSet->mpItems[i].mpSet )
+ ImplSetSplitSize( pSet->mpItems[i].mpSet, nNewSize );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCalcSet( ImplSplitSet* pSet,
+ long nSetLeft, long nSetTop,
+ long nSetWidth, long nSetHeight,
+ BOOL bRows, BOOL bDown = TRUE )
+{
+ if ( !pSet->mpItems )
+ return;
+
+ USHORT i;
+ USHORT j;
+ USHORT nMins;
+ USHORT nCalcItems;
+ USHORT nItems = pSet->mnItems;
+ USHORT nVisItems;
+ USHORT nAbsItems;
+ long nCalcSize;
+ long nSizeDelta;
+ long nCurSize;
+ long nSizeWinSize;
+ long nNewSizeWinSize;
+ long nTemp;
+ long nTempErr;
+ long nErrorSum;
+ long nCurSizeDelta;
+ long nPos;
+ long nMaxPos;
+ long* pSize;
+ ImplSplitItem* pItems = pSet->mpItems;
+ BOOL bEmpty;
+
+ // Anzahl sichtbarer Items ermitteln
+ nVisItems = 0;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( !(pItems[i].mnBits & SWIB_INVISIBLE) )
+ nVisItems++;
+ }
+
+ // Groessen berechnen
+ if ( bRows )
+ nCalcSize = nSetHeight;
+ else
+ nCalcSize = nSetWidth;
+ nCalcSize -= (nVisItems-1)*pSet->mnSplitSize;
+ nCurSize = 0;
+ if ( pSet->mbCalcPix || (pSet->mnLastSize != nCalcSize) )
+ {
+ long nPercentFactor = 10;
+ long nRelCount = 0;
+ long nPercent = 0;
+ long nRelPercent = 0;
+ long nAbsSize = 0;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( !(pItems[i].mnBits & SWIB_INVISIBLE) )
+ {
+ if ( pItems[i].mnBits & SWIB_RELATIVESIZE )
+ nRelCount += pItems[i].mnSize;
+ else if ( pItems[i].mnBits & SWIB_PERCENTSIZE )
+ nPercent += pItems[i].mnSize;
+ else
+ nAbsSize += pItems[i].mnSize;
+ }
+ }
+ // Relative-Werte auf prozentual mappen (Percent bei uns 10tel Prozent)
+ nPercent *= nPercentFactor;
+ if ( nRelCount )
+ {
+ long nRelPercentBase = 1000;
+ while ( (nRelCount > nRelPercentBase) && (nPercentFactor < 100000) )
+ {
+ nRelPercentBase *= 10;
+ nPercentFactor *= 10;
+ }
+ if ( nPercent < nRelPercentBase )
+ {
+ nRelPercent = (nRelPercentBase-nPercent)/nRelCount;
+ nPercent += nRelPercent*nRelCount;
+ }
+ else
+ nRelPercent = 0;
+ }
+ if ( !nPercent )
+ nPercent = 1;
+ nSizeDelta = nCalcSize-nAbsSize;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnBits & SWIB_INVISIBLE )
+ pItems[i].mnPixSize = 0;
+ else if ( pItems[i].mnBits & SWIB_RELATIVESIZE )
+ {
+ if ( nSizeDelta <= 0 )
+ pItems[i].mnPixSize = 0;
+ else
+ pItems[i].mnPixSize = (nSizeDelta*pItems[i].mnSize*nRelPercent)/nPercent;
+ }
+ else if ( pItems[i].mnBits & SWIB_PERCENTSIZE )
+ {
+ if ( nSizeDelta <= 0 )
+ pItems[i].mnPixSize = 0;
+ else
+ pItems[i].mnPixSize = (nSizeDelta*pItems[i].mnSize*nPercentFactor)/nPercent;
+ }
+ else
+ pItems[i].mnPixSize = pItems[i].mnSize;
+ nCurSize += pItems[i].mnPixSize;
+ }
+
+ pSet->mbCalcPix = FALSE;
+ pSet->mnLastSize = nCalcSize;
+
+ // Fenster einpassen
+ nSizeDelta = nCalcSize-nCurSize;
+ if ( nSizeDelta )
+ {
+ nAbsItems = 0;
+ nSizeWinSize = 0;
+ nNewSizeWinSize = 0;
+
+ // Zuerst die absoluten Items relativ resizen
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( !(pItems[i].mnBits & SWIB_INVISIBLE) )
+ {
+ if ( !(pItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE)) )
+ {
+ nAbsItems++;
+ nSizeWinSize += pItems[i].mnPixSize;
+ }
+ }
+ }
+ // Rundungsfehler werden hier nicht ausgelichen
+ if ( (nAbsItems < (USHORT)(Abs( nSizeDelta ))) && nSizeWinSize )
+ {
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( !(pItems[i].mnBits & SWIB_INVISIBLE) )
+ {
+ if ( !(pItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE)) )
+ {
+ pItems[i].mnPixSize += (nSizeDelta*pItems[i].mnPixSize)/nSizeWinSize;
+ nNewSizeWinSize += pItems[i].mnPixSize;
+ }
+ }
+ }
+ nSizeDelta -= nNewSizeWinSize-nSizeWinSize;
+ }
+
+ // Jetzt die Rundunsfehler ausgleichen
+ j = 0;
+ nMins = 0;
+ while ( nSizeDelta && (nItems != nMins) )
+ {
+ // Feststellen, welche Items berechnet werden duerfen
+ nCalcItems = 0;
+ while ( !nCalcItems )
+ {
+ for ( i = 0; i < nItems; i++ )
+ {
+ pItems[i].mbSubSize = FALSE;
+
+ if ( j >= 2 )
+ pItems[i].mbSubSize = TRUE;
+ else
+ {
+ if ( !(pItems[i].mnBits & SWIB_INVISIBLE) )
+ {
+ if ( (nSizeDelta > 0) || pItems[i].mnPixSize )
+ {
+ if ( j >= 1 )
+ pItems[i].mbSubSize = TRUE;
+ else
+ {
+ if ( (j == 0) && (pItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE)) )
+ pItems[i].mbSubSize = TRUE;
+ }
+ }
+ }
+ }
+
+ if ( pItems[i].mbSubSize )
+ nCalcItems++;
+ }
+
+ j++;
+ }
+
+ // Groessen von den einzelnen Items abziehen
+ nErrorSum = nSizeDelta % nCalcItems;
+ nCurSizeDelta = nSizeDelta / nCalcItems;
+ nMins = 0;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnBits & SWIB_INVISIBLE )
+ nMins++;
+ else if ( pItems[i].mbSubSize )
+ {
+ pSize = &(pItems[i].mnPixSize);
+
+ if ( nErrorSum )
+ {
+ if ( nErrorSum < 0 )
+ nTempErr = -1;
+ else
+ nTempErr = 1;
+ }
+ else
+ nTempErr = 0;
+
+ if ( (*pSize+nCurSizeDelta+nTempErr) <= 0 )
+ {
+ nTemp = *pSize;
+ if ( nTemp )
+ {
+ *pSize -= nTemp;
+ nSizeDelta += nTemp;
+ }
+ nMins++;
+ }
+ else
+ {
+ *pSize += nCurSizeDelta;
+ nSizeDelta -= nCurSizeDelta;
+ if ( nTempErr && (*pSize || (nTempErr > 0)) )
+ {
+ *pSize += nTempErr;
+ nSizeDelta -= nTempErr;
+ nErrorSum -= nTempErr;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( !(pItems[i].mnBits & SWIB_INVISIBLE) )
+ nCurSize += pItems[i].mnPixSize;
+ }
+ }
+
+ // Maximale Groesse berechnen
+ if ( bRows )
+ {
+ nPos = nSetTop;
+ if ( !bDown )
+ nMaxPos = nSetTop-nSetHeight;
+ else
+ nMaxPos = nSetTop+nSetHeight;
+ }
+ else
+ {
+ nPos = nSetLeft;
+ if ( !bDown )
+ nMaxPos = nSetLeft-nSetWidth;
+ else
+ nMaxPos = nSetLeft+nSetWidth;
+ }
+
+ // Fenster anordnen und Werte anpassen
+ for ( i = 0; i < nItems; i++ )
+ {
+ pItems[i].mnOldSplitPos = pItems[i].mnSplitPos;
+ pItems[i].mnOldSplitSize = pItems[i].mnSplitSize;
+ pItems[i].mnOldWidth = pItems[i].mnWidth;
+ pItems[i].mnOldHeight = pItems[i].mnHeight;
+
+ if ( pItems[i].mnBits & SWIB_INVISIBLE )
+ bEmpty = TRUE;
+ else
+ {
+ bEmpty = FALSE;
+ if ( bDown )
+ {
+ if ( nPos+pItems[i].mnPixSize > nMaxPos )
+ bEmpty = TRUE;
+ }
+ else
+ {
+ nPos -= pItems[i].mnPixSize;
+ if ( nPos < nMaxPos )
+ bEmpty = TRUE;
+ }
+ }
+
+ if ( bEmpty )
+ {
+ pItems[i].mnWidth = 0;
+ pItems[i].mnHeight = 0;
+ pItems[i].mnSplitSize = 0;
+ }
+ else
+ {
+ if ( bRows )
+ {
+ pItems[i].mnLeft = nSetLeft;
+ pItems[i].mnTop = nPos;
+ pItems[i].mnWidth = nSetWidth;
+ pItems[i].mnHeight = pItems[i].mnPixSize;
+ }
+ else
+ {
+ pItems[i].mnLeft = nPos;
+ pItems[i].mnTop = nSetTop;
+ pItems[i].mnWidth = pItems[i].mnPixSize;
+ pItems[i].mnHeight = nSetHeight;
+ }
+
+ if ( i > nItems-1 )
+ pItems[i].mnSplitSize = 0;
+ else
+ {
+ pItems[i].mnSplitSize = pSet->mnSplitSize;
+ if ( bDown )
+ {
+ pItems[i].mnSplitPos = nPos+pItems[i].mnPixSize;
+ if ( pItems[i].mnSplitPos+pItems[i].mnSplitSize > nMaxPos )
+ pItems[i].mnSplitSize = nMaxPos-pItems[i].mnSplitPos;
+ }
+ else
+ {
+ pItems[i].mnSplitPos = nPos-pSet->mnSplitSize;
+ if ( pItems[i].mnSplitPos < nMaxPos )
+ pItems[i].mnSplitSize = pItems[i].mnSplitPos+pSet->mnSplitSize-nMaxPos;
+ }
+ }
+ }
+
+ if ( !(pItems[i].mnBits & SWIB_INVISIBLE) )
+ {
+ if ( !bDown )
+ nPos -= pSet->mnSplitSize;
+ else
+ nPos += pItems[i].mnPixSize+pSet->mnSplitSize;
+ }
+ }
+
+ // Sub-Set's berechnen
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet && pItems[i].mnWidth && pItems[i].mnHeight )
+ {
+ ImplCalcSet( pItems[i].mpSet,
+ pItems[i].mnLeft, pItems[i].mnTop,
+ pItems[i].mnWidth, pItems[i].mnHeight,
+ ((pItems[i].mnBits & SWIB_COLSET) == 0) );
+ }
+ }
+
+ // Fixed setzen
+ for ( i = 0; i < nItems; i++ )
+ {
+ pItems[i].mbFixed = FALSE;
+ if ( pItems[i].mnBits & SWIB_FIXED )
+ pItems[i].mbFixed = TRUE;
+ else
+ {
+ // Wenn Child-Set vorhanden, ist dieses Item auch Fixed, wenn
+ // ein Child fixed ist
+ if ( pItems[i].mpSet )
+ {
+ for ( j = 0; j < pItems[i].mpSet->mnItems; j++ )
+ {
+ if ( pItems[i].mpSet->mpItems[j].mbFixed )
+ {
+ pItems[i].mbFixed = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplCalcSet2( SplitWindow* pWindow, ImplSplitSet* pSet, BOOL bHide,
+ BOOL bRows, BOOL /*bDown*/ )
+{
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ if ( pWindow->IsReallyVisible() && pWindow->IsUpdateMode() && pWindow->mbInvalidate )
+ {
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnSplitSize )
+ {
+ // Evt. alles invalidieren oder nur einen kleinen Teil
+ if ( (pItems[i].mnOldSplitPos != pItems[i].mnSplitPos) ||
+ (pItems[i].mnOldSplitSize != pItems[i].mnSplitSize) ||
+ (pItems[i].mnOldWidth != pItems[i].mnWidth) ||
+ (pItems[i].mnOldHeight != pItems[i].mnHeight) )
+ {
+ Rectangle aRect;
+
+ // Old Rect invalidieren
+ if ( bRows )
+ {
+ aRect.Left() = pItems[i].mnLeft;
+ aRect.Right() = pItems[i].mnLeft+pItems[i].mnOldWidth-1;
+ aRect.Top() = pItems[i].mnOldSplitPos;
+ aRect.Bottom() = aRect.Top() + pItems[i].mnOldSplitSize;
+ }
+ else
+ {
+ aRect.Top() = pItems[i].mnTop;
+ aRect.Bottom() = pItems[i].mnTop+pItems[i].mnOldHeight-1;
+ aRect.Left() = pItems[i].mnOldSplitPos;
+ aRect.Right() = aRect.Left() + pItems[i].mnOldSplitSize;
+ }
+ pWindow->Invalidate( aRect );
+ // New Rect invalidieren
+ if ( bRows )
+ {
+ aRect.Left() = pItems[i].mnLeft;
+ aRect.Right() = pItems[i].mnLeft+pItems[i].mnWidth-1;
+ aRect.Top() = pItems[i].mnSplitPos;
+ aRect.Bottom() = aRect.Top() + pItems[i].mnSplitSize;
+ }
+ else
+ {
+ aRect.Top() = pItems[i].mnTop;
+ aRect.Bottom() = pItems[i].mnTop+pItems[i].mnHeight-1;
+ aRect.Left() = pItems[i].mnSplitPos;
+ aRect.Right() = aRect.Left() + pItems[i].mnSplitSize;
+ }
+ pWindow->Invalidate( aRect );
+
+ // Leere Sets komplett invalidieren, da diese Flaechen
+ // nicht von Fenstern ueberladen werden
+ if ( pItems[i].mpSet && !pItems[i].mpSet->mpItems )
+ {
+ aRect.Left() = pItems[i].mnLeft;
+ aRect.Top() = pItems[i].mnTop;
+ aRect.Right() = pItems[i].mnLeft+pItems[i].mnWidth-1;
+ aRect.Bottom() = pItems[i].mnTop+pItems[i].mnHeight-1;
+ pWindow->Invalidate( aRect );
+ }
+ }
+ }
+ }
+ }
+
+ // Fenster positionieren
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet )
+ {
+ BOOL bTempHide = bHide;
+ if ( !pItems[i].mnWidth || !pItems[i].mnHeight )
+ bTempHide = TRUE;
+ ImplCalcSet2( pWindow, pItems[i].mpSet, bTempHide,
+ ((pItems[i].mnBits & SWIB_COLSET) == 0) );
+ }
+ else
+ {
+ if ( pItems[i].mnWidth && pItems[i].mnHeight && !bHide )
+ {
+ Point aPos( pItems[i].mnLeft, pItems[i].mnTop );
+ Size aSize( pItems[i].mnWidth, pItems[i].mnHeight );
+ pItems[i].mpWindow->SetPosSizePixel( aPos, aSize );
+ }
+ else
+ pItems[i].mpWindow->Hide();
+ }
+ }
+
+ // Fenster anzeigen und Flag zuruecksetzen
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpWindow && pItems[i].mnWidth && pItems[i].mnHeight && !bHide )
+ pItems[i].mpWindow->Show();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCalcLogSize( ImplSplitItem* pItems, USHORT nItems )
+{
+ // Original-Groessen updaten
+ USHORT i;
+ long nRelSize = 0;
+ long nPerSize = 0;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnBits & SWIB_RELATIVESIZE )
+ nRelSize += pItems[i].mnPixSize;
+ else if ( pItems[i].mnBits & SWIB_PERCENTSIZE )
+ nPerSize += pItems[i].mnPixSize;
+ }
+ nPerSize += nRelSize;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mnBits & SWIB_RELATIVESIZE )
+ {
+ if ( nRelSize )
+ pItems[i].mnSize = (pItems[i].mnPixSize+(nRelSize/2))/nRelSize;
+ else
+ pItems[i].mnSize = 1;
+ }
+ else if ( pItems[i].mnBits & SWIB_PERCENTSIZE )
+ {
+ if ( nPerSize )
+ pItems[i].mnSize = (pItems[i].mnPixSize*100)/nPerSize;
+ else
+ pItems[i].mnSize = 1;
+ }
+ else
+ pItems[i].mnSize = pItems[i].mnPixSize;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawBack( SplitWindow* pWindow, const Rectangle& rRect,
+ const Wallpaper* pWall, const Bitmap* pBitmap )
+{
+ if ( pBitmap )
+ {
+ Point aPos = rRect.TopLeft();
+ Size aBmpSize = pBitmap->GetSizePixel();
+ pWindow->Push( PUSH_CLIPREGION );
+ pWindow->IntersectClipRegion( rRect );
+ do
+ {
+ aPos.X() = rRect.Left();
+ do
+ {
+ pWindow->DrawBitmap( aPos, *pBitmap );
+ aPos.X() += aBmpSize.Width();
+ }
+ while ( aPos.X() < rRect.Right() );
+ aPos.Y() += aBmpSize.Height();
+ }
+ while ( aPos.Y() < rRect.Bottom() );
+ pWindow->Pop();
+ }
+ else
+ pWindow->DrawWallpaper( rRect, *pWall );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawBack( SplitWindow* pWindow, ImplSplitSet* pSet )
+{
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ // Beim Mainset auch den Hintergrund zeichnen
+ if ( pSet->mnId == 0 )
+ {
+ if ( pSet->mpBitmap )
+ {
+ Rectangle aRect( pWindow->mnLeftBorder,
+ pWindow->mnTopBorder,
+ pWindow->mnDX-pWindow->mnRightBorder-1,
+ pWindow->mnDY-pWindow->mnBottomBorder-1 );
+ ImplDrawBack( pWindow, aRect, pSet->mpWallpaper, pSet->mpBitmap );
+ }
+ }
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ pSet = pItems[i].mpSet;
+ if ( pSet )
+ {
+ if ( pSet->mpBitmap || pSet->mpWallpaper )
+ {
+ // Wegen ICC auftrennen
+ Point aPoint( pItems[i].mnLeft, pItems[i].mnTop );
+ Size aSize( pItems[i].mnWidth, pItems[i].mnHeight );
+ Rectangle aRect( aPoint, aSize );
+ ImplDrawBack( pWindow, aRect, pSet->mpWallpaper, pSet->mpBitmap );
+ }
+ }
+ }
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet )
+ ImplDrawBack( pWindow, pItems[i].mpSet );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDrawSplit( SplitWindow* pWindow, ImplSplitSet* pSet,
+ BOOL bRows, BOOL bDown = TRUE )
+{
+ if ( !pSet->mpItems )
+ return;
+
+ USHORT i;
+ USHORT nItems = pSet->mnItems;
+ long nPos;
+ long nTop;
+ long nBottom;
+ ImplSplitItem* pItems = pSet->mpItems;
+ const StyleSettings& rStyleSettings = pWindow->GetSettings().GetStyleSettings();
+
+ BOOL bFlat = (pWindow->GetStyle() & WB_FLATSPLITDRAW) == WB_FLATSPLITDRAW;
+
+ for ( i = 0; i < nItems-1; i++ )
+ {
+ if ( pItems[i].mnSplitSize )
+ {
+ nPos = pItems[i].mnSplitPos;
+
+ long nItemSplitSize = pItems[i].mnSplitSize;
+ long nSplitSize = pSet->mnSplitSize;
+ if ( bRows )
+ {
+ nTop = pItems[i].mnLeft;
+ nBottom = pItems[i].mnLeft+pItems[i].mnWidth-1;
+
+ if ( bFlat ) nPos--;
+
+ if ( bDown || (nItemSplitSize >= nSplitSize) )
+ {
+ pWindow->SetLineColor( rStyleSettings.GetLightColor() );
+ pWindow->DrawLine( Point( nTop, nPos+1 ), Point( nBottom, nPos+1 ) );
+ }
+ nPos += nSplitSize-2;
+ if ( bFlat ) nPos+=2;
+ if ( (!bDown && (nItemSplitSize >= 2)) ||
+ (bDown && (nItemSplitSize >= nSplitSize-1)) )
+ {
+ pWindow->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWindow->DrawLine( Point( nTop, nPos ), Point( nBottom, nPos ) );
+ }
+ if ( !bFlat )
+ {
+ nPos++;
+ if ( !bDown || (nItemSplitSize >= nSplitSize) )
+ {
+ pWindow->SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ pWindow->DrawLine( Point( nTop, nPos ), Point( nBottom, nPos ) );
+ }
+ }
+ }
+ else
+ {
+ nTop = pItems[i].mnTop;
+ nBottom = pItems[i].mnTop+pSet->mpItems[i].mnHeight-1;
+
+ if ( bFlat ) nPos--;
+ if ( bDown || (nItemSplitSize >= nSplitSize) )
+ {
+ pWindow->SetLineColor( rStyleSettings.GetLightColor() );
+ pWindow->DrawLine( Point( nPos+1, nTop ), Point( nPos+1, nBottom ) );
+ }
+ nPos += pSet->mnSplitSize-2;
+ if ( bFlat ) nPos+=2;
+ if ( (!bDown && (nItemSplitSize >= 2)) ||
+ (bDown && (nItemSplitSize >= nSplitSize-1)) )
+ {
+ pWindow->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWindow->DrawLine( Point( nPos, nTop ), Point( nPos, nBottom ) );
+ }
+ if( !bFlat )
+ {
+ nPos++;
+ if ( !bDown || (nItemSplitSize >= nSplitSize) )
+ {
+ pWindow->SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ pWindow->DrawLine( Point( nPos, nTop ), Point( nPos, nBottom ) );
+ }
+ }
+ }
+ }
+ }
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet && pItems[i].mnWidth && pItems[i].mnHeight )
+ ImplDrawSplit( pWindow, pItems[i].mpSet, ((pItems[i].mnBits & SWIB_COLSET) == 0) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::ImplTestSplit( ImplSplitSet* pSet, const Point& rPos,
+ long& rMouseOff, ImplSplitSet** ppFoundSet, USHORT& rFoundPos,
+ BOOL bRows, BOOL /*bDown*/ )
+{
+ if ( !pSet->mpItems )
+ return 0;
+
+ USHORT i;
+ USHORT nSplitTest;
+ USHORT nItems = pSet->mnItems;
+ long nMPos1;
+ long nMPos2;
+ long nPos;
+ long nTop;
+ long nBottom;
+ ImplSplitItem* pItems = pSet->mpItems;
+
+ if ( bRows )
+ {
+ nMPos1 = rPos.X();
+ nMPos2 = rPos.Y();
+ }
+ else
+ {
+ nMPos1 = rPos.Y();
+ nMPos2 = rPos.X();
+ }
+
+ for ( i = 0; i < nItems-1; i++ )
+ {
+ if ( pItems[i].mnSplitSize )
+ {
+ if ( bRows )
+ {
+ nTop = pItems[i].mnLeft;
+ nBottom = pItems[i].mnLeft+pItems[i].mnWidth-1;
+ }
+ else
+ {
+ nTop = pItems[i].mnTop;
+ nBottom = pItems[i].mnTop+pItems[i].mnHeight-1;
+ }
+ nPos = pItems[i].mnSplitPos;
+
+ if ( (nMPos1 >= nTop) && (nMPos1 <= nBottom) &&
+ (nMPos2 >= nPos) && (nMPos2 <= nPos+pItems[i].mnSplitSize) )
+ {
+ if ( !pItems[i].mbFixed && !pItems[i+1].mbFixed )
+ {
+ rMouseOff = nMPos2-nPos;
+ *ppFoundSet = pSet;
+ rFoundPos = i;
+ if ( bRows )
+ return SPLIT_VERT;
+ else
+ return SPLIT_HORZ;
+ }
+ else
+ return SPLIT_NOSPLIT;
+ }
+ }
+ }
+
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mpSet )
+ {
+ nSplitTest = ImplTestSplit( pItems[i].mpSet, rPos,
+ rMouseOff, ppFoundSet, rFoundPos,
+ ((pItems[i].mnBits & SWIB_COLSET) == 0) );
+ if ( nSplitTest )
+ return nSplitTest;
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::ImplTestSplit( SplitWindow* pWindow, const Point& rPos,
+ long& rMouseOff, ImplSplitSet** ppFoundSet, USHORT& rFoundPos )
+{
+ // Resizeable SplitWindow muss anders behandelt werden
+ if ( pWindow->mnWinStyle & WB_SIZEABLE )
+ {
+ long nTPos;
+ long nPos;
+ long nBorder;
+
+ if ( pWindow->mbHorz )
+ {
+ if ( pWindow->mbBottomRight )
+ {
+ nBorder = pWindow->mnBottomBorder;
+ nPos = 0;
+ }
+ else
+ {
+ nBorder = pWindow->mnTopBorder;
+ nPos = pWindow->mnDY-nBorder;
+ }
+ nTPos = rPos.Y();
+ }
+ else
+ {
+ if ( pWindow->mbBottomRight )
+ {
+ nBorder = pWindow->mnRightBorder;
+ nPos = 0;
+ }
+ else
+ {
+ nBorder = pWindow->mnLeftBorder;
+ nPos = pWindow->mnDX-nBorder;
+ }
+ nTPos = rPos.X();
+ }
+ long nSplitSize = pWindow->mpMainSet->mnSplitSize-2;
+ if ( pWindow->mbAutoHide || pWindow->mbFadeOut )
+ nSplitSize += SPLITWIN_SPLITSIZEEXLN;
+ if ( !pWindow->mbBottomRight )
+ nPos -= nSplitSize;
+ if ( (nTPos >= nPos) && (nTPos <= nPos+nSplitSize+nBorder) )
+ {
+ rMouseOff = nTPos-nPos;
+ *ppFoundSet = pWindow->mpMainSet;
+ if ( pWindow->mpMainSet->mpItems )
+ rFoundPos = pWindow->mpMainSet->mnItems-1;
+ else
+ rFoundPos = 0;
+ if ( pWindow->mbHorz )
+ return SPLIT_VERT | SPLIT_WINDOW;
+ else
+ return SPLIT_HORZ | SPLIT_WINDOW;
+ }
+ }
+
+ return ImplTestSplit( pWindow->mpMainSet, rPos, rMouseOff, ppFoundSet, rFoundPos,
+ pWindow->mbHorz, !pWindow->mbBottomRight );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawSplitTracking( SplitWindow* pThis, const Point& rPos )
+{
+ Rectangle aRect;
+
+ if ( pThis->mnSplitTest & SPLIT_HORZ )
+ {
+ aRect.Top() = pThis->maDragRect.Top();
+ aRect.Bottom() = pThis->maDragRect.Bottom();
+ aRect.Left() = rPos.X();
+ aRect.Right() = aRect.Left()+pThis->mpSplitSet->mnSplitSize-1;
+ if ( !(pThis->mnWinStyle & WB_NOSPLITDRAW) )
+ aRect.Right()--;
+ if ( (pThis->mnSplitTest & SPLIT_WINDOW) &&
+ (pThis->mbAutoHide || pThis->mbFadeOut) )
+ {
+ aRect.Left() += SPLITWIN_SPLITSIZEEXLN;
+ aRect.Right() += SPLITWIN_SPLITSIZEEXLN;
+ }
+ }
+ else
+ {
+ aRect.Left() = pThis->maDragRect.Left();
+ aRect.Right() = pThis->maDragRect.Right();
+ aRect.Top() = rPos.Y();
+ aRect.Bottom() = aRect.Top()+pThis->mpSplitSet->mnSplitSize-1;
+ if ( !(pThis->mnWinStyle & WB_NOSPLITDRAW) )
+ aRect.Bottom()--;
+ if ( (pThis->mnSplitTest & SPLIT_WINDOW) &&
+ (pThis->mbAutoHide || pThis->mbFadeOut) )
+ {
+ aRect.Top() += SPLITWIN_SPLITSIZEEXLN;
+ aRect.Bottom() += SPLITWIN_SPLITSIZEEXLN;
+ }
+ }
+ pThis->ShowTracking( aRect, SHOWTRACK_SPLIT );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplInit( Window* pParent, WinBits nStyle )
+{
+ ImplSplitSet* pNewSet = new ImplSplitSet;
+ pNewSet->mpItems = NULL;
+ pNewSet->mpWallpaper = NULL;
+ pNewSet->mpBitmap = NULL;
+ pNewSet->mnLastSize = 0;
+ pNewSet->mnItems = 0;
+ pNewSet->mnId = 0;
+ pNewSet->mnSplitSize = SPLITWIN_SPLITSIZE;
+ pNewSet->mbCalcPix = TRUE;
+
+ mpMainSet = pNewSet;
+ mpBaseSet = pNewSet;
+ mpSplitSet = NULL;
+ mpLastSizes = NULL;
+ mnDX = 0;
+ mnDY = 0;
+ mnLeftBorder = 0;
+ mnTopBorder = 0;
+ mnRightBorder = 0;
+ mnBottomBorder = 0;
+ mnMaxSize = 0;
+ mnMouseOff = 0;
+ meAlign = WINDOWALIGN_TOP;
+ mnWinStyle = nStyle;
+ mnSplitTest = 0;
+ mnSplitPos = 0;
+ mnMouseModifier = 0;
+ mnMStartPos = 0;
+ mnMSplitPos = 0;
+ mbDragFull = FALSE;
+ mbHorz = TRUE;
+ mbBottomRight = FALSE;
+ mbCalc = FALSE;
+ mbRecalc = TRUE;
+ mbInvalidate = TRUE;
+ mbAutoHide = FALSE;
+ mbFadeIn = FALSE;
+ mbFadeOut = FALSE;
+ mbAutoHideIn = FALSE;
+ mbAutoHideDown = FALSE;
+ mbFadeInDown = FALSE;
+ mbFadeOutDown = FALSE;
+ mbAutoHidePressed = FALSE;
+ mbFadeInPressed = FALSE;
+ mbFadeOutPressed = FALSE;
+ mbFadeNoButtonMode = FALSE;
+ mbNoAlign = FALSE;
+
+ if ( nStyle & WB_NOSPLITDRAW )
+ {
+ pNewSet->mnSplitSize -= 2;
+ mbInvalidate = FALSE;
+ }
+
+ if ( nStyle & WB_BORDER )
+ {
+ ImplCalcBorder( meAlign, mbNoAlign, mnLeftBorder, mnTopBorder,
+ mnRightBorder, mnBottomBorder );
+ }
+ else
+ {
+ mnLeftBorder = 0;
+ mnTopBorder = 0;
+ mnRightBorder = 0;
+ mnBottomBorder = 0;
+ }
+
+ DockingWindow::ImplInit( pParent, (nStyle | WB_CLIPCHILDREN) & ~(WB_BORDER | WB_SIZEABLE) );
+
+ ImplInitSettings();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplInitSettings()
+{
+ // Wenn fuer das MainSet eine Bitmap gesetzt wird, dann
+ // brauchen wir nicht mehr den Hintergrund loeschen
+ // Wenn MainSet Wallpaper hat, dann ist das der Hintergrund, ansonsten
+ // sind es die Standard-Farben
+ if ( mpMainSet->mpBitmap )
+ SetBackground();
+ else if ( mpMainSet->mpWallpaper )
+ SetBackground( *mpMainSet->mpWallpaper );
+ else
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ Color aColor;
+ if ( IsControlBackground() )
+ aColor = GetControlBackground();
+ else if ( Window::GetStyle() & WB_3DLOOK )
+ aColor = rStyleSettings.GetFaceColor();
+ else
+ aColor = rStyleSettings.GetWindowColor();
+ SetBackground( aColor );
+ }
+}
+
+// =======================================================================
+
+SplitWindow::SplitWindow( Window* pParent, WinBits nStyle ) :
+ DockingWindow( WINDOW_SPLITWINDOW )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+SplitWindow::SplitWindow( Window* pParent, const ResId& rResId ) :
+ DockingWindow( WINDOW_SPLITWINDOW )
+{
+ rResId.SetRT( RSC_SPLITWINDOW );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+SplitWindow::~SplitWindow()
+{
+ // Sets loeschen
+ ImplDeleteSet( mpMainSet );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplSetWindowSize( long nDelta )
+{
+ if ( !nDelta )
+ return;
+
+ Size aSize = GetSizePixel();
+ if ( meAlign == WINDOWALIGN_TOP )
+ {
+ aSize.Height() += nDelta;
+ SetSizePixel( aSize );
+ }
+ else if ( meAlign == WINDOWALIGN_BOTTOM )
+ {
+ maDragRect.Top() += nDelta;
+ Point aPos = GetPosPixel();
+ aPos.Y() -= nDelta;
+ aSize.Height() += nDelta;
+ SetPosSizePixel( aPos, aSize );
+ }
+ else if ( meAlign == WINDOWALIGN_LEFT )
+ {
+ aSize.Width() += nDelta;
+ SetSizePixel( aSize );
+ }
+ else // meAlign == WINDOWALIGN_RIGHT
+ {
+ maDragRect.Left() += nDelta;
+ Point aPos = GetPosPixel();
+ aPos.X() -= nDelta;
+ aSize.Width() += nDelta;
+ SetPosSizePixel( aPos, aSize );
+ }
+
+ SplitResize();
+}
+
+// -----------------------------------------------------------------------
+
+Size SplitWindow::CalcLayoutSizePixel( const Size& aNewSize )
+{
+ Size aSize( aNewSize );
+ long nSplitSize = mpMainSet->mnSplitSize-2;
+
+ if ( mbAutoHide || mbFadeOut )
+ nSplitSize += SPLITWIN_SPLITSIZEEXLN;
+
+ // Wenn Fenster sizeable ist, wird die groesse automatisch nach
+ // dem MainSet festgelegt, wenn kein relatives Fenster enthalten
+ // ist
+ if ( mnWinStyle & WB_SIZEABLE )
+ {
+ long nCurSize;
+ long nCalcSize = 0;
+ USHORT i;
+
+ for ( i = 0; i < mpMainSet->mnItems; i++ )
+ {
+ if ( mpMainSet->mpItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE) )
+ break;
+ else
+ nCalcSize += mpMainSet->mpItems[i].mnSize;
+ }
+
+ if ( i == mpMainSet->mnItems )
+ {
+ long nDelta = 0;
+ Point aPos = GetPosPixel();
+
+ if ( mbHorz )
+ nCurSize = aNewSize.Height()-mnTopBorder-mnBottomBorder;
+ else
+ nCurSize = aNewSize.Width()-mnLeftBorder-mnRightBorder;
+ nCurSize -= nSplitSize;
+ nCurSize -= (mpMainSet->mnItems-1)*mpMainSet->mnSplitSize;
+
+ nDelta = nCalcSize-nCurSize;
+ if ( !nDelta )
+ return aSize;
+
+ if ( meAlign == WINDOWALIGN_TOP )
+ {
+ aSize.Height() += nDelta;
+ }
+ else if ( meAlign == WINDOWALIGN_BOTTOM )
+ {
+ aPos.Y() -= nDelta;
+ aSize.Height() += nDelta;
+ }
+ else if ( meAlign == WINDOWALIGN_LEFT )
+ {
+ aSize.Width() += nDelta;
+ }
+ else // meAlign == WINDOWALIGN_RIGHT
+ {
+ aPos.X() -= nDelta;
+ aSize.Width() += nDelta;
+ }
+ }
+ }
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplCalcLayout()
+{
+ if ( !mbCalc || !mbRecalc || !mpMainSet->mpItems )
+ return;
+
+ long nSplitSize = mpMainSet->mnSplitSize-2;
+ if ( mbAutoHide || mbFadeOut )
+ nSplitSize += SPLITWIN_SPLITSIZEEXLN;
+
+ // Wenn Fenster sizeable ist, wird die groesse automatisch nach
+ // dem MainSet festgelegt, wenn kein relatives Fenster enthalten
+ // ist
+ if ( mnWinStyle & WB_SIZEABLE )
+ {
+ long nCurSize;
+ long nCalcSize = 0;
+ USHORT i;
+
+ for ( i = 0; i < mpMainSet->mnItems; i++ )
+ {
+ if ( mpMainSet->mpItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE) )
+ break;
+ else
+ nCalcSize += mpMainSet->mpItems[i].mnSize;
+ }
+
+ if ( i == mpMainSet->mnItems )
+ {
+ if ( mbHorz )
+ nCurSize = mnDY-mnTopBorder-mnBottomBorder;
+ else
+ nCurSize = mnDX-mnLeftBorder-mnRightBorder;
+ nCurSize -= nSplitSize;
+ nCurSize -= (mpMainSet->mnItems-1)*mpMainSet->mnSplitSize;
+
+ mbRecalc = FALSE;
+ ImplSetWindowSize( nCalcSize-nCurSize );
+ mbRecalc = TRUE;
+ }
+ }
+
+ if ( (mnDX <= 0) || (mnDY <= 0) )
+ return;
+
+ // Groessen/Position vorberechnen
+ long nL;
+ long nT;
+ long nW;
+ long nH;
+
+ if ( mbHorz )
+ {
+ if ( mbBottomRight )
+ nT = mnDY-mnBottomBorder;
+ else
+ nT = mnTopBorder;
+ nL = mnLeftBorder;
+ }
+ else
+ {
+ if ( mbBottomRight )
+ nL = mnDX-mnRightBorder;
+ else
+ nL = mnLeftBorder;
+ nT = mnTopBorder;
+ }
+ nW = mnDX-mnLeftBorder-mnRightBorder;
+ nH = mnDY-mnTopBorder-mnBottomBorder;
+ if ( mnWinStyle & WB_SIZEABLE )
+ {
+ if ( mbHorz )
+ nH -= nSplitSize;
+ else
+ nW -= nSplitSize;
+ }
+
+ // Sets rekursiv berechnen
+ ImplCalcSet( mpMainSet, nL, nT, nW, nH, mbHorz, !mbBottomRight );
+ ImplCalcSet2( this, mpMainSet, FALSE, mbHorz, !mbBottomRight );
+ mbCalc = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplUpdate()
+{
+ mbCalc = TRUE;
+
+ if ( IsReallyShown() && IsUpdateMode() && mbRecalc )
+ {
+ if ( mpMainSet->mpItems )
+ ImplCalcLayout();
+ else
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplUpdateSet( ImplSplitSet* pSet )
+{
+ if ( IsReallyShown() && IsUpdateMode() && mbRecalc )
+ {
+ // Wenn wir noch berechnen muessen, dann alles invalidieren.
+ if ( mbCalc )
+ {
+ // Wenn nicht NOSPLITDRAW gesetzt ist, koennen wir uns das
+ // invalidieren sparen, da bei ImplCalcSet2() die freien flaechen
+ // sowieso invalidiert werden
+ if ( !mpMainSet->mpItems || (mnWinStyle & WB_NOSPLITDRAW) )
+ pSet = mpMainSet;
+ else
+ return;
+ }
+
+ Rectangle aRect;
+ if ( pSet == mpMainSet )
+ {
+ aRect.Left() = mnLeftBorder;
+ aRect.Top() = mnTopBorder;
+ aRect.Right() = mnDX-mnRightBorder-1;
+ aRect.Bottom() = mnDY-mnBottomBorder-1;
+ }
+ else
+ {
+ ImplSplitItem* pItem;
+ USHORT nPos;
+
+ pSet = ImplFindItem( mpMainSet, pSet->mnId, nPos );
+ pItem = &(pSet->mpItems[nPos]);
+ aRect.Left() = pItem->mnLeft;
+ aRect.Top() = pItem->mnTop;
+ aRect.Right() = aRect.Left()+pItem->mnWidth;
+ aRect.Bottom() = aRect.Top()+pItem->mnHeight;
+ }
+ Invalidate( aRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplSplitMousePos( Point& rMousePos )
+{
+ if ( mnSplitTest & SPLIT_HORZ )
+ {
+ rMousePos.X() -= mnMouseOff;
+ if ( rMousePos.X() < maDragRect.Left() )
+ rMousePos.X() = maDragRect.Left();
+ else if ( rMousePos.X()+mpSplitSet->mnSplitSize+1 > maDragRect.Right() )
+ rMousePos.X() = maDragRect.Right()-mpSplitSet->mnSplitSize+1;
+ // Wegen FullDrag in Screen-Koordinaaten merken
+ mnMSplitPos = OutputToScreenPixel( rMousePos ).X();
+ }
+ else
+ {
+ rMousePos.Y() -= mnMouseOff;
+ if ( rMousePos.Y() < maDragRect.Top() )
+ rMousePos.Y() = maDragRect.Top();
+ else if ( rMousePos.Y()+mpSplitSet->mnSplitSize+1 > maDragRect.Bottom() )
+ rMousePos.Y() = maDragRect.Bottom()-mpSplitSet->mnSplitSize+1;
+ mnMSplitPos = OutputToScreenPixel( rMousePos ).Y();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplGetButtonRect( Rectangle& rRect, long nEx, BOOL bTest ) const
+{
+ long nSplitSize = mpMainSet->mnSplitSize-2;
+ if ( mbAutoHide || mbFadeOut || mbFadeIn )
+ nSplitSize += SPLITWIN_SPLITSIZEEX;
+
+ long nButtonSize = 0;
+ if ( mbFadeIn )
+ nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
+ if ( mbFadeOut )
+ nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
+ if ( mbAutoHide )
+ nButtonSize += SPLITWIN_SPLITSIZEAUTOHIDE+1;
+ long nCenterEx = 0;
+ if ( mbHorz )
+ nCenterEx += ((mnDX-mnLeftBorder-mnRightBorder)-nButtonSize)/2;
+ else
+ nCenterEx += ((mnDY-mnTopBorder-mnBottomBorder)-nButtonSize)/2;
+ if ( nCenterEx > 0 )
+ nEx += nCenterEx;
+
+ if ( meAlign == WINDOWALIGN_TOP )
+ {
+ rRect.Left() = mnLeftBorder+nEx;
+ rRect.Top() = mnDY-mnBottomBorder-nSplitSize;
+ rRect.Right() = rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE;
+ rRect.Bottom() = mnDY-mnBottomBorder-1;
+ if ( bTest )
+ {
+ rRect.Top() -= mnTopBorder;
+ rRect.Bottom() += mnBottomBorder;
+ }
+ }
+ else if ( meAlign == WINDOWALIGN_BOTTOM )
+ {
+ rRect.Left() = mnLeftBorder+nEx;
+ rRect.Top() = mnTopBorder;
+ rRect.Right() = rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE;
+ rRect.Bottom() = mnTopBorder+nSplitSize-1;
+ if ( bTest )
+ {
+ rRect.Top() -= mnTopBorder;
+ rRect.Bottom() += mnBottomBorder;
+ }
+ }
+ else if ( meAlign == WINDOWALIGN_LEFT )
+ {
+ rRect.Left() = mnDX-mnRightBorder-nSplitSize;
+ rRect.Top() = mnTopBorder+nEx;
+ rRect.Right() = mnDX-mnRightBorder-1;
+ rRect.Bottom() = rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE;
+ if ( bTest )
+ {
+ rRect.Left() -= mnLeftBorder;
+ rRect.Right() += mnRightBorder;
+ }
+ }
+ else if ( meAlign == WINDOWALIGN_RIGHT )
+ {
+ rRect.Left() = mnLeftBorder;
+ rRect.Top() = mnTopBorder+nEx;
+ rRect.Right() = mnLeftBorder+nSplitSize-1;
+ rRect.Bottom() = rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE;
+ if ( bTest )
+ {
+ rRect.Left() -= mnLeftBorder;
+ rRect.Right() += mnRightBorder;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplGetAutoHideRect( Rectangle& rRect, BOOL bTest ) const
+{
+ Rectangle aRect;
+
+ if ( mbAutoHide )
+ {
+ long nEx = 0;
+ if ( mbFadeIn || mbFadeOut )
+ nEx = SPLITWIN_SPLITSIZEFADE+1;
+ ImplGetButtonRect( aRect, nEx, bTest && mbFadeIn );
+ }
+
+ rRect = aRect;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplGetFadeInRect( Rectangle& rRect, BOOL bTest ) const
+{
+ Rectangle aRect;
+
+ if ( mbFadeIn )
+ ImplGetButtonRect( aRect, 0, bTest );
+
+ rRect = aRect;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplGetFadeOutRect( Rectangle& rRect, BOOL ) const
+{
+ Rectangle aRect;
+
+ if ( mbFadeOut )
+ ImplGetButtonRect( aRect, 0, FALSE );
+
+ rRect = aRect;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawButtonRect( const Rectangle& rRect, long nSize )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if ( mbHorz )
+ {
+ long nLeft = rRect.Left();
+ long nRight = rRect.Right();
+ long nCenter = rRect.Center().Y();
+ long nEx1 = nLeft+((rRect.GetWidth()-nSize)/2)-2;
+ long nEx2 = nEx1+nSize+3;
+ SetLineColor( rStyleSettings.GetLightColor() );
+ DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Left(), rRect.Bottom() ) );
+ DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Right(), rRect.Top() ) );
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( rRect.Right(), rRect.Top() ), Point( rRect.Right(), rRect.Bottom() ) );
+ DrawLine( Point( rRect.Left(), rRect.Bottom() ), Point( rRect.Right(), rRect.Bottom() ) );
+ long i = nLeft+2;
+ while ( i < nRight-3 )
+ {
+ if ( (i < nEx1) || (i > nEx2 ) )
+ {
+ DrawPixel( Point( i, nCenter-2 ), rStyleSettings.GetLightColor() );
+ DrawPixel( Point( i+1, nCenter-2+1 ), rStyleSettings.GetShadowColor() );
+ }
+ i++;
+ if ( (i < nEx1) || ((i > nEx2 ) && (i < nRight-3)) )
+ {
+ DrawPixel( Point( i, nCenter+2 ), rStyleSettings.GetLightColor() );
+ DrawPixel( Point( i+1, nCenter+2+1 ), rStyleSettings.GetShadowColor() );
+ }
+ i += 2;
+ }
+ }
+ else
+ {
+ long nTop = rRect.Top();
+ long nBottom = rRect.Bottom();
+ long nCenter = rRect.Center().X();
+ long nEx1 = nTop+((rRect.GetHeight()-nSize)/2)-2;
+ long nEx2 = nEx1+nSize+3;
+ SetLineColor( rStyleSettings.GetLightColor() );
+ DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Right(), rRect.Top() ) );
+ DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Left(), rRect.Bottom() ) );
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( rRect.Right(), rRect.Top() ), Point( rRect.Right(), rRect.Bottom() ) );
+ DrawLine( Point( rRect.Left(), rRect.Bottom() ), Point( rRect.Right(), rRect.Bottom() ) );
+ long i = nTop+2;
+ while ( i < nBottom-3 )
+ {
+ if ( (i < nEx1) || (i > nEx2 ) )
+ {
+ DrawPixel( Point( nCenter-2, i ), rStyleSettings.GetLightColor() );
+ DrawPixel( Point( nCenter-2+1, i+1 ), rStyleSettings.GetShadowColor() );
+ }
+ i++;
+ if ( (i < nEx1) || ((i > nEx2 ) && (i < nBottom-3)) )
+ {
+ DrawPixel( Point( nCenter+2, i ), rStyleSettings.GetLightColor() );
+ DrawPixel( Point( nCenter+2+1, i+1 ), rStyleSettings.GetShadowColor() );
+ }
+ i += 2;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawAutoHide( BOOL bInPaint )
+{
+ if ( mbAutoHide )
+ {
+ Rectangle aTempRect;
+ ImplGetAutoHideRect( aTempRect );
+
+ if ( !bInPaint )
+ Erase( aTempRect );
+
+ // ImageListe laden, wenn noch nicht vorhanden
+ ImplSVData* pSVData = ImplGetSVData();
+ ImageList* pImageList;
+ if ( mbHorz )
+ {
+ if ( !pSVData->maCtrlData.mpSplitHPinImgList )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ {
+ Color aNonAlphaMask( 0x00, 0x00, 0xFF );
+ pSVData->maCtrlData.mpSplitHPinImgList = new ImageList(4);
+ pSVData->maCtrlData.mpSplitHPinImgList->InsertFromHorizontalBitmap
+ ( ResId( SV_RESID_BITMAP_SPLITHPIN, *pResMgr ), 4, &aNonAlphaMask );
+ }
+ }
+ pImageList = pSVData->maCtrlData.mpSplitHPinImgList;
+ }
+ else
+ {
+ if ( !pSVData->maCtrlData.mpSplitVPinImgList )
+ {
+ ResMgr* pResMgr = ImplGetResMgr();
+ pSVData->maCtrlData.mpSplitVPinImgList = new ImageList(4);
+ if( pResMgr )
+ {
+ Color aNonAlphaMask( 0x00, 0x00, 0xFF );
+ pSVData->maCtrlData.mpSplitVPinImgList->InsertFromHorizontalBitmap
+ ( ResId( SV_RESID_BITMAP_SPLITVPIN, *pResMgr ), 4, &aNonAlphaMask );
+ }
+ }
+ pImageList = pSVData->maCtrlData.mpSplitVPinImgList;
+ }
+
+ // Image ermitteln und zurueckgeben
+ USHORT nId;
+ if ( mbAutoHidePressed )
+ {
+ if ( mbAutoHideIn )
+ nId = 3;
+ else
+ nId = 4;
+ }
+ else
+ {
+ if ( mbAutoHideIn )
+ nId = 1;
+ else
+ nId = 2;
+ }
+
+ Image aImage = pImageList->GetImage( nId );
+ Size aImageSize = aImage.GetSizePixel();
+ Point aPos( aTempRect.Left()+((aTempRect.GetWidth()-aImageSize.Width())/2),
+ aTempRect.Top()+((aTempRect.GetHeight()-aImageSize.Height())/2) );
+ long nSize;
+ if ( mbHorz )
+ nSize = aImageSize.Width();
+ else
+ nSize = aImageSize.Height();
+ ImplDrawButtonRect( aTempRect, nSize );
+ DrawImage( aPos, aImage );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawFadeArrow( const Point& rPt, BOOL bHorz, BOOL bLeft )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ int x( rPt.X() );
+ int y( rPt.Y() );
+
+ Color aCol;
+ if( !bHorz )
+ {
+ int dx = 1;
+ if( bLeft )
+ {
+ x ++;
+ dx = -1;
+ }
+
+ x++; y++;
+ aCol = Color( COL_WHITE );
+ DrawPixel( Point(x, y), aCol );
+ DrawPixel( Point(x, y+1), aCol );
+ DrawPixel( Point(x, y+2), aCol );
+ DrawPixel( Point(x+dx, y+1), aCol );
+
+ x--; y--;
+ aCol = rStyleSettings.GetDarkShadowColor();
+ DrawPixel( Point(x, y), rStyleSettings.GetDarkShadowColor() );
+ DrawPixel( Point(x, y+1), rStyleSettings.GetDarkShadowColor() );
+ DrawPixel( Point(x, y+2), rStyleSettings.GetDarkShadowColor() );
+ DrawPixel( Point(x+dx, y+1), rStyleSettings.GetDarkShadowColor() );
+ }
+ else
+ {
+ int dy = 1;
+ if( bLeft )
+ {
+ y ++;
+ dy = -1;
+ }
+
+ x++; y++;
+ aCol = Color( COL_WHITE );
+ DrawPixel( Point(x, y), aCol );
+ DrawPixel( Point(x+1, y), aCol );
+ DrawPixel( Point(x+2, y), aCol );
+ DrawPixel( Point(x+1, y+dy), aCol );
+
+ x--; y--;
+ aCol = rStyleSettings.GetDarkShadowColor();
+ DrawPixel( Point(x, y), aCol );
+ DrawPixel( Point(x+1, y), aCol );
+ DrawPixel( Point(x+2, y), aCol );
+ DrawPixel( Point(x+1, y+dy), aCol );
+ }
+}
+
+void SplitWindow::ImplDrawGrip( const Rectangle& rRect, BOOL bHorz, BOOL bLeft )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if( rRect.IsInside( GetPointerPosPixel() ) )
+ {
+ DrawWallpaper( rRect, Wallpaper( Color( COL_WHITE ) ) );
+ DrawSelectionBackground( rRect, 2, FALSE, FALSE, FALSE );
+ }
+
+ if( bHorz )
+ {
+ int width = (int) (0.5 * rRect.getWidth() + 0.5);
+ int i = rRect.nLeft + (rRect.getWidth() - width) / 2;
+ width += i;
+ const int y = rRect.nTop + 1;
+ ImplDrawFadeArrow( Point( i-8, y), bHorz, bLeft );
+ while( i <= width )
+ {
+
+ DrawPixel( Point(i, y), rStyleSettings.GetDarkShadowColor() );
+ DrawPixel( Point(i+1, y), rStyleSettings.GetShadowColor() );
+
+ DrawPixel( Point(i, y+1), rStyleSettings.GetShadowColor() );
+ DrawPixel( Point(i+1, y+1), rStyleSettings.GetFaceColor() );
+ DrawPixel( Point(i+2, y+1), Color(COL_WHITE) );
+
+ DrawPixel( Point(i+1, y+2), Color(COL_WHITE) );
+ DrawPixel( Point(i+2, y+2), Color(COL_WHITE) );
+ i+=4;
+ }
+ ImplDrawFadeArrow( Point( i+3, y), bHorz, bLeft );
+ }
+ else
+ {
+ int height = (int) (0.5 * rRect.getHeight() + 0.5);
+ int i = rRect.nTop + (rRect.getHeight() - height) / 2;
+ height += i;
+ const int x = rRect.nLeft + 1;
+ ImplDrawFadeArrow( Point( x, i-8), bHorz, bLeft );
+ while( i <= height )
+ {
+
+ DrawPixel( Point(x, i), rStyleSettings.GetDarkShadowColor() );
+ DrawPixel( Point(x+1, i), rStyleSettings.GetShadowColor() );
+
+ DrawPixel( Point(x, i+1), rStyleSettings.GetShadowColor() );
+ DrawPixel( Point(x+1, i+1), rStyleSettings.GetFaceColor() );
+ DrawPixel( Point(x+2, i+1), Color(COL_WHITE) );
+
+ DrawPixel( Point(x+1, i+2), Color(COL_WHITE) );
+ DrawPixel( Point(x+2, i+2), Color(COL_WHITE) );
+ i+=4;
+ }
+ ImplDrawFadeArrow( Point( x, i+3), bHorz, bLeft );
+ }
+}
+
+void SplitWindow::ImplDrawFadeIn( BOOL bInPaint )
+{
+ if ( mbFadeIn )
+ {
+ Rectangle aTempRect;
+ Image aImage;
+ ImplGetFadeInRect( aTempRect );
+
+ BOOL bLeft;
+ if ( meAlign == WINDOWALIGN_TOP )
+ bLeft = FALSE;
+ else if ( meAlign == WINDOWALIGN_BOTTOM )
+ bLeft = TRUE;
+ else if ( meAlign == WINDOWALIGN_LEFT )
+ bLeft = FALSE;
+ else if ( meAlign == WINDOWALIGN_RIGHT )
+ bLeft = TRUE;
+ else
+ bLeft = TRUE;
+
+ if ( !bInPaint )
+ Erase( aTempRect );
+
+ ImplDrawGrip( aTempRect, (meAlign == WINDOWALIGN_TOP) || (meAlign == WINDOWALIGN_BOTTOM), bLeft );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplDrawFadeOut( BOOL bInPaint )
+{
+ if ( mbFadeOut )
+ {
+ Rectangle aTempRect;
+ Image aImage;
+ ImplGetFadeOutRect( aTempRect );
+
+ BOOL bLeft;
+ if ( meAlign == WINDOWALIGN_TOP )
+ bLeft = TRUE;
+ else if ( meAlign == WINDOWALIGN_BOTTOM )
+ bLeft = FALSE;
+ else if ( meAlign == WINDOWALIGN_LEFT )
+ bLeft = TRUE;
+ else if ( meAlign == WINDOWALIGN_RIGHT )
+ bLeft = FALSE;
+ else
+ bLeft = TRUE;
+
+ if ( !bInPaint )
+ Erase( aTempRect );
+
+ ImplDrawGrip( aTempRect, (meAlign == WINDOWALIGN_TOP) || (meAlign == WINDOWALIGN_BOTTOM), bLeft );
+ }
+}
+
+// -----------------------------------------------------------------------
+void SplitWindow::ImplStartSplit( const MouseEvent& rMEvt )
+{
+ Point aMousePosPixel = rMEvt.GetPosPixel();
+ mnSplitTest = ImplTestSplit( this, aMousePosPixel, mnMouseOff, &mpSplitSet, mnSplitPos );
+
+ if ( mnSplitTest && !(mnSplitTest & SPLIT_NOSPLIT) )
+ {
+ ImplSplitItem* pSplitItem;
+ long nCurMaxSize;
+ USHORT nTemp;
+ BOOL bDown;
+ BOOL bPropSmaller;
+
+ mnMouseModifier = rMEvt.GetModifier();
+ if ( !(mnMouseModifier & KEY_SHIFT) || (mnSplitPos+1 >= mpSplitSet->mnItems) )
+ bPropSmaller = FALSE;
+ else
+ bPropSmaller = TRUE;
+
+ // Hier kann noch die maximale Groesse gesetzt werden
+ StartSplit();
+
+ if ( mnMaxSize )
+ nCurMaxSize = mnMaxSize;
+ else
+ {
+ Size aSize = GetParent()->GetOutputSizePixel();
+ if ( mbHorz )
+ nCurMaxSize = aSize.Height();
+ else
+ nCurMaxSize = aSize.Width();
+ }
+
+ if ( mpSplitSet->mpItems )
+ {
+ bDown = TRUE;
+ if ( (mpSplitSet == mpMainSet) && mbBottomRight )
+ bDown = FALSE;
+
+ pSplitItem = &(mpSplitSet->mpItems[mnSplitPos]);
+ maDragRect.Left() = pSplitItem->mnLeft;
+ maDragRect.Top() = pSplitItem->mnTop;
+ maDragRect.Right() = pSplitItem->mnLeft+pSplitItem->mnWidth-1;
+ maDragRect.Bottom() = pSplitItem->mnTop+pSplitItem->mnHeight-1;
+
+ if ( mnSplitTest & SPLIT_HORZ )
+ {
+ if ( bDown )
+ maDragRect.Right() += mpSplitSet->mnSplitSize;
+ else
+ maDragRect.Left() -= mpSplitSet->mnSplitSize;
+ }
+ else
+ {
+ if ( bDown )
+ maDragRect.Bottom() += mpSplitSet->mnSplitSize;
+ else
+ maDragRect.Top() -= mpSplitSet->mnSplitSize;
+ }
+
+ if ( mnSplitPos )
+ {
+ nTemp = mnSplitPos;
+ while ( nTemp )
+ {
+ pSplitItem = &(mpSplitSet->mpItems[nTemp-1]);
+ if ( pSplitItem->mbFixed )
+ break;
+ else
+ {
+ if ( mnSplitTest & SPLIT_HORZ )
+ {
+ if ( bDown )
+ maDragRect.Left() -= pSplitItem->mnPixSize;
+ else
+ maDragRect.Right() += pSplitItem->mnPixSize;
+ }
+ else
+ {
+ if ( bDown )
+ maDragRect.Top() -= pSplitItem->mnPixSize;
+ else
+ maDragRect.Bottom() += pSplitItem->mnPixSize;
+ }
+ }
+ nTemp--;
+ }
+ }
+
+ if ( (mpSplitSet == mpMainSet) && (mnWinStyle & WB_SIZEABLE) && !bPropSmaller )
+ {
+ if ( bDown )
+ {
+ if ( mbHorz )
+ maDragRect.Bottom() += nCurMaxSize-mnDY-mnTopBorder;
+ else
+ maDragRect.Right() += nCurMaxSize-mnDX-mnLeftBorder;
+ }
+ else
+ {
+ if ( mbHorz )
+ maDragRect.Top() -= nCurMaxSize-mnDY-mnBottomBorder;
+ else
+ maDragRect.Left() -= nCurMaxSize-mnDX-mnRightBorder;
+ }
+ }
+ else
+ {
+ nTemp = mnSplitPos+1;
+ while ( nTemp < mpSplitSet->mnItems )
+ {
+ pSplitItem = &(mpSplitSet->mpItems[nTemp]);
+ if ( pSplitItem->mbFixed )
+ break;
+ else
+ {
+ if ( mnSplitTest & SPLIT_HORZ )
+ {
+ if ( bDown )
+ maDragRect.Right() += pSplitItem->mnPixSize;
+ else
+ maDragRect.Left() -= pSplitItem->mnPixSize;
+ }
+ else
+ {
+ if ( bDown )
+ maDragRect.Bottom() += pSplitItem->mnPixSize;
+ else
+ maDragRect.Top() -= pSplitItem->mnPixSize;
+ }
+ }
+ nTemp++;
+ }
+ }
+ }
+ else
+ {
+ maDragRect.Left() = mnLeftBorder;
+ maDragRect.Top() = mnTopBorder;
+ maDragRect.Right() = mnDX-mnRightBorder-1;
+ maDragRect.Bottom() = mnDY-mnBottomBorder-1;
+ if ( mbHorz )
+ {
+ if ( mbBottomRight )
+ maDragRect.Top() -= nCurMaxSize-mnDY-mnBottomBorder;
+ else
+ maDragRect.Bottom() += nCurMaxSize-mnDY-mnTopBorder;
+ }
+ else
+ {
+ if ( mbBottomRight )
+ maDragRect.Left() -= nCurMaxSize-mnDX-mnRightBorder;
+ else
+ maDragRect.Right() += nCurMaxSize-mnDX-mnLeftBorder;
+ }
+ }
+
+ StartTracking();
+
+ mbDragFull = (GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT) != 0;
+
+ ImplSplitMousePos( aMousePosPixel );
+
+ if ( !mbDragFull )
+ ImplDrawSplitTracking( this, aMousePosPixel );
+ else
+ {
+ ImplSplitItem* pItems = mpSplitSet->mpItems;
+ USHORT nItems = mpSplitSet->mnItems;
+ mpLastSizes = new long[nItems*2];
+ for ( USHORT i = 0; i < nItems; i++ )
+ {
+ mpLastSizes[i*2] = pItems[i].mnSize;
+ mpLastSizes[i*2+1] = pItems[i].mnPixSize;
+ }
+ }
+ mnMStartPos = mnMSplitPos;
+
+ PointerStyle eStyle = POINTER_ARROW;
+ if ( mnSplitTest & SPLIT_HORZ )
+ eStyle = POINTER_HSPLIT;
+ else if ( mnSplitTest & SPLIT_VERT )
+ eStyle = POINTER_VSPLIT;
+
+ Pointer aPtr( eStyle );
+ SetPointer( aPtr );
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::StartSplit()
+{
+ maStartSplitHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::Split()
+{
+ maSplitHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SplitResize()
+{
+ maSplitResizeHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::AutoHide()
+{
+ maAutoHideHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::FadeIn()
+{
+ maFadeInHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::FadeOut()
+{
+ maFadeOutHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( !rMEvt.IsLeft() || rMEvt.IsMod2() )
+ {
+ DockingWindow::MouseButtonDown( rMEvt );
+ return;
+ }
+
+ Point aMousePosPixel = rMEvt.GetPosPixel();
+ Rectangle aTestRect;
+
+ mbFadeNoButtonMode = FALSE;
+ ImplGetAutoHideRect( aTestRect, TRUE );
+ if ( aTestRect.IsInside( aMousePosPixel ) )
+ {
+ mbAutoHideDown = TRUE;
+ mbAutoHidePressed = TRUE;
+ ImplDrawAutoHide( FALSE );
+ }
+ else
+ {
+ ImplGetFadeOutRect( aTestRect, TRUE );
+ if ( aTestRect.IsInside( aMousePosPixel ) )
+ {
+ mbFadeOutDown = TRUE;
+ mbFadeOutPressed = TRUE;
+ ImplDrawFadeOut( FALSE );
+ }
+ else
+ {
+ ImplGetFadeInRect( aTestRect, TRUE );
+ if ( aTestRect.IsInside( aMousePosPixel ) )
+ {
+ mbFadeInDown = TRUE;
+ mbFadeInPressed = TRUE;
+ ImplDrawFadeIn( FALSE );
+ }
+ else if ( !aTestRect.IsEmpty() && !(mnWinStyle & WB_SIZEABLE) )
+ {
+ mbFadeNoButtonMode = TRUE;
+ FadeIn();
+ return;
+ }
+ }
+ }
+
+ if ( mbAutoHideDown || mbFadeInDown || mbFadeOutDown )
+ StartTracking();
+ else
+ ImplStartSplit( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( !IsTracking() )
+ {
+ Point aPos = rMEvt.GetPosPixel();
+ long nTemp;
+ ImplSplitSet* pTempSplitSet;
+ USHORT nTempSplitPos;
+ USHORT nSplitTest = ImplTestSplit( this, aPos, nTemp, &pTempSplitSet, nTempSplitPos );
+ PointerStyle eStyle = POINTER_ARROW;
+ Rectangle aAutoHideRect;
+ Rectangle aFadeInRect;
+ Rectangle aFadeOutRect;
+
+ ImplGetAutoHideRect( aAutoHideRect );
+ ImplGetFadeInRect( aFadeInRect );
+ ImplGetFadeOutRect( aFadeOutRect );
+ if ( !aAutoHideRect.IsInside( aPos ) &&
+ !aFadeInRect.IsInside( aPos ) &&
+ !aFadeOutRect.IsInside( aPos ) )
+ {
+ if ( nSplitTest && !(nSplitTest & SPLIT_NOSPLIT) )
+ {
+ if ( nSplitTest & SPLIT_HORZ )
+ eStyle = POINTER_HSPLIT;
+ else if ( nSplitTest & SPLIT_VERT )
+ eStyle = POINTER_VSPLIT;
+ }
+ }
+
+ Pointer aPtr( eStyle );
+ SetPointer( aPtr );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::Tracking( const TrackingEvent& rTEvt )
+{
+ Point aMousePosPixel = rTEvt.GetMouseEvent().GetPosPixel();
+
+ if ( mbAutoHideDown )
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ mbAutoHideDown = FALSE;
+ if ( mbAutoHidePressed )
+ {
+ mbAutoHidePressed = FALSE;
+
+ if ( !rTEvt.IsTrackingCanceled() )
+ {
+ mbAutoHideIn = !mbAutoHideIn;
+ ImplDrawAutoHide( FALSE );
+ AutoHide();
+ }
+ else
+ ImplDrawAutoHide( FALSE );
+ }
+ }
+ else
+ {
+ Rectangle aTestRect;
+ ImplGetAutoHideRect( aTestRect, TRUE );
+ BOOL bNewPressed = aTestRect.IsInside( aMousePosPixel );
+ if ( bNewPressed != mbAutoHidePressed )
+ {
+ mbAutoHidePressed = bNewPressed;
+ ImplDrawAutoHide( FALSE );
+ }
+ }
+ }
+ else if ( mbFadeInDown )
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ mbFadeInDown = FALSE;
+ if ( mbFadeInPressed )
+ {
+ mbFadeInPressed = FALSE;
+ ImplDrawFadeIn( FALSE );
+
+ if ( !rTEvt.IsTrackingCanceled() )
+ FadeIn();
+ }
+ }
+ else
+ {
+ Rectangle aTestRect;
+ ImplGetFadeInRect( aTestRect, TRUE );
+ BOOL bNewPressed = aTestRect.IsInside( aMousePosPixel );
+ if ( bNewPressed != mbFadeInPressed )
+ {
+ mbFadeInPressed = bNewPressed;
+ ImplDrawFadeIn( FALSE );
+ }
+ }
+ }
+ else if ( mbFadeOutDown )
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ mbFadeOutDown = FALSE;
+ if ( mbFadeOutPressed )
+ {
+ mbFadeOutPressed = FALSE;
+ ImplDrawFadeOut( FALSE );
+
+ if ( !rTEvt.IsTrackingCanceled() )
+ FadeOut();
+ }
+ }
+ else
+ {
+ Rectangle aTestRect;
+ ImplGetFadeOutRect( aTestRect, TRUE );
+ BOOL bNewPressed = aTestRect.IsInside( aMousePosPixel );
+ if ( bNewPressed == FALSE )
+ {
+ mbFadeOutPressed = bNewPressed;
+ ImplDrawFadeOut( FALSE );
+
+ // We need a mouseevent with a position inside the button for the
+ // ImplStartSplit function!
+ MouseEvent aOrgMEvt = rTEvt.GetMouseEvent();
+ MouseEvent aNewMEvt = MouseEvent( aTestRect.Center(), aOrgMEvt.GetClicks(),
+ aOrgMEvt.GetMode(), aOrgMEvt.GetButtons(),
+ aOrgMEvt.GetModifier() );
+
+ ImplStartSplit( aNewMEvt );
+ mbFadeOutDown = FALSE;
+ }
+ }
+ }
+ else
+ {
+ ImplSplitMousePos( aMousePosPixel );
+ BOOL bSplit = TRUE;
+ if ( mbDragFull )
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ if ( rTEvt.IsTrackingCanceled() )
+ {
+ ImplSplitItem* pItems = mpSplitSet->mpItems;
+ USHORT nItems = mpSplitSet->mnItems;
+ for ( USHORT i = 0; i < nItems; i++ )
+ {
+ pItems[i].mnSize = mpLastSizes[i*2];
+ pItems[i].mnPixSize = mpLastSizes[i*2+1];
+ }
+ ImplUpdate();
+ Split();
+ }
+ bSplit = FALSE;
+ }
+ }
+ else
+ {
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ HideTracking();
+ bSplit = !rTEvt.IsTrackingCanceled();
+ }
+ else
+ {
+ ImplDrawSplitTracking( this, aMousePosPixel );
+ bSplit = FALSE;
+ }
+ }
+
+ if ( bSplit )
+ {
+ BOOL bPropSmaller = (mnMouseModifier & KEY_SHIFT) ? TRUE : FALSE;
+ BOOL bPropGreater = (mnMouseModifier & KEY_MOD1) ? TRUE : FALSE;
+ long nDelta = mnMSplitPos-mnMStartPos;
+
+ if ( (mnSplitTest & SPLIT_WINDOW) && !mpMainSet->mpItems )
+ {
+ if ( (mpSplitSet == mpMainSet) && mbBottomRight )
+ nDelta *= -1;
+ ImplSetWindowSize( nDelta );
+ }
+ else
+ {
+ long nNewSize = mpSplitSet->mpItems[mnSplitPos].mnPixSize;
+ if ( (mpSplitSet == mpMainSet) && mbBottomRight )
+ nNewSize -= nDelta;
+ else
+ nNewSize += nDelta;
+ SplitItem( mpSplitSet->mpItems[mnSplitPos].mnId, nNewSize,
+ bPropSmaller, bPropGreater );
+ }
+
+ Split();
+
+ if ( mbDragFull )
+ {
+ Update();
+ mnMStartPos = mnMSplitPos;
+ }
+ }
+
+ if ( rTEvt.IsTrackingEnded() )
+ {
+ if ( mpLastSizes )
+ delete mpLastSizes;
+ mpLastSizes = NULL;
+ mpSplitSet = NULL;
+ mnMouseOff = 0;
+ mnMStartPos = 0;
+ mnMSplitPos = 0;
+ mnMouseModifier = 0;
+ mnSplitTest = 0;
+ mnSplitPos = 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long SplitWindow::PreNotify( NotifyEvent& rNEvt )
+{
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ Rectangle aFadeInRect;
+ Rectangle aFadeOutRect;
+ ImplGetFadeInRect( aFadeInRect );
+ ImplGetFadeOutRect( aFadeOutRect );
+
+ if ( aFadeInRect.IsInside( GetPointerPosPixel() ) != aFadeInRect.IsInside( GetLastPointerPosPixel() ) )
+ Invalidate( aFadeInRect );
+ if ( aFadeOutRect.IsInside( GetPointerPosPixel() ) != aFadeOutRect.IsInside( GetLastPointerPosPixel() ) )
+ Invalidate( aFadeOutRect );
+
+ if( pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
+ {
+ Invalidate( aFadeInRect );
+ Invalidate( aFadeOutRect );
+ }
+ }
+ }
+ return Window::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::Paint( const Rectangle& )
+{
+ if ( mnWinStyle & WB_BORDER )
+ ImplDrawBorder( this );
+
+ ImplDrawBorderLine( this );
+ ImplDrawFadeOut( TRUE );
+ ImplDrawFadeIn( TRUE );
+ ImplDrawAutoHide( TRUE );
+
+ // FrameSet-Hintergruende zeichnen
+ ImplDrawBack( this, mpMainSet );
+
+ // Splitter zeichnen
+ if ( !(mnWinStyle & WB_NOSPLITDRAW) )
+ ImplDrawSplit( this, mpMainSet, mbHorz, !mbBottomRight );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::Move()
+{
+ DockingWindow::Move();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::Resize()
+{
+ Size aSize = GetOutputSizePixel();
+ mnDX = aSize.Width();
+ mnDY = aSize.Height();
+
+ ImplUpdate();
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ // no keyboard help for splitwin
+ if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) && !rHEvt.KeyboardActivated() )
+ {
+ Point aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
+ Rectangle aHelpRect;
+ USHORT nHelpResId = 0;
+
+ ImplGetAutoHideRect( aHelpRect, TRUE );
+ if ( aHelpRect.IsInside( aMousePosPixel ) )
+ {
+ if ( mbAutoHideIn )
+ nHelpResId = SV_HELPTEXT_SPLITFIXED;
+ else
+ nHelpResId = SV_HELPTEXT_SPLITFLOATING;
+ }
+ else
+ {
+ ImplGetFadeInRect( aHelpRect, TRUE );
+ if ( aHelpRect.IsInside( aMousePosPixel ) )
+ nHelpResId = SV_HELPTEXT_FADEIN;
+ else
+ {
+ ImplGetFadeOutRect( aHelpRect, TRUE );
+ if ( aHelpRect.IsInside( aMousePosPixel ) )
+ nHelpResId = SV_HELPTEXT_FADEOUT;
+ }
+ }
+
+ // Rechteck ermitteln
+ if ( nHelpResId )
+ {
+ Point aPt = OutputToScreenPixel( aHelpRect.TopLeft() );
+ aHelpRect.Left() = aPt.X();
+ aHelpRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aHelpRect.BottomRight() );
+ aHelpRect.Right() = aPt.X();
+ aHelpRect.Bottom() = aPt.Y();
+
+ // Text ermitteln und anzeigen
+ XubString aStr;
+ ResMgr* pResMgr = ImplGetResMgr();
+ if( pResMgr )
+ aStr = XubString( ResId( nHelpResId, *pResMgr ) );
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aStr );
+ else
+ Help::ShowQuickHelp( this, aHelpRect, aStr );
+ return;
+ }
+ }
+
+ DockingWindow::RequestHelp( rHEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ if ( IsUpdateMode() )
+ ImplCalcLayout();
+ }
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsUpdateMode() && IsReallyShown() )
+ ImplCalcLayout();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+
+ DockingWindow::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+ else
+ DockingWindow::DataChanged( rDCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::InsertItem( USHORT nId, Window* pWindow, long nSize,
+ USHORT nPos, USHORT nSetId,
+ SplitWindowItemBits nBits )
+{
+#ifdef DBG_UTIL
+ USHORT nDbgDummy;
+ DBG_ASSERT( ImplFindSet( mpMainSet, nSetId ), "SplitWindow::InsertItem() - Set not exists" );
+ DBG_ASSERT( !ImplFindItem( mpMainSet, nId, nDbgDummy ), "SplitWindow::InsertItem() - Id already exists" );
+#endif
+
+ // Size muss min. 1 sein
+ if ( nSize < 1 )
+ nSize = 1;
+
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+ ImplSplitSet* pNewSet;
+ ImplSplitItem* pItem;
+
+ // Platz fuer neues Item schaffen
+ if ( nPos > pSet->mnItems )
+ nPos = pSet->mnItems;
+ ImplSplitItem* pNewItems = new ImplSplitItem[pSet->mnItems+1];
+ if ( nPos )
+ memcpy( pNewItems, pSet->mpItems, sizeof( ImplSplitItem )*nPos );
+ if ( nPos < pSet->mnItems )
+ memcpy( pNewItems+nPos+1, pSet->mpItems+nPos, sizeof( ImplSplitItem )*(pSet->mnItems-nPos) );
+ delete[] pSet->mpItems;
+ pSet->mpItems = pNewItems;
+ pSet->mnItems++;
+ pSet->mbCalcPix = TRUE;
+
+ // Item anlegen und erweitern
+ pItem = &(pSet->mpItems[nPos]);
+ memset( pItem, 0, sizeof( ImplSplitItem ) );
+ pItem->mnSize = nSize;
+ pItem->mnId = nId;
+ pItem->mnBits = nBits;
+
+ if ( pWindow )
+ {
+ pItem->mpWindow = pWindow;
+ pItem->mpOrgParent = pWindow->GetParent();
+
+ // Window mit SplitWindow verbinden
+ pWindow->Hide();
+ pWindow->SetParent( this );
+ }
+ else
+ {
+ pNewSet = new ImplSplitSet;
+ pNewSet->mpItems = NULL;
+ pNewSet->mpWallpaper = NULL;
+ pNewSet->mpBitmap = NULL;
+ pNewSet->mnLastSize = 0;
+ pNewSet->mnItems = 0;
+ pNewSet->mnId = nId;
+ pNewSet->mnSplitSize = pSet->mnSplitSize;
+ pNewSet->mbCalcPix = TRUE;
+
+ pItem->mpSet = pNewSet;
+ }
+
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::InsertItem( USHORT nId, long nSize,
+ USHORT nPos, USHORT nSetId,
+ SplitWindowItemBits nBits )
+{
+ InsertItem( nId, NULL, nSize, nPos, nSetId, nBits );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::MoveItem( USHORT nId, USHORT nNewPos, USHORT nNewSetId )
+{
+#ifdef DBG_UTIL
+ USHORT nDbgDummy;
+ DBG_ASSERT( ImplFindItem( mpMainSet, nId, nDbgDummy ), "SplitWindow::MoveItem() - Id not found" );
+ DBG_ASSERT( ImplFindSet( mpMainSet, nNewSetId ), "SplitWindow::MoveItem() - Set not exists" );
+#endif
+
+ USHORT nPos;
+ ImplSplitSet* pNewSet = ImplFindSet( mpMainSet, nNewSetId );
+ ImplSplitSet* pSet = ImplFindItem( mpMainSet, nId, nPos );
+ ImplSplitItem aTempItem;
+
+ if ( pNewSet == pSet )
+ {
+ if ( nNewPos >= pNewSet->mnItems )
+ nNewPos = pNewSet->mnItems-1;
+ if ( nPos != nNewPos )
+ {
+ memcpy( &aTempItem, &(pSet->mpItems[nPos]), sizeof( aTempItem ) );
+ if ( nPos < nNewPos )
+ {
+ memmove( pSet->mpItems+nPos, pSet->mpItems+nPos+1,
+ (nNewPos-nPos)*sizeof( ImplSplitItem ) );
+ }
+ else
+ {
+ memmove( pSet->mpItems+nNewPos+1, pSet->mpItems+nNewPos,
+ (nPos-nNewPos)*sizeof( ImplSplitItem ) );
+ }
+ memcpy( &(pSet->mpItems[nNewPos]), &aTempItem, sizeof( aTempItem ) );
+
+ ImplUpdate();
+ }
+ }
+ else
+ {
+ if ( nNewPos >= pNewSet->mnItems )
+ nNewPos = pNewSet->mnItems;
+ memcpy( &aTempItem, &(pSet->mpItems[nPos]), sizeof( aTempItem ) );
+ pSet->mnItems--;
+ pSet->mbCalcPix = TRUE;
+ if ( pSet->mnItems )
+ {
+ memmove( pSet->mpItems+nPos, pSet->mpItems+nPos+1,
+ (pSet->mnItems-nPos)*sizeof( ImplSplitItem ) );
+ }
+ else
+ {
+ delete[] pSet->mpItems;
+ pSet->mpItems = NULL;
+ }
+ ImplSplitItem* pNewItems = new ImplSplitItem[pNewSet->mnItems+1];
+ if ( nNewPos )
+ memcpy( pNewItems, pNewSet->mpItems, sizeof( ImplSplitItem )*nNewPos );
+ if ( nNewPos < pNewSet->mnItems )
+ {
+ memcpy( pNewItems+nNewPos+1, pNewSet->mpItems+nNewPos,
+ sizeof( ImplSplitItem )*(pNewSet->mnItems-nNewPos) );
+ }
+ delete[] pNewSet->mpItems;
+ pNewSet->mpItems = pNewItems;
+ pNewSet->mnItems++;
+ pNewSet->mbCalcPix = TRUE;
+ memcpy( &(pNewSet->mpItems[nNewPos]), &aTempItem, sizeof( aTempItem ) );
+ ImplUpdate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::RemoveItem( USHORT nId, BOOL bHide )
+{
+#ifdef DBG_UTIL
+ USHORT nDbgDummy;
+ DBG_ASSERT( ImplFindItem( mpMainSet, nId, nDbgDummy ), "SplitWindow::RemoveItem() - Id not found" );
+#endif
+
+ // Set suchen
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpMainSet, nId, nPos );
+ ImplSplitItem* pItem = &(pSet->mpItems[nPos]);
+ Window* pWindow = pItem->mpWindow;
+ Window* pOrgParent = pItem->mpOrgParent;
+
+ // Evt. Set loeschen
+ if ( !pWindow )
+ ImplDeleteSet( pItem->mpSet );
+
+ // Item entfernen
+ pSet->mnItems--;
+ pSet->mbCalcPix = TRUE;
+ if ( pSet->mnItems )
+ {
+ memmove( pSet->mpItems+nPos, pSet->mpItems+nPos+1,
+ (pSet->mnItems-nPos)*sizeof( ImplSplitItem ) );
+ }
+ else
+ {
+ delete[] pSet->mpItems;
+ pSet->mpItems = NULL;
+ }
+
+ ImplUpdate();
+
+ // Window erst hier loeschen, um weniger Paints zu haben
+ if ( pWindow )
+ {
+ // Fenster wieder herstellen
+ if ( bHide || (pOrgParent != this) )
+ {
+ pWindow->Hide();
+ pWindow->SetParent( pOrgParent );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::Clear()
+{
+ // Alle Sets loeschen
+ ImplDeleteSet( mpMainSet );
+
+ // Main-Set wieder anlegen
+ mpMainSet = new ImplSplitSet;
+ mpMainSet->mpItems = NULL;
+ mpMainSet->mpWallpaper = NULL;
+ mpMainSet->mpBitmap = NULL;
+ mpMainSet->mnLastSize = 0;
+ mpMainSet->mnItems = 0;
+ mpMainSet->mnId = 0;
+ mpMainSet->mnSplitSize = SPLITWIN_SPLITSIZE;
+ mpMainSet->mbCalcPix = TRUE;
+ if ( mnWinStyle & WB_NOSPLITDRAW )
+ mpMainSet->mnSplitSize -= 2;
+ mpBaseSet = mpMainSet;
+
+ // Und neu invalidieren
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetBaseSet( USHORT nSetId )
+{
+ mpBaseSet = ImplFindSet( mpMainSet, nSetId );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::GetBaseSet() const
+{
+ return mpBaseSet->mnId;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetSplitSize( USHORT nSetId, long nSplitSize,
+ BOOL bWithChilds )
+{
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+ if ( pSet )
+ {
+ if ( bWithChilds )
+ ImplSetSplitSize( pSet, nSplitSize );
+ else
+ pSet->mnSplitSize = nSplitSize;
+ }
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+long SplitWindow::GetSplitSize( USHORT nSetId ) const
+{
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+ if ( pSet )
+ return pSet->mnSplitSize;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetItemBackground( USHORT nSetId )
+{
+ Wallpaper aWall;
+ SetItemBackground( nSetId, aWall );
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetItemBackground( USHORT nSetId, const Wallpaper& rWallpaper )
+{
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+
+ if ( pSet )
+ {
+ BOOL bUpdate = TRUE;
+
+ if ( rWallpaper.GetStyle() == WALLPAPER_NULL )
+ {
+ if ( pSet->mpWallpaper )
+ {
+ delete pSet->mpWallpaper;
+ pSet->mpWallpaper = NULL;
+ }
+ else
+ bUpdate = FALSE;
+ }
+ else
+ {
+ // Ab jetzt muss immer invalidiert werden
+ mbInvalidate = TRUE;
+
+ if ( !pSet->mpWallpaper )
+ pSet->mpWallpaper = new Wallpaper( rWallpaper );
+ else
+ *(pSet->mpWallpaper) = rWallpaper;
+ }
+
+ // Beim MainSet koennen wir den Background umsetzen
+ if ( pSet == mpMainSet )
+ ImplInitSettings();
+
+ if ( bUpdate )
+ ImplUpdateSet( pSet );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Wallpaper SplitWindow::GetItemBackground( USHORT nSetId ) const
+{
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+
+ if ( pSet && pSet->mpWallpaper )
+ return *(pSet->mpWallpaper);
+ else
+ {
+ Wallpaper aWall;
+ return aWall;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SplitWindow::IsItemBackground( USHORT nSetId ) const
+{
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+
+ if ( pSet && pSet->mpWallpaper )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetItemBitmap( USHORT nSetId, const Bitmap& rBitmap )
+{
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+
+ if ( pSet )
+ {
+ BOOL bUpdate = TRUE;
+
+ if ( !rBitmap )
+ {
+ if ( pSet->mpBitmap )
+ {
+ delete pSet->mpBitmap;
+ pSet->mpBitmap = NULL;
+ }
+ else
+ bUpdate = FALSE;
+ }
+ else
+ {
+ // Ab jetzt muss immer invalidiert werden
+ mbInvalidate = TRUE;
+
+ if ( !pSet->mpBitmap )
+ pSet->mpBitmap = new Bitmap( rBitmap );
+ else
+ *(pSet->mpBitmap) = rBitmap;
+ }
+
+ // Beim MainSet koennen wir den Background umsetzen
+ if ( pSet == mpMainSet )
+ ImplInitSettings();
+
+ if ( bUpdate )
+ ImplUpdateSet( pSet );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Bitmap SplitWindow::GetItemBitmap( USHORT nSetId ) const
+{
+ ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId );
+
+ if ( pSet && pSet->mpBitmap )
+ return *(pSet->mpBitmap);
+ else
+ {
+ Bitmap aBitmap;
+ return aBitmap;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SplitItem( USHORT nId, long nNewSize,
+ BOOL bPropSmall, BOOL bPropGreat )
+{
+ USHORT nItems;
+ USHORT nPos;
+ USHORT nMin;
+ USHORT nMax;
+ USHORT i;
+ USHORT n;
+ long nDelta;
+ long nTempDelta;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+ ImplSplitItem* pItems;
+
+ if ( !pSet )
+ return;
+
+ nItems = pSet->mnItems;
+ pItems = pSet->mpItems;
+
+ if ( mbCalc )
+ {
+ pItems[nPos].mnSize = nNewSize;
+ return;
+ }
+
+ nDelta = nNewSize-pItems[nPos].mnPixSize;
+ if ( !nDelta )
+ return;
+
+ // Bereich berechnen, der beim Splitten betroffen sein kann
+ nMin = 0;
+ nMax = nItems;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( pItems[i].mbFixed )
+ {
+ if ( i < nPos )
+ nMin = i+1;
+ else
+ nMax = i;
+ }
+ }
+
+ // Wenn das Fenster sizeable ist, wird das TopSet anders behandelt
+ BOOL bSmall = TRUE;
+ BOOL bGreat = TRUE;
+ if ( (pSet == mpMainSet) && (mnWinStyle & WB_SIZEABLE) )
+ {
+ if ( nPos < pSet->mnItems-1 )
+ {
+ if ( !((bPropSmall && bPropGreat) ||
+ ((nDelta > 0) && bPropSmall) ||
+ ((nDelta < 0) && bPropGreat)) )
+ {
+ if ( nDelta < 0 )
+ bGreat = FALSE;
+ else
+ bSmall = FALSE;
+ }
+ }
+ else
+ {
+ if ( nDelta < 0 )
+ bGreat = FALSE;
+ else
+ bSmall = FALSE;
+ }
+ }
+ else if ( nPos >= nMax )
+ {
+ bSmall = FALSE;
+ bGreat = FALSE;
+ }
+ else if ( nPos && (nPos >= pSet->mnItems-1) )
+ {
+ nPos--;
+ nDelta *= -1;
+ BOOL bTemp = bPropSmall;
+ bPropSmall = bPropGreat;
+ bPropGreat = bTemp;
+ }
+
+ // Jetzt die Fenster splitten
+ if ( nDelta < 0 )
+ {
+ if ( bGreat )
+ {
+ if ( bPropGreat )
+ {
+ nTempDelta = nDelta;
+ do
+ {
+ n = nPos+1;
+ do
+ {
+ if ( nTempDelta )
+ {
+ pItems[n].mnPixSize++;
+ nTempDelta++;
+ }
+ n++;
+ }
+ while ( n < nMax );
+ }
+ while ( nTempDelta );
+ }
+ else
+ pItems[nPos+1].mnPixSize -= nDelta;
+ }
+
+ if ( bSmall )
+ {
+ if ( bPropSmall )
+ {
+ do
+ {
+ n = nPos+1;
+ do
+ {
+ if ( nDelta && pItems[n-1].mnPixSize )
+ {
+ pItems[n-1].mnPixSize--;
+ nDelta++;
+ }
+
+ n--;
+ }
+ while ( n > nMin );
+ }
+ while ( nDelta );
+ }
+ else
+ {
+ n = nPos+1;
+ do
+ {
+ if ( pItems[n-1].mnPixSize+nDelta < 0 )
+ {
+ nDelta += pItems[n-1].mnPixSize;
+ pItems[n-1].mnPixSize = 0;
+ }
+ else
+ {
+ pItems[n-1].mnPixSize += nDelta;
+ break;
+ }
+ n--;
+ }
+ while ( n > nMin );
+ }
+ }
+ }
+ else
+ {
+ if ( bGreat )
+ {
+ if ( bPropGreat )
+ {
+ nTempDelta = nDelta;
+ do
+ {
+ n = nPos+1;
+ do
+ {
+ if ( nTempDelta )
+ {
+ pItems[n-1].mnPixSize++;
+ nTempDelta--;
+ }
+ n--;
+ }
+ while ( n > nMin );
+ }
+ while ( nTempDelta );
+ }
+ else
+ pItems[nPos].mnPixSize += nDelta;
+ }
+
+ if ( bSmall )
+ {
+ if ( bPropSmall )
+ {
+ do
+ {
+ n = nPos+1;
+ do
+ {
+ if ( nDelta && pItems[n].mnPixSize )
+ {
+ pItems[n].mnPixSize--;
+ nDelta--;
+ }
+
+ n++;
+ }
+ while ( n < nMax );
+ }
+ while ( nDelta );
+ }
+ else
+ {
+ n = nPos+1;
+ do
+ {
+ if ( pItems[n].mnPixSize-nDelta < 0 )
+ {
+ nDelta -= pItems[n].mnPixSize;
+ pItems[n].mnPixSize = 0;
+ }
+ else
+ {
+ pItems[n].mnPixSize -= nDelta;
+ break;
+ }
+ n++;
+ }
+ while ( n < nMax );
+ }
+ }
+ }
+
+ // Original-Groessen updaten
+ ImplCalcLogSize( pItems, nItems );
+
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetItemSize( USHORT nId, long nNewSize )
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+ ImplSplitItem* pItem;
+
+ if ( !pSet )
+ return;
+
+ // Testen, ob sich Groesse aendert
+ pItem = &(pSet->mpItems[nPos]);
+ if ( pItem->mnSize != nNewSize )
+ {
+ // Neue Groesse setzen und neu durchrechnen
+ pItem->mnSize = nNewSize;
+ pSet->mbCalcPix = TRUE;
+ ImplUpdate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long SplitWindow::GetItemSize( USHORT nId ) const
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+
+ if ( pSet )
+ return pSet->mpItems[nPos].mnSize;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+long SplitWindow::GetItemSize( USHORT nId, SplitWindowItemBits nBits ) const
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+
+ if ( pSet )
+ {
+ if ( nBits == pSet->mpItems[nPos].mnBits )
+ return pSet->mpItems[nPos].mnSize;
+ else
+ {
+ ((SplitWindow*)this)->ImplCalcLayout();
+
+ long nRelSize = 0;
+ long nPerSize = 0;
+ ImplSplitItem* pItems;
+ USHORT nItems;
+ SplitWindowItemBits nTempBits;
+ USHORT i;
+ nItems = pSet->mnItems;
+ pItems = pSet->mpItems;
+ for ( i = 0; i < nItems; i++ )
+ {
+ if ( i == nPos )
+ nTempBits = nBits;
+ else
+ nTempBits = pItems[i].mnBits;
+ if ( nTempBits & SWIB_RELATIVESIZE )
+ nRelSize += pItems[i].mnPixSize;
+ else if ( nTempBits & SWIB_PERCENTSIZE )
+ nPerSize += pItems[i].mnPixSize;
+ }
+ nPerSize += nRelSize;
+ if ( nBits & SWIB_RELATIVESIZE )
+ {
+ if ( nRelSize )
+ return (pItems[nPos].mnPixSize+(nRelSize/2))/nRelSize;
+ else
+ return 1;
+ }
+ else if ( nBits & SWIB_PERCENTSIZE )
+ {
+ if ( nPerSize )
+ return (pItems[nPos].mnPixSize*100)/nPerSize;
+ else
+ return 1;
+ }
+ else
+ return pItems[nPos].mnPixSize;
+ }
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetItemBits( USHORT nId, SplitWindowItemBits nNewBits )
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+ ImplSplitItem* pItem;
+
+ if ( !pSet )
+ return;
+
+ pItem = &(pSet->mpItems[nPos]);
+ if ( pItem->mpWindow )
+ nNewBits &= ~SWIB_COLSET;
+
+ if ( pItem->mnBits != nNewBits )
+ {
+ // Neue Bits setzen und neu durchrechnen
+ pItem->mnBits = nNewBits;
+ pSet->mbCalcPix = TRUE;
+ ImplUpdate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SplitWindowItemBits SplitWindow::GetItemBits( USHORT nId ) const
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+
+ if ( pSet )
+ return pSet->mpItems[nPos].mnBits;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+Window* SplitWindow::GetItemWindow( USHORT nId ) const
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+
+ if ( pSet )
+ return pSet->mpItems[nPos].mpWindow;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::GetSet( USHORT nId ) const
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+
+ if ( pSet )
+ return pSet->mnId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SplitWindow::GetSet( USHORT nId, USHORT& rSetId, USHORT& rPos ) const
+{
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, rPos );
+ if ( pSet )
+ {
+ rSetId = pSet->mnId;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SplitWindow::IsItemValid( USHORT nId ) const
+{
+ USHORT nPos;
+ ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
+
+ if ( pSet )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::GetItemId( Window* pWindow ) const
+{
+ return ImplFindItem( mpBaseSet, pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::GetItemId( const Point& rPos ) const
+{
+ return ImplFindItem( mpBaseSet, rPos, mbHorz, !mbBottomRight );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::GetItemPos( USHORT nId, USHORT nSetId ) const
+{
+ ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId );
+ USHORT nPos = SPLITWINDOW_ITEM_NOTFOUND;
+
+ if ( pSet )
+ {
+ for ( USHORT i = 0; i < pSet->mnItems; i++ )
+ {
+ if ( pSet->mpItems[i].mnId == nId )
+ {
+ nPos = i;
+ break;
+ }
+ }
+ }
+
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::GetItemId( USHORT nPos, USHORT nSetId ) const
+{
+ ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId );
+ if ( pSet && (nPos < pSet->mnItems) )
+ return pSet->mpItems[nPos].mnId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SplitWindow::GetItemCount( USHORT nSetId ) const
+{
+ ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId );
+ if ( pSet )
+ return pSet->mnItems;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ImplNewAlign()
+{
+ if ( mbNoAlign )
+ {
+ mbHorz = FALSE;
+ mbBottomRight = FALSE;
+ }
+ else if ( meAlign == WINDOWALIGN_TOP )
+ {
+ mbHorz = TRUE;
+ mbBottomRight = FALSE;
+ }
+ else if ( meAlign == WINDOWALIGN_BOTTOM )
+ {
+ mbHorz = TRUE;
+ mbBottomRight = TRUE;
+ }
+ else if ( meAlign == WINDOWALIGN_LEFT )
+ {
+ mbHorz = FALSE;
+ mbBottomRight = FALSE;
+ }
+ else if ( meAlign == WINDOWALIGN_RIGHT )
+ {
+ mbHorz = FALSE;
+ mbBottomRight = TRUE;
+ }
+
+ if ( mnWinStyle & WB_BORDER )
+ {
+ ImplCalcBorder( meAlign, mbNoAlign, mnLeftBorder, mnTopBorder,
+ mnRightBorder, mnBottomBorder );
+ }
+
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetNoAlign( BOOL bNoAlign )
+{
+ bNoAlign = bNoAlign != 0;
+ if ( mbNoAlign != bNoAlign )
+ {
+ mbNoAlign = bNoAlign;
+ ImplNewAlign();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetAlign( WindowAlign eNewAlign )
+{
+ if ( meAlign != eNewAlign )
+ {
+ meAlign = eNewAlign;
+ ImplNewAlign();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size SplitWindow::CalcWindowSizePixel( const Size& rSize, WindowAlign eAlign,
+ WinBits nWinStyle, BOOL bExtra )
+{
+ long nLeft;
+ long nTop;
+ long nRight;
+ long nBottom;
+ Size aSize = rSize;
+
+ ImplCalcBorder( eAlign, FALSE, nLeft, nTop, nRight, nBottom );
+ aSize.Width() += nLeft+nRight;
+ aSize.Height() += nTop+nBottom;
+
+ if ( nWinStyle & WB_SIZEABLE )
+ {
+ if ( (eAlign == WINDOWALIGN_TOP) || (eAlign == WINDOWALIGN_BOTTOM) )
+ {
+ aSize.Height() += SPLITWIN_SPLITSIZE-2;
+ if ( bExtra )
+ aSize.Height() += SPLITWIN_SPLITSIZEEXLN;
+ }
+ else
+ {
+ aSize.Width() += SPLITWIN_SPLITSIZE-2;
+ if ( bExtra )
+ aSize.Width() += SPLITWIN_SPLITSIZEEXLN;
+ }
+ }
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ShowAutoHideButton( BOOL bShow )
+{
+ mbAutoHide = bShow;
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ShowFadeInHideButton( BOOL bShow )
+{
+ mbFadeIn = bShow;
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::ShowFadeOutButton( BOOL bShow )
+{
+ mbFadeOut = bShow;
+ ImplUpdate();
+}
+
+// -----------------------------------------------------------------------
+
+void SplitWindow::SetAutoHideState( BOOL bAutoHide )
+{
+ mbAutoHideIn = bAutoHide;
+ if ( IsReallyVisible() )
+ {
+ Rectangle aRect;
+ ImplGetAutoHideRect( aRect );
+ Invalidate( aRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long SplitWindow::GetFadeInSize() const
+{
+ long n = 0;
+
+ if ( mbHorz )
+ n = mnTopBorder+mnBottomBorder;
+ else
+ n = mnLeftBorder+mnRightBorder;
+
+ return n+SPLITWIN_SPLITSIZE+SPLITWIN_SPLITSIZEEX-2;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle SplitWindow::GetAutoHideRect() const
+{
+ Rectangle aRect;
+ ImplGetAutoHideRect( aRect, TRUE );
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle SplitWindow::GetFadeInRect() const
+{
+ Rectangle aRect;
+ ImplGetFadeInRect( aRect, TRUE );
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle SplitWindow::GetFadeOutRect() const
+{
+ Rectangle aRect;
+ ImplGetFadeOutRect( aRect, TRUE );
+ return aRect;
+}
diff --git a/vcl/source/window/status.cxx b/vcl/source/window/status.cxx
new file mode 100644
index 000000000000..385dd241c770
--- /dev/null
+++ b/vcl/source/window/status.cxx
@@ -0,0 +1,1794 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/list.hxx>
+#include <tools/debug.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/event.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/help.hxx>
+#include <vcl/status.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/window.h>
+
+// =======================================================================
+
+#define STATUSBAR_OFFSET_X STATUSBAR_OFFSET
+#define STATUSBAR_OFFSET_Y 2
+#define STATUSBAR_OFFSET_TEXTY 3
+
+#define STATUSBAR_PRGS_OFFSET 3
+#define STATUSBAR_PRGS_COUNT 100
+#define STATUSBAR_PRGS_MIN 5
+
+// -----------------------------------------------------------------------
+
+class StatusBar::ImplData
+{
+public:
+ ImplData();
+ ~ImplData();
+
+ VirtualDevice* mpVirDev;
+ long mnItemBorderWidth;
+ bool mbTopBorder:1;
+ bool mbDrawItemFrames:1;
+};
+
+StatusBar::ImplData::ImplData()
+{
+ mpVirDev = NULL;
+ mbTopBorder = false;
+ mbDrawItemFrames = false;
+ mnItemBorderWidth = 0;
+}
+
+StatusBar::ImplData::~ImplData()
+{
+}
+
+struct ImplStatusItem
+{
+ USHORT mnId;
+ StatusBarItemBits mnBits;
+ long mnWidth;
+ long mnOffset;
+ long mnExtraWidth;
+ long mnX;
+ XubString maText;
+ XubString maHelpText;
+ XubString maQuickHelpText;
+ ULONG mnHelpId;
+ void* mpUserData;
+ BOOL mbVisible;
+ XubString maAccessibleName;
+ XubString maCommand;
+};
+
+DECLARE_LIST( ImplStatusItemList, ImplStatusItem* )
+
+// =======================================================================
+
+inline long ImplCalcProgessWidth( USHORT nMax, long nSize )
+{
+ return ((nMax*(nSize+(nSize/2)))-(nSize/2)+(STATUSBAR_PRGS_OFFSET*2));
+}
+
+// -----------------------------------------------------------------------
+
+static Point ImplGetItemTextPos( const Size& rRectSize, const Size& rTextSize,
+ USHORT nStyle )
+{
+ long nX;
+ long nY;
+ long delta = (rTextSize.Height()/4) + 1;
+ if( delta + rTextSize.Width() > rRectSize.Width() )
+ delta = 0;
+
+ if ( nStyle & SIB_LEFT )
+ nX = delta;
+ else if ( nStyle & SIB_RIGHT )
+ nX = rRectSize.Width()-rTextSize.Width()-delta;
+ else // SIB_CENTER
+ nX = (rRectSize.Width()-rTextSize.Width())/2;
+ nY = (rRectSize.Height()-rTextSize.Height())/2 + 1;
+ return Point( nX, nY );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL StatusBar::ImplIsItemUpdate()
+{
+ if ( !mbProgressMode && mbVisibleItems && IsReallyVisible() && IsUpdateMode() )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplInit( Window* pParent, WinBits nStyle )
+{
+ mpImplData = new ImplData;
+
+ // Default ist RightAlign
+ if ( !(nStyle & (WB_LEFT | WB_RIGHT)) )
+ nStyle |= WB_RIGHT;
+
+ Window::ImplInit( pParent, nStyle & ~WB_BORDER, NULL );
+
+ // WinBits merken
+ mpItemList = new ImplStatusItemList;
+ mpImplData->mpVirDev = new VirtualDevice( *this );
+ mnCurItemId = 0;
+ mbFormat = TRUE;
+ mbVisibleItems = TRUE;
+ mbProgressMode = FALSE;
+ mbInUserDraw = FALSE;
+ mbBottomBorder = FALSE;
+ mnItemsWidth = STATUSBAR_OFFSET_X;
+ mnDX = 0;
+ mnDY = 0;
+ mnCalcHeight = 0;
+ mnItemY = STATUSBAR_OFFSET_Y;
+ mnTextY = STATUSBAR_OFFSET_TEXTY;
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ SetLineColor();
+
+ SetOutputSizePixel( CalcWindowSizePixel() );
+}
+
+// -----------------------------------------------------------------------
+
+StatusBar::StatusBar( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_STATUSBAR )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+StatusBar::StatusBar( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_STATUSBAR )
+{
+ rResId.SetRT( RSC_STATUSBAR );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+StatusBar::~StatusBar()
+{
+ // Alle Items loeschen
+ ImplStatusItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ delete pItem;
+ pItem = mpItemList->Next();
+ }
+
+ delete mpItemList;
+
+ // VirtualDevice loeschen
+ delete mpImplData->mpVirDev;
+
+ delete mpImplData;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if ( bFont )
+ {
+ Font aFont = rStyleSettings.GetToolFont();
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ SetZoomedPointFont( aFont );
+ }
+
+ if ( bForeground || bFont )
+ {
+ Color aColor;
+ if ( IsControlForeground() )
+ aColor = GetControlForeground();
+ else if ( GetStyle() & WB_3DLOOK )
+ aColor = rStyleSettings.GetButtonTextColor();
+ else
+ aColor = rStyleSettings.GetWindowTextColor();
+ SetTextColor( aColor );
+ SetTextFillColor();
+
+ mpImplData->mpVirDev->SetFont( GetFont() );
+ mpImplData->mpVirDev->SetTextColor( GetTextColor() );
+ mpImplData->mpVirDev->SetTextAlign( GetTextAlign() );
+ mpImplData->mpVirDev->SetTextFillColor();
+ }
+
+ if ( bBackground )
+ {
+ Color aColor;
+ if ( IsControlBackground() )
+ aColor = GetControlBackground();
+ else if ( GetStyle() & WB_3DLOOK )
+ aColor = rStyleSettings.GetFaceColor();
+ else
+ aColor = rStyleSettings.GetWindowColor();
+ SetBackground( aColor );
+ mpImplData->mpVirDev->SetBackground( GetBackground() );
+
+ // NWF background
+ if( ! IsControlBackground() &&
+ IsNativeControlSupported( CTRL_WINDOW_BACKGROUND, PART_BACKGROUND_WINDOW ) )
+ {
+ ImplGetWindowImpl()->mnNativeBackground = PART_BACKGROUND_WINDOW;
+ EnableChildTransparentMode( TRUE );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplFormat()
+{
+ ImplStatusItem* pItem;
+ long nExtraWidth;
+ long nExtraWidth2;
+ long nX;
+ USHORT nAutoSizeItems = 0;
+
+ // Breiten zusammenrechnen
+ mnItemsWidth = STATUSBAR_OFFSET_X;
+ long nOffset = 0;
+ pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mbVisible )
+ {
+ if ( pItem->mnBits & SIB_AUTOSIZE )
+ nAutoSizeItems++;
+
+ mnItemsWidth += pItem->mnWidth + nOffset;
+ nOffset = pItem->mnOffset;
+ }
+
+ pItem = mpItemList->Next();
+ }
+
+ if ( GetStyle() & WB_RIGHT )
+ {
+ // Bei rechtsbuendiger Ausrichtung wird kein AutoSize ausgewertet,
+ // da wir links den Text anzeigen, der mit SetText gesetzt wird
+ nX = mnDX - mnItemsWidth;
+ nExtraWidth = 0;
+ nExtraWidth2 = 0;
+ }
+ else
+ {
+ mnItemsWidth += STATUSBAR_OFFSET_X;
+
+ // Bei linksbuendiger Ausrichtung muessen wir gegebenenfalls noch
+ // AutoSize auswerten
+ if ( nAutoSizeItems && (mnDX > (mnItemsWidth - STATUSBAR_OFFSET)) )
+ {
+ nExtraWidth = (mnDX - mnItemsWidth - 1) / nAutoSizeItems;
+ nExtraWidth2 = (mnDX - mnItemsWidth - 1) % nAutoSizeItems;
+ }
+ else
+ {
+ nExtraWidth = 0;
+ nExtraWidth2 = 0;
+ }
+ nX = STATUSBAR_OFFSET_X;
+ }
+
+ pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mbVisible )
+ {
+ if ( pItem->mnBits & SIB_AUTOSIZE )
+ {
+ pItem->mnExtraWidth = nExtraWidth;
+ if ( nExtraWidth2 )
+ {
+ pItem->mnExtraWidth++;
+ nExtraWidth2--;
+ }
+ }
+ else
+ pItem->mnExtraWidth = 0;
+
+ pItem->mnX = nX;
+ nX += pItem->mnWidth + pItem->mnExtraWidth + pItem->mnOffset;
+ }
+
+ pItem = mpItemList->Next();
+ }
+
+ mbFormat = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle StatusBar::ImplGetItemRectPos( USHORT nPos ) const
+{
+ Rectangle aRect;
+ ImplStatusItem* pItem;
+ pItem = mpItemList->GetObject( nPos );
+ if ( pItem )
+ {
+ if ( pItem->mbVisible )
+ {
+ aRect.Left() = pItem->mnX;
+ aRect.Right() = aRect.Left() + pItem->mnWidth + pItem->mnExtraWidth;
+ aRect.Top() = mnItemY;
+ aRect.Bottom() = mnCalcHeight - STATUSBAR_OFFSET_Y;
+ if( IsTopBorder() )
+ aRect.Bottom()+=2;
+ }
+ }
+
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT StatusBar::ImplGetFirstVisiblePos() const
+{
+ ImplStatusItem* pItem;
+
+ for( USHORT nPos = 0; nPos < mpItemList->Count(); nPos++ )
+ {
+ pItem = mpItemList->GetObject( nPos );
+ if ( pItem )
+ {
+ if ( pItem->mbVisible )
+ return nPos;
+ }
+ }
+
+ return ~0;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplDrawText( BOOL bOffScreen, long nOldTextWidth )
+{
+ // Das ueberschreiben der Item-Box verhindern
+ Rectangle aTextRect;
+ aTextRect.Left() = STATUSBAR_OFFSET_X+1;
+ aTextRect.Top() = mnTextY;
+ if ( mbVisibleItems && (GetStyle() & WB_RIGHT) )
+ aTextRect.Right() = mnDX - mnItemsWidth - 1;
+ else
+ aTextRect.Right() = mnDX - 1;
+ if ( aTextRect.Right() > aTextRect.Left() )
+ {
+ // Position ermitteln
+ XubString aStr = GetText();
+ USHORT nPos = aStr.Search( _LF );
+ if ( nPos != STRING_NOTFOUND )
+ aStr.Erase( nPos );
+
+ aTextRect.Bottom() = aTextRect.Top()+GetTextHeight()+1;
+
+ if ( bOffScreen )
+ {
+ long nMaxWidth = Max( nOldTextWidth, GetTextWidth( aStr ) );
+ Size aVirDevSize( nMaxWidth, aTextRect.GetHeight() );
+ mpImplData->mpVirDev->SetOutputSizePixel( aVirDevSize );
+ Rectangle aTempRect = aTextRect;
+ aTempRect.SetPos( Point( 0, 0 ) );
+ mpImplData->mpVirDev->DrawText( aTempRect, aStr, TEXT_DRAW_LEFT | TEXT_DRAW_TOP | TEXT_DRAW_CLIP | TEXT_DRAW_ENDELLIPSIS );
+ DrawOutDev( aTextRect.TopLeft(), aVirDevSize, Point(), aVirDevSize, *mpImplData->mpVirDev );
+ }
+ else
+ DrawText( aTextRect, aStr, TEXT_DRAW_LEFT | TEXT_DRAW_TOP | TEXT_DRAW_CLIP | TEXT_DRAW_ENDELLIPSIS );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplDrawItem( BOOL bOffScreen, USHORT nPos, BOOL bDrawText, BOOL bDrawFrame )
+{
+ Rectangle aRect = ImplGetItemRectPos( nPos );
+
+ if ( aRect.IsEmpty() )
+ return;
+
+ // Ausgabebereich berechnen
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ long nW = mpImplData->mnItemBorderWidth + 1;
+ Rectangle aTextRect( aRect.Left()+nW, aRect.Top()+nW,
+ aRect.Right()-nW, aRect.Bottom()-nW );
+ Size aTextRectSize( aTextRect.GetSize() );
+
+ if ( bOffScreen )
+ mpImplData->mpVirDev->SetOutputSizePixel( aTextRectSize );
+ else
+ {
+ Region aRegion( aTextRect );
+ SetClipRegion( aRegion );
+ }
+
+ // Text ausgeben
+ if ( bDrawText )
+ {
+ Size aTextSize( GetTextWidth( pItem->maText ), GetTextHeight() );
+ Point aTextPos = ImplGetItemTextPos( aTextRectSize, aTextSize, pItem->mnBits );
+ if ( bOffScreen )
+ mpImplData->mpVirDev->DrawText( aTextPos, pItem->maText );
+ else
+ {
+ aTextPos.X() += aTextRect.Left();
+ aTextPos.Y() += aTextRect.Top();
+ DrawText( aTextPos, pItem->maText );
+ }
+ }
+
+ // Gegebenenfalls auch DrawItem aufrufen
+ if ( pItem->mnBits & SIB_USERDRAW )
+ {
+ if ( bOffScreen )
+ {
+ mbInUserDraw = TRUE;
+ mpImplData->mpVirDev->EnableRTL( IsRTLEnabled() );
+ UserDrawEvent aODEvt( mpImplData->mpVirDev, Rectangle( Point(), aTextRectSize ), pItem->mnId );
+ UserDraw( aODEvt );
+ mpImplData->mpVirDev->EnableRTL( FALSE );
+ mbInUserDraw = FALSE;
+ }
+ else
+ {
+ UserDrawEvent aODEvt( this, aTextRect, pItem->mnId );
+ UserDraw( aODEvt );
+ }
+ }
+
+ if ( bOffScreen )
+ DrawOutDev( aTextRect.TopLeft(), aTextRectSize, Point(), aTextRectSize, *mpImplData->mpVirDev );
+ else
+ SetClipRegion();
+
+ // Frame ausgeben
+ if ( bDrawFrame )
+ {
+ if( mpImplData->mbDrawItemFrames )
+ {
+ if( !(pItem->mnBits & SIB_FLAT) )
+ {
+ USHORT nStyle;
+
+ if ( pItem->mnBits & SIB_IN )
+ nStyle = FRAME_DRAW_IN;
+ else
+ nStyle = FRAME_DRAW_OUT;
+
+ DecorationView aDecoView( this );
+ aDecoView.DrawFrame( aRect, nStyle );
+ }
+ }
+ else if( nPos != ImplGetFirstVisiblePos() )
+ {
+ // draw separator
+ Point aFrom( aRect.TopLeft() );
+ aFrom.X()--;
+ aFrom.Y()++;
+ Point aTo( aRect.BottomLeft() );
+ aTo.X()--;
+ aTo.Y()--;
+
+ DecorationView aDecoView( this );
+ aDecoView.DrawSeparator( aFrom, aTo );
+ }
+ }
+
+ if ( !ImplIsRecordLayout() )
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_DRAWITEM, (void*) sal_IntPtr(pItem->mnId) );
+}
+
+// -----------------------------------------------------------------------
+
+void DrawProgress( Window* pWindow, const Point& rPos,
+ long nOffset, long nPrgsWidth, long nPrgsHeight,
+ USHORT nPercent1, USHORT nPercent2, USHORT nPercentCount,
+ const Rectangle& rFramePosSize
+ )
+{
+ if( pWindow->IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) )
+ {
+ bool bNeedErase = ImplGetSVData()->maNWFData.mbProgressNeedsErase;
+
+ long nFullWidth = (nPrgsWidth + nOffset) * (10000 / nPercentCount);
+ long nPerc = (nPercent2 > 10000) ? 10000 : nPercent2;
+ ImplControlValue aValue( nFullWidth * (long)nPerc / 10000 );
+ Rectangle aDrawRect( rPos, Size( nFullWidth, nPrgsHeight ) );
+ Rectangle aControlRegion( aDrawRect );
+ if( bNeedErase )
+ {
+ Window* pEraseWindow = pWindow;
+ while( pEraseWindow->IsPaintTransparent() &&
+ ! pEraseWindow->ImplGetWindowImpl()->mbFrame )
+ {
+ pEraseWindow = pEraseWindow->ImplGetWindowImpl()->mpParent;
+ }
+ if( pEraseWindow == pWindow )
+ // restore background of pWindow
+ pEraseWindow->Erase( rFramePosSize );
+ else
+ {
+ // restore transparent background
+ Point aTL( pWindow->OutputToAbsoluteScreenPixel( rFramePosSize.TopLeft() ) );
+ aTL = pEraseWindow->AbsoluteScreenToOutputPixel( aTL );
+ Rectangle aRect( aTL, rFramePosSize.GetSize() );
+ pEraseWindow->Invalidate( aRect, INVALIDATE_NOCHILDREN |
+ INVALIDATE_NOCLIPCHILDREN |
+ INVALIDATE_TRANSPARENT );
+ pEraseWindow->Update();
+ }
+ pWindow->Push( PUSH_CLIPREGION );
+ pWindow->IntersectClipRegion( rFramePosSize );
+ }
+ BOOL bNativeOK = pWindow->DrawNativeControl( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
+ CTRL_STATE_ENABLED, aValue, rtl::OUString() );
+ if( bNeedErase )
+ pWindow->Pop();
+ if( bNativeOK )
+ {
+ pWindow->Flush();
+ return;
+ }
+ }
+
+ // Werte vorberechnen
+ USHORT nPerc1 = nPercent1 / nPercentCount;
+ USHORT nPerc2 = nPercent2 / nPercentCount;
+
+ if ( nPerc1 > nPerc2 )
+ {
+ // Support progress that can also decrease
+
+ // Rechteck berechnen
+ long nDX = nPrgsWidth + nOffset;
+ long nLeft = rPos.X()+((nPerc1-1)*nDX);
+ Rectangle aRect( nLeft, rPos.Y(), nLeft+nPrgsWidth, rPos.Y()+nPrgsHeight );
+
+ do
+ {
+ pWindow->Erase( aRect );
+ aRect.Left() -= nDX;
+ aRect.Right() -= nDX;
+ nPerc1--;
+ }
+ while ( nPerc1 > nPerc2 );
+
+ pWindow->Flush();
+ }
+ else if ( nPerc1 < nPerc2 )
+ {
+ // Percent-Rechtecke malen
+ // Wenn Percent2 ueber 100%, Werte anpassen
+ if ( nPercent2 > 10000 )
+ {
+ nPerc2 = 10000 / nPercentCount;
+ if ( nPerc1 >= nPerc2 )
+ nPerc1 = nPerc2-1;
+ }
+
+ // Rechteck berechnen
+ long nDX = nPrgsWidth + nOffset;
+ long nLeft = rPos.X()+(nPerc1*nDX);
+ Rectangle aRect( nLeft, rPos.Y(), nLeft+nPrgsWidth, rPos.Y()+nPrgsHeight );
+
+ do
+ {
+ pWindow->DrawRect( aRect );
+ aRect.Left() += nDX;
+ aRect.Right() += nDX;
+ nPerc1++;
+ }
+ while ( nPerc1 < nPerc2 );
+
+ // Bei mehr als 100%, lassen wir das Rechteck blinken
+ if ( nPercent2 > 10000 )
+ {
+ // an/aus-Status festlegen
+ if ( ((nPercent2 / nPercentCount) & 0x01) == (nPercentCount & 0x01) )
+ {
+ aRect.Left() -= nDX;
+ aRect.Right() -= nDX;
+ pWindow->Erase( aRect );
+ }
+ }
+
+ pWindow->Flush();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplDrawProgress( BOOL bPaint,
+ USHORT nPercent1, USHORT nPercent2 )
+{
+ bool bNative = IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL );
+ // bPaint: draw text also, else only update progress
+ if ( bPaint )
+ {
+ DrawText( maPrgsTxtPos, maPrgsTxt );
+ if( ! bNative )
+ {
+ DecorationView aDecoView( this );
+ aDecoView.DrawFrame( maPrgsFrameRect, FRAME_DRAW_IN );
+ }
+ }
+
+ Point aPos( maPrgsFrameRect.Left()+STATUSBAR_PRGS_OFFSET,
+ maPrgsFrameRect.Top()+STATUSBAR_PRGS_OFFSET );
+ long nPrgsHeight = mnPrgsSize;
+ if( bNative )
+ {
+ aPos = maPrgsFrameRect.TopLeft();
+ nPrgsHeight = maPrgsFrameRect.GetHeight();
+ }
+ DrawProgress( this, aPos, mnPrgsSize/2, mnPrgsSize, nPrgsHeight,
+ nPercent1*100, nPercent2*100, mnPercentCount, maPrgsFrameRect );
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplCalcProgressRect()
+{
+ // calculate text size
+ Size aPrgsTxtSize( GetTextWidth( maPrgsTxt ), GetTextHeight() );
+ maPrgsTxtPos.X() = STATUSBAR_OFFSET_X+1;
+
+ // calculate progress frame
+ maPrgsFrameRect.Left() = maPrgsTxtPos.X()+aPrgsTxtSize.Width()+STATUSBAR_OFFSET;
+ maPrgsFrameRect.Top() = mnItemY;
+ maPrgsFrameRect.Bottom() = mnCalcHeight - STATUSBAR_OFFSET_Y;
+ if( IsTopBorder() )
+ maPrgsFrameRect.Bottom()+=2;
+
+ // calculate size of progress rects
+ mnPrgsSize = maPrgsFrameRect.Bottom()-maPrgsFrameRect.Top()-(STATUSBAR_PRGS_OFFSET*2);
+ USHORT nMaxPercent = STATUSBAR_PRGS_COUNT;
+
+ long nMaxWidth = mnDX-STATUSBAR_OFFSET-1;
+
+ // make smaller if there are too many rects
+ while ( maPrgsFrameRect.Left()+ImplCalcProgessWidth( nMaxPercent, mnPrgsSize ) > nMaxWidth )
+ {
+ nMaxPercent--;
+ if ( nMaxPercent <= STATUSBAR_PRGS_MIN )
+ break;
+ }
+ maPrgsFrameRect.Right() = maPrgsFrameRect.Left() + ImplCalcProgessWidth( nMaxPercent, mnPrgsSize );
+
+ // save the divisor for later
+ mnPercentCount = 10000 / nMaxPercent;
+ BOOL bNativeOK = FALSE;
+ if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aValue;
+ Rectangle aControlRegion( Rectangle( (const Point&)Point(), maPrgsFrameRect.GetSize() ) );
+ Rectangle aNativeControlRegion, aNativeContentRegion;
+ if( (bNativeOK = GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
+ CTRL_STATE_ENABLED, aValue, rtl::OUString(),
+ aNativeControlRegion, aNativeContentRegion ) ) != FALSE )
+ {
+ long nProgressHeight = aNativeControlRegion.GetHeight();
+ if( nProgressHeight > maPrgsFrameRect.GetHeight() )
+ {
+ long nDelta = nProgressHeight - maPrgsFrameRect.GetHeight();
+ maPrgsFrameRect.Top() -= (nDelta - nDelta/2);
+ maPrgsFrameRect.Bottom() += nDelta/2;
+ }
+ maPrgsTxtPos.Y() = maPrgsFrameRect.Top() + (nProgressHeight - GetTextHeight())/2;
+ }
+ }
+ if( ! bNativeOK )
+ maPrgsTxtPos.Y() = mnTextY;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ // Nur bei linker Maustaste ToolBox ausloesen
+ if ( rMEvt.IsLeft() )
+ {
+ if ( mbVisibleItems )
+ {
+ Point aMousePos = rMEvt.GetPosPixel();
+ USHORT i = 0;
+
+ // Item suchen, das geklickt wurde
+ ImplStatusItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ // Ist es dieses Item
+ if ( ImplGetItemRectPos( i ).IsInside( aMousePos ) )
+ {
+ mnCurItemId = pItem->mnId;
+ if ( rMEvt.GetClicks() == 2 )
+ DoubleClick();
+ else
+ Click();
+ mnCurItemId = 0;
+
+ // Item wurde gefunden
+ return;
+ }
+
+ i++;
+ pItem = mpItemList->Next();
+ }
+ }
+
+ // Kein Item, dann nur Click oder DoubleClick
+ if ( rMEvt.GetClicks() == 2 )
+ DoubleClick();
+ else
+ Click();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::Paint( const Rectangle& )
+{
+ if ( mbFormat )
+ ImplFormat();
+
+ USHORT nItemCount = (USHORT)mpItemList->Count();
+
+ if ( mbProgressMode )
+ ImplDrawProgress( TRUE, 0, mnPercent );
+ else
+ {
+ // Text zeichen
+ if ( !mbVisibleItems || (GetStyle() & WB_RIGHT) )
+ ImplDrawText( FALSE, 0 );
+
+ // Items zeichnen
+ if ( mbVisibleItems )
+ {
+ // Items zeichnen
+ for ( USHORT i = 0; i < nItemCount; i++ )
+ ImplDrawItem( FALSE, i, TRUE, TRUE );
+ }
+ }
+
+ // draw borders
+ if( IsTopBorder() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( 0, 0 ), Point( mnDX-1, 0 ) );
+ SetLineColor( rStyleSettings.GetLightColor() );
+ DrawLine( Point( 0, 1 ), Point( mnDX-1, 1 ) );
+ }
+
+ if ( IsBottomBorder() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( 0, mnDY-2 ), Point( mnDX-1, mnDY-2 ) );
+ SetLineColor( rStyleSettings.GetLightColor() );
+ DrawLine( Point( 0, mnDY-1 ), Point( mnDX-1, mnDY-1 ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::Move()
+{
+ Window::Move();
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::Resize()
+{
+ // Breite und Hoehe abfragen und merken
+ Size aSize = GetOutputSizePixel();
+ mnDX = aSize.Width();
+ mnDY = aSize.Height();
+ mnCalcHeight = mnDY;
+ // subtract border
+ if( IsTopBorder() )
+ mnCalcHeight -= 2;
+ if ( IsBottomBorder() )
+ mnCalcHeight -= 2;
+
+ mnItemY = STATUSBAR_OFFSET_Y;
+ if( IsTopBorder() )
+ mnItemY += 2;
+ mnTextY = (mnCalcHeight-GetTextHeight())/2;
+ if( IsTopBorder() )
+ mnTextY += 2;
+
+ // Formatierung neu ausloesen
+ mbFormat = TRUE;
+
+ if ( mbProgressMode )
+ ImplCalcProgressRect();
+
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::RequestHelp( const HelpEvent& rHEvt )
+{
+ // no keyboard help in status bar
+ if( rHEvt.KeyboardActivated() )
+ return;
+
+ USHORT nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
+
+ if ( nItemId )
+ {
+ Rectangle aItemRect = GetItemRect( nItemId );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.Left() = aPt.X();
+ aItemRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.Right() = aPt.X();
+ aItemRect.Bottom() = aPt.Y();
+
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ {
+ XubString aStr = GetHelpText( nItemId );
+ Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
+ return;
+ }
+ else if ( rHEvt.GetMode() & HELPMODE_QUICK )
+ {
+ XubString aStr = GetQuickHelpText( nItemId );
+ // Show quickhelp if available
+ if( aStr.Len() )
+ {
+ Help::ShowQuickHelp( this, aItemRect, aStr );
+ return;
+ }
+ aStr = GetItemText( nItemId );
+ // show a quick help if item text doesn't fit
+ if ( GetTextWidth( aStr ) > aItemRect.GetWidth() )
+ {
+ Help::ShowQuickHelp( this, aItemRect, aStr );
+ return;
+ }
+ }
+ else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
+ {
+ String aCommand = GetItemCommand( nItemId );
+ ULONG nHelpId = GetHelpId( nItemId );
+
+ if ( aCommand.Len() || nHelpId )
+ {
+ // Wenn eine Hilfe existiert, dann ausloesen
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if ( aCommand.Len() )
+ pHelp->Start( aCommand, this );
+ else if ( nHelpId )
+ pHelp->Start( nHelpId, this );
+ }
+ return;
+ }
+ }
+ }
+
+ Window::RequestHelp( rHEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ ImplFormat();
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ Invalidate();
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ mbFormat = TRUE;
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_DISPLAY) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ mbFormat = TRUE;
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ ImplStatusItem* pItem = mpItemList->First();
+ long nFudge = GetTextHeight() / 4;
+ while ( pItem )
+ {
+ long nWidth = GetTextWidth( pItem->maText ) + nFudge;
+ if( nWidth > pItem->mnWidth + STATUSBAR_OFFSET )
+ pItem->mnWidth = nWidth + STATUSBAR_OFFSET;
+ pItem = mpItemList->Next();
+ }
+ Size aSize = GetSizePixel();
+ // do not disturb current width, since
+ // CalcWindowSizePixel calculates a minimum width
+ aSize.Height() = CalcWindowSizePixel().Height();
+ SetSizePixel( aSize );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::Click()
+{
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_CLICK );
+ maClickHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::DoubleClick()
+{
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_DOUBLECLICK );
+ maDoubleClickHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::UserDraw( const UserDrawEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::InsertItem( USHORT nItemId, ULONG nWidth,
+ StatusBarItemBits nBits,
+ long nOffset, USHORT nPos )
+{
+ DBG_ASSERT( nItemId, "StatusBar::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == STATUSBAR_ITEM_NOTFOUND,
+ "StatusBar::InsertItem(): ItemId already exists" );
+
+ // IN und CENTER sind Default
+ if ( !(nBits & (SIB_IN | SIB_OUT | SIB_FLAT)) )
+ nBits |= SIB_IN;
+ if ( !(nBits & (SIB_LEFT | SIB_RIGHT | SIB_CENTER)) )
+ nBits |= SIB_CENTER;
+
+ // Item anlegen
+ long nFudge = GetTextHeight()/4;
+ ImplStatusItem* pItem = new ImplStatusItem;
+ pItem->mnId = nItemId;
+ pItem->mnBits = nBits;
+ pItem->mnWidth = (long)nWidth+nFudge+STATUSBAR_OFFSET;
+ pItem->mnOffset = nOffset;
+ pItem->mnHelpId = 0;
+ pItem->mpUserData = 0;
+ pItem->mbVisible = TRUE;
+
+ // Item in die Liste einfuegen
+ mpItemList->Insert( pItem, nPos );
+
+ mbFormat = TRUE;
+ if ( ImplIsItemUpdate() )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_ITEMADDED, (void*) sal_IntPtr(nItemId) );
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::RemoveItem( USHORT nItemId )
+{
+ USHORT nPos = GetItemPos( nItemId );
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->Remove( nPos );
+ delete pItem;
+
+ mbFormat = TRUE;
+ if ( ImplIsItemUpdate() )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_ITEMREMOVED, (void*) sal_IntPtr(nItemId) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ShowItem( USHORT nItemId )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ if ( !pItem->mbVisible )
+ {
+ pItem->mbVisible = TRUE;
+
+ mbFormat = TRUE;
+ if ( ImplIsItemUpdate() )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_SHOWITEM, (void*) sal_IntPtr(nItemId) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::HideItem( USHORT nItemId )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ if ( pItem->mbVisible )
+ {
+ pItem->mbVisible = FALSE;
+
+ mbFormat = TRUE;
+ if ( ImplIsItemUpdate() )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_HIDEITEM, (void*) sal_IntPtr(nItemId) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL StatusBar::IsItemVisible( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->mbVisible;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ShowItems()
+{
+ if ( !mbVisibleItems )
+ {
+ mbVisibleItems = TRUE;
+ if ( !mbProgressMode )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_SHOWALLITEMS );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::HideItems()
+{
+ if ( mbVisibleItems )
+ {
+ mbVisibleItems = FALSE;
+ if ( !mbProgressMode )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_HIDEALLITEMS );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::CopyItems( const StatusBar& rStatusBar )
+{
+ // Alle Items entfernen
+ ImplStatusItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ delete pItem;
+ pItem = mpItemList->Next();
+ }
+
+ // Items aus der Liste loeschen
+ mpItemList->Clear();
+
+ // Items kopieren
+ ULONG i = 0;
+ pItem = rStatusBar.mpItemList->GetObject( i );
+ while ( pItem )
+ {
+ mpItemList->Insert( new ImplStatusItem( *pItem ), LIST_APPEND );
+ i++;
+ pItem = rStatusBar.mpItemList->GetObject( i );
+ }
+
+ mbFormat = TRUE;
+ if ( ImplIsItemUpdate() )
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::Clear()
+{
+ // Alle Item loeschen
+ ImplStatusItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ delete pItem;
+ pItem = mpItemList->Next();
+ }
+
+ // Items aus der Liste loeschen
+ mpItemList->Clear();
+
+ mbFormat = TRUE;
+ if ( ImplIsItemUpdate() )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_ALLITEMSREMOVED );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT StatusBar::GetItemCount() const
+{
+ return (USHORT)mpItemList->Count();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT StatusBar::GetItemId( USHORT nPos ) const
+{
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ if ( pItem )
+ return pItem->mnId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT StatusBar::GetItemPos( USHORT nItemId ) const
+{
+ ImplStatusItem* pItem = mpItemList->First();
+ while ( pItem )
+ {
+ if ( pItem->mnId == nItemId )
+ return (USHORT)mpItemList->GetCurPos();
+
+ pItem = mpItemList->Next();
+ }
+
+ return STATUSBAR_ITEM_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT StatusBar::GetItemId( const Point& rPos ) const
+{
+ if ( AreItemsVisible() && !mbFormat )
+ {
+ USHORT nItemCount = GetItemCount();
+ USHORT nPos;
+ for ( nPos = 0; nPos < nItemCount; nPos++ )
+ {
+ // Rechteck holen
+ Rectangle aRect = ImplGetItemRectPos( nPos );
+ if ( aRect.IsInside( rPos ) )
+ return mpItemList->GetObject( nPos )->mnId;
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle StatusBar::GetItemRect( USHORT nItemId ) const
+{
+ Rectangle aRect;
+
+ if ( AreItemsVisible() && !mbFormat )
+ {
+ USHORT nPos = GetItemPos( nItemId );
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ // Rechteck holen und Rahmen abziehen
+ aRect = ImplGetItemRectPos( nPos );
+ long nW = mpImplData->mnItemBorderWidth+1;
+ aRect.Top() += nW-1;
+ aRect.Bottom() -= nW-1;
+ aRect.Left() += nW;
+ aRect.Right() -= nW;
+ return aRect;
+ }
+ }
+
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+Point StatusBar::GetItemTextPos( USHORT nItemId ) const
+{
+ if ( !mbFormat )
+ {
+ USHORT nPos = GetItemPos( nItemId );
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ // Rechteck holen
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ Rectangle aRect = ImplGetItemRectPos( nPos );
+ long nW = mpImplData->mnItemBorderWidth + 1;
+ Rectangle aTextRect( aRect.Left()+nW, aRect.Top()+nW,
+ aRect.Right()-nW, aRect.Bottom()-nW );
+ Point aPos = ImplGetItemTextPos( aTextRect.GetSize(),
+ Size( GetTextWidth( pItem->maText ), GetTextHeight() ),
+ pItem->mnBits );
+ if ( !mbInUserDraw )
+ {
+ aPos.X() += aTextRect.Left();
+ aPos.Y() += aTextRect.Top();
+ }
+ return aPos;
+ }
+ }
+
+ return Point();
+}
+
+// -----------------------------------------------------------------------
+
+ULONG StatusBar::GetItemWidth( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->mnWidth;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+StatusBarItemBits StatusBar::GetItemBits( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->mnBits;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+long StatusBar::GetItemOffset( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->mnOffset;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetItemText( USHORT nItemId, const XubString& rText )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+
+ if ( pItem->maText != rText )
+ {
+ pItem->maText = rText;
+
+ // adjust item width - see also DataChanged()
+ long nFudge = GetTextHeight()/4;
+ long nWidth = GetTextWidth( pItem->maText ) + nFudge;
+ if( (nWidth > pItem->mnWidth + STATUSBAR_OFFSET) ||
+ ((nWidth < pItem->mnWidth) && (mnDX - STATUSBAR_OFFSET) < mnItemsWidth ))
+ {
+ pItem->mnWidth = nWidth + STATUSBAR_OFFSET;
+ ImplFormat();
+ Invalidate();
+ }
+
+ // Item neu Zeichen, wenn StatusBar sichtbar und
+ // UpdateMode gesetzt ist
+ if ( pItem->mbVisible && !mbFormat && ImplIsItemUpdate() )
+ {
+ Update();
+ ImplDrawItem( TRUE, nPos, TRUE, FALSE );
+ Flush();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& StatusBar::GetItemText( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->maText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetItemCommand( USHORT nItemId, const XubString& rCommand )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+
+ if ( pItem->maCommand != rCommand )
+ pItem->maCommand = rCommand;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& StatusBar::GetItemCommand( USHORT nItemId )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->maCommand;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetItemData( USHORT nItemId, void* pNewData )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ pItem->mpUserData = pNewData;
+
+ // Wenn es ein User-Item ist, DrawItem-Aufrufen
+ if ( (pItem->mnBits & SIB_USERDRAW) && pItem->mbVisible &&
+ !mbFormat && ImplIsItemUpdate() )
+ {
+ Update();
+ ImplDrawItem( TRUE, nPos, FALSE, FALSE );
+ Flush();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void* StatusBar::GetItemData( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->mpUserData;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetHelpText( USHORT nItemId, const XubString& rText )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ mpItemList->GetObject( nPos )->maHelpText = rText;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& StatusBar::GetHelpText( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ if ( !pItem->maHelpText.Len() && ( pItem->mnHelpId || pItem->maCommand.Len() ))
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if ( pItem->maCommand.Len() )
+ pItem->maHelpText = pHelp->GetHelpText( pItem->maCommand, this );
+ if ( !pItem->maHelpText.Len() && pItem->mnHelpId )
+ pItem->maHelpText = pHelp->GetHelpText( pItem->mnHelpId, this );
+ }
+ }
+
+ return pItem->maHelpText;
+ }
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetQuickHelpText( USHORT nItemId, const XubString& rText )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ mpItemList->GetObject( nPos )->maQuickHelpText = rText;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& StatusBar::GetQuickHelpText( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+ return pItem->maQuickHelpText;
+ }
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetHelpId( USHORT nItemId, ULONG nHelpId )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ mpItemList->GetObject( nPos )->mnHelpId = nHelpId;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG StatusBar::GetHelpId( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->mnHelpId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ImplCalcBorder( )
+{
+ mnCalcHeight = mnDY;
+ // subtract border
+ if( IsTopBorder() )
+ {
+ mnCalcHeight -= 2;
+ mnTextY += 2;
+ mnItemY += 2;
+ }
+ if ( IsBottomBorder() )
+ mnCalcHeight -= 2;
+ mbFormat = TRUE;
+ Invalidate();
+}
+
+void StatusBar::SetBottomBorder( BOOL bBottomBorder )
+{
+ if ( mbBottomBorder != bBottomBorder )
+ {
+ mbBottomBorder = bBottomBorder;
+ ImplCalcBorder();
+ }
+}
+
+void StatusBar::SetTopBorder( BOOL bTopBorder )
+{
+ if ( mpImplData->mbTopBorder != static_cast<bool>(bTopBorder) )
+ {
+ mpImplData->mbTopBorder = static_cast<bool>(bTopBorder);
+ ImplCalcBorder();
+ }
+}
+
+BOOL StatusBar::IsTopBorder() const
+{
+ return mpImplData->mbTopBorder;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::StartProgressMode( const XubString& rText )
+{
+ DBG_ASSERT( !mbProgressMode, "StatusBar::StartProgressMode(): progress mode is active" );
+
+ mbProgressMode = TRUE;
+ mnPercent = 0;
+ maPrgsTxt = rText;
+
+ // Groessen berechnen
+ ImplCalcProgressRect();
+
+ // Paint ausloesen (dort wird der Text und der Frame gemalt)
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Color aPrgsColor = rStyleSettings.GetHighlightColor();
+ if ( aPrgsColor == rStyleSettings.GetFaceColor() )
+ aPrgsColor = rStyleSettings.GetDarkShadowColor();
+ SetLineColor();
+ SetFillColor( aPrgsColor );
+ if ( IsReallyVisible() )
+ {
+ Invalidate();
+ Update();
+ Flush();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetProgressValue( USHORT nNewPercent )
+{
+ DBG_ASSERT( mbProgressMode, "StatusBar::SetProgressValue(): no progrss mode" );
+ DBG_ASSERTWARNING( nNewPercent <= 100, "StatusBar::SetProgressValue(): nPercent > 100" );
+
+ if ( mbProgressMode
+ && IsReallyVisible()
+ && (!mnPercent || (mnPercent != nNewPercent)) )
+ {
+ Update();
+ SetLineColor();
+ ImplDrawProgress( FALSE, mnPercent, nNewPercent );
+ Flush();
+ }
+ mnPercent = nNewPercent;
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::EndProgressMode()
+{
+ DBG_ASSERT( mbProgressMode, "StatusBar::EndProgressMode(): no progress mode" );
+
+ mbProgressMode = FALSE;
+ maPrgsTxt.Erase();
+
+ // Paint neu ausloesen um StatusBar wieder herzustellen
+ SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
+ if ( IsReallyVisible() )
+ {
+ Invalidate();
+ Update();
+ Flush();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::ResetProgressMode()
+{
+ if ( mbProgressMode )
+ {
+ mnPercent = 0;
+ maPrgsTxt.Erase();
+ if ( IsReallyVisible() )
+ {
+ Invalidate();
+ Update();
+ Flush();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetText( const XubString& rText )
+{
+ if ( (!mbVisibleItems || (GetStyle() & WB_RIGHT)) && !mbProgressMode &&
+ IsReallyVisible() && IsUpdateMode() )
+ {
+ if ( mbFormat )
+ {
+ Invalidate();
+ Window::SetText( rText );
+ }
+ else
+ {
+ Update();
+ long nOldTextWidth = GetTextWidth( GetText() );
+ Window::SetText( rText );
+ ImplDrawText( TRUE, nOldTextWidth );
+ Flush();
+ }
+ }
+ else if ( mbProgressMode )
+ {
+ maPrgsTxt = rText;
+ if ( IsReallyVisible() )
+ {
+ Invalidate();
+ Update();
+ Flush();
+ }
+ }
+ else
+ Window::SetText( rText );
+}
+
+// -----------------------------------------------------------------------
+
+Size StatusBar::CalcWindowSizePixel() const
+{
+ ULONG i = 0;
+ ULONG nCount = mpItemList->Count();
+ long nOffset = 0;
+ long nCalcWidth = (STATUSBAR_OFFSET_X*2);
+ long nCalcHeight;
+
+ while ( i < nCount )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( i );
+ nCalcWidth += pItem->mnWidth + nOffset;
+ nOffset = pItem->mnOffset;
+ i++;
+ }
+
+ long nMinHeight = GetTextHeight();
+ const long nBarTextOffset = STATUSBAR_OFFSET_TEXTY*2;
+ long nProgressHeight = nMinHeight + nBarTextOffset;
+ // FIXME: IsNativeControlSupported and GetNativeControlRegion should be const ?
+ StatusBar* pThis = const_cast<StatusBar*>( this );
+ if( pThis->IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) )
+ {
+ ImplControlValue aValue;
+ Rectangle aControlRegion( (const Point&)Point(), Size( nCalcWidth, nMinHeight ) );
+ Rectangle aNativeControlRegion, aNativeContentRegion;
+ if( pThis->GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
+ CTRL_STATE_ENABLED, aValue, rtl::OUString(),
+ aNativeControlRegion, aNativeContentRegion ) )
+ {
+ nProgressHeight = aNativeControlRegion.GetHeight();
+ }
+ }
+
+ if( mpImplData->mbDrawItemFrames &&
+ pThis->IsNativeControlSupported( CTRL_FRAME, PART_BORDER ) )
+ {
+ ImplControlValue aControlValue( FRAME_DRAW_NODRAW );
+ Rectangle aBound, aContent;
+ Rectangle aNatRgn( Point( 0, 0 ), Size( 150, 50 ) );
+ if( pThis->GetNativeControlRegion(CTRL_FRAME, PART_BORDER,
+ aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ mpImplData->mnItemBorderWidth =
+ ( aBound.GetHeight() - aContent.GetHeight() ) / 2;
+ }
+ }
+
+ nCalcHeight = nMinHeight+nBarTextOffset + 2*mpImplData->mnItemBorderWidth;
+ if( nCalcHeight < nProgressHeight+2 )
+ nCalcHeight = nProgressHeight+2;
+
+ // add border
+ if( IsTopBorder() )
+ nCalcHeight += 2;
+ if ( IsBottomBorder() )
+ nCalcHeight += 2;
+
+ return Size( nCalcWidth, nCalcHeight );
+}
+
+
+// -----------------------------------------------------------------------
+
+void StatusBar::SetAccessibleName( USHORT nItemId, const XubString& rName )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ {
+ ImplStatusItem* pItem = mpItemList->GetObject( nPos );
+
+ if ( pItem->maAccessibleName != rName )
+ {
+ pItem->maAccessibleName = rName;
+ ImplCallEventListeners( VCLEVENT_STATUSBAR_NAMECHANGED, (void*) sal_IntPtr(pItem->mnId) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& StatusBar::GetAccessibleName( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != STATUSBAR_ITEM_NOTFOUND )
+ return mpItemList->GetObject( nPos )->maAccessibleName;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/source/window/syschild.cxx b/vcl/source/window/syschild.cxx
new file mode 100644
index 000000000000..ef71f83df1ee
--- /dev/null
+++ b/vcl/source/window/syschild.cxx
@@ -0,0 +1,192 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salinst.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/window.hxx>
+#include <vcl/salobj.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#ifndef _SV_WIDNOW_H
+#include <vcl/window.h>
+#endif
+#include <vcl/svapp.hxx>
+#include <vcl/syschild.hxx>
+
+
+
+// =======================================================================
+
+long ImplSysChildProc( void* pInst, SalObject* /* pObject */,
+ USHORT nEvent, const void* /* pEvent */ )
+{
+ SystemChildWindow* pWindow = (SystemChildWindow*)pInst;
+ long nRet = 0;
+
+ ImplDelData aDogTag( pWindow );
+ switch ( nEvent )
+ {
+ case SALOBJ_EVENT_GETFOCUS:
+ // Focus holen und zwar so, das alle Handler gerufen
+ // werden, als ob dieses Fenster den Focus bekommt,
+ // ohne das der Frame den Focus wieder klaut
+ pWindow->ImplGetFrameData()->mbSysObjFocus = TRUE;
+ pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = TRUE;
+ pWindow->ToTop( TOTOP_NOGRABFOCUS );
+ if( aDogTag.IsDead() )
+ break;
+ pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = FALSE;
+ pWindow->ImplGetFrameData()->mbInSysObjFocusHdl = TRUE;
+ pWindow->GrabFocus();
+ if( aDogTag.IsDead() )
+ break;
+ pWindow->ImplGetFrameData()->mbInSysObjFocusHdl = FALSE;
+ break;
+
+ case SALOBJ_EVENT_LOSEFOCUS:
+ // Hintenrum einen LoseFocus ausloesen, das der Status
+ // der Fenster dem entsprechenden Activate-Status
+ // entspricht
+ pWindow->ImplGetFrameData()->mbSysObjFocus = FALSE;
+ if ( !pWindow->ImplGetFrameData()->mnFocusId )
+ {
+ pWindow->ImplGetFrameData()->mbStartFocusState = TRUE;
+ Application::PostUserEvent( pWindow->ImplGetFrameData()->mnFocusId, LINK( pWindow->ImplGetFrameWindow(), Window, ImplAsyncFocusHdl ) );
+ }
+ break;
+
+ case SALOBJ_EVENT_TOTOP:
+ pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = TRUE;
+ if ( !Application::GetFocusWindow() || pWindow->HasChildPathFocus() )
+ pWindow->ToTop( TOTOP_NOGRABFOCUS );
+ else
+ pWindow->ToTop();
+ if( aDogTag.IsDead() )
+ break;
+ pWindow->GrabFocus();
+ if( aDogTag.IsDead() )
+ break;
+ pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = FALSE;
+ break;
+ }
+
+ return nRet;
+}
+
+// =======================================================================
+
+void SystemChildWindow::ImplInitSysChild( Window* pParent, WinBits nStyle, SystemWindowData *pData, BOOL bShow )
+{
+ mpWindowImpl->mpSysObj = ImplGetSVData()->mpDefInst->CreateObject( pParent->ImplGetFrame(), pData, bShow );
+
+ Window::ImplInit( pParent, nStyle, NULL );
+
+ // Wenn es ein richtiges SysChild ist, dann painten wir auch nicht
+ if ( GetSystemData() )
+ {
+ mpWindowImpl->mpSysObj->SetCallback( this, ImplSysChildProc );
+ SetParentClipMode( PARENTCLIPMODE_CLIP );
+ SetBackground();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SystemChildWindow::SystemChildWindow( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_SYSTEMCHILDWINDOW )
+{
+ ImplInitSysChild( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+SystemChildWindow::SystemChildWindow( Window* pParent, WinBits nStyle, SystemWindowData *pData, BOOL bShow ) :
+ Window( WINDOW_SYSTEMCHILDWINDOW )
+{
+ ImplInitSysChild( pParent, nStyle, pData, bShow );
+}
+
+// -----------------------------------------------------------------------
+
+SystemChildWindow::SystemChildWindow( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_SYSTEMCHILDWINDOW )
+{
+ rResId.SetRT( RSC_WINDOW );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInitSysChild( pParent, nStyle, NULL );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+SystemChildWindow::~SystemChildWindow()
+{
+ Hide();
+ if ( mpWindowImpl->mpSysObj )
+ {
+ ImplGetSVData()->mpDefInst->DestroyObject( mpWindowImpl->mpSysObj );
+ mpWindowImpl->mpSysObj = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* SystemChildWindow::GetSystemData() const
+{
+ if ( mpWindowImpl->mpSysObj )
+ return mpWindowImpl->mpSysObj->GetSystemData();
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemChildWindow::EnableEraseBackground( BOOL bEnable )
+{
+ if ( mpWindowImpl->mpSysObj )
+ mpWindowImpl->mpSysObj->EnableEraseBackground( bEnable );
+}
+
+BOOL SystemChildWindow::IsEraseBackgroundEnabled()
+{
+ if ( mpWindowImpl->mpSysObj )
+ return mpWindowImpl->mpSysObj->IsEraseBackgroundEnabled();
+ else
+ return FALSE;
+}
diff --git a/vcl/source/window/syswin.cxx b/vcl/source/window/syswin.cxx
new file mode 100644
index 000000000000..f3624ef56f59
--- /dev/null
+++ b/vcl/source/window/syswin.cxx
@@ -0,0 +1,1086 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salframe.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/window.h>
+#include <vcl/brdwin.hxx>
+#include <vcl/sound.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <vcl/unowrap.hxx>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+// =======================================================================
+class SystemWindow::ImplData
+{
+public:
+ ImplData();
+ ~ImplData();
+
+ TaskPaneList* mpTaskPaneList;
+ Size maMaxOutSize;
+ rtl::OUString maRepresentedURL;
+};
+
+SystemWindow::ImplData::ImplData()
+{
+ mpTaskPaneList = NULL;
+ maMaxOutSize = Size( SHRT_MAX, SHRT_MAX );
+}
+
+SystemWindow::ImplData::~ImplData()
+{
+ if( mpTaskPaneList )
+ delete mpTaskPaneList;
+}
+
+// =======================================================================
+
+SystemWindow::SystemWindow( WindowType nType ) :
+ Window( nType )
+{
+ mpImplData = new ImplData;
+ mpWindowImpl->mbSysWin = TRUE;
+ mpWindowImpl->mnActivateMode = ACTIVATE_MODE_GRABFOCUS;
+
+ mpMenuBar = NULL;
+ mbPined = FALSE;
+ mbRollUp = FALSE;
+ mbRollFunc = FALSE;
+ mbDockBtn = FALSE;
+ mbHideBtn = FALSE;
+ mbSysChild = FALSE;
+ mnMenuBarMode = MENUBAR_MODE_NORMAL;
+ mnIcon = 0;
+}
+
+SystemWindow::~SystemWindow()
+{
+ delete mpImplData;
+ mpImplData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+long SystemWindow::Notify( NotifyEvent& rNEvt )
+{
+ // capture KeyEvents for menu handling
+ if ( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ MenuBar* pMBar = mpMenuBar;
+ if ( !pMBar && ( GetType() == WINDOW_FLOATINGWINDOW ) )
+ {
+ Window* pWin = ImplGetFrameWindow()->ImplGetWindow();
+ if( pWin && pWin->IsSystemWindow() )
+ pMBar = ((SystemWindow*)pWin)->GetMenuBar();
+ }
+ if ( pMBar && pMBar->ImplHandleKeyEvent( *rNEvt.GetKeyEvent(), FALSE ) )
+ return TRUE;
+ }
+
+ return Window::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long SystemWindow::PreNotify( NotifyEvent& rNEvt )
+{
+ // capture KeyEvents for taskpane cycling
+ if ( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ if( rNEvt.GetKeyEvent()->GetKeyCode().GetCode() == KEY_F6 &&
+ rNEvt.GetKeyEvent()->GetKeyCode().IsMod1() &&
+ !rNEvt.GetKeyEvent()->GetKeyCode().IsShift() )
+ {
+ // Ctrl-F6 goes directly to the document
+ GrabFocusToDocument();
+ return TRUE;
+ }
+ else
+ {
+ TaskPaneList *pTList = mpImplData->mpTaskPaneList;
+ if( !pTList && ( GetType() == WINDOW_FLOATINGWINDOW ) )
+ {
+ Window* pWin = ImplGetFrameWindow()->ImplGetWindow();
+ if( pWin && pWin->IsSystemWindow() )
+ pTList = ((SystemWindow*)pWin)->mpImplData->mpTaskPaneList;
+ }
+ if( !pTList )
+ {
+ // search topmost system window which is the one to handle dialog/toolbar cycling
+ SystemWindow *pSysWin = this;
+ Window *pWin = this;
+ while( pWin )
+ {
+ pWin = pWin->GetParent();
+ if( pWin && pWin->IsSystemWindow() )
+ pSysWin = (SystemWindow*) pWin;
+ }
+ pTList = pSysWin->mpImplData->mpTaskPaneList;
+ }
+ if( pTList && pTList->HandleKeyEvent( *rNEvt.GetKeyEvent() ) )
+ return TRUE;
+ }
+ }
+ return Window::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+TaskPaneList* SystemWindow::GetTaskPaneList()
+{
+ if( mpImplData->mpTaskPaneList )
+ return mpImplData->mpTaskPaneList ;
+ else
+ {
+ mpImplData->mpTaskPaneList = new TaskPaneList();
+ MenuBar* pMBar = mpMenuBar;
+ if ( !pMBar && ( GetType() == WINDOW_FLOATINGWINDOW ) )
+ {
+ Window* pWin = ImplGetFrameWindow()->ImplGetWindow();
+ if ( pWin && pWin->IsSystemWindow() )
+ pMBar = ((SystemWindow*)pWin)->GetMenuBar();
+ }
+ if( pMBar )
+ mpImplData->mpTaskPaneList->AddWindow( pMBar->ImplGetWindow() );
+ return mpImplData->mpTaskPaneList;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SystemWindow::Close()
+{
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE );
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ ImplRemoveDel( &aDelData );
+
+ if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() )
+ return FALSE;
+
+ // Is Window not closeable, ignore close
+ Window* pBorderWin = ImplGetBorderWindow();
+ WinBits nStyle;
+ if ( pBorderWin )
+ nStyle = pBorderWin->GetStyle();
+ else
+ nStyle = GetStyle();
+ if ( !(nStyle & WB_CLOSEABLE) )
+ {
+ Sound::Beep( SOUND_DISABLE, this );
+ return FALSE;
+ }
+
+ Hide();
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::TitleButtonClick( USHORT )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::Pin()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::Roll()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::Resizing( Size& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetZLevel( BYTE nLevel )
+{
+ Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+ if ( pWindow->mpWindowImpl->mbOverlapWin && !pWindow->mpWindowImpl->mbFrame )
+ {
+ BYTE nOldLevel = pWindow->mpWindowImpl->mpOverlapData->mnTopLevel;
+ pWindow->mpWindowImpl->mpOverlapData->mnTopLevel = nLevel;
+ // Wenn der neue Level groesser als der alte ist, schieben
+ // wir das Fenster nach hinten
+ if ( !IsReallyVisible() && (nLevel > nOldLevel) && pWindow->mpWindowImpl->mpNext )
+ {
+ // Fenster aus der Liste entfernen
+ if ( pWindow->mpWindowImpl->mpPrev )
+ pWindow->mpWindowImpl->mpPrev->mpWindowImpl->mpNext = pWindow->mpWindowImpl->mpNext;
+ else
+ pWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = pWindow->mpWindowImpl->mpNext;
+ pWindow->mpWindowImpl->mpNext->mpWindowImpl->mpPrev = pWindow->mpWindowImpl->mpPrev;
+ pWindow->mpWindowImpl->mpNext = NULL;
+ // und Fenster wieder in die Liste am Ende eintragen
+ pWindow->mpWindowImpl->mpPrev = pWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
+ pWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = pWindow;
+ pWindow->mpWindowImpl->mpPrev->mpWindowImpl->mpNext = pWindow;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetRepresentedURL( const rtl::OUString& i_rURL )
+{
+ bool bChanged = (i_rURL != mpImplData->maRepresentedURL);
+ mpImplData->maRepresentedURL = i_rURL;
+ if ( !mbSysChild && bChanged )
+ {
+ const Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+
+ if ( pWindow->mpWindowImpl->mbFrame )
+ pWindow->mpWindowImpl->mpFrame->SetRepresentedURL( i_rURL );
+ }
+}
+// -----------------------------------------------------------------------
+
+const rtl::OUString& SystemWindow::GetRepresentedURL() const
+{
+ return mpImplData->maRepresentedURL;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetIcon( USHORT nIcon )
+{
+ if ( mnIcon == nIcon )
+ return;
+
+ mnIcon = nIcon;
+
+ if ( !mbSysChild )
+ {
+ const Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+
+ if ( pWindow->mpWindowImpl->mbFrame )
+ pWindow->mpWindowImpl->mpFrame->SetIcon( nIcon );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BYTE SystemWindow::GetZLevel() const
+{
+ const Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+ if ( pWindow->mpWindowImpl->mpOverlapData )
+ return pWindow->mpWindowImpl->mpOverlapData->mnTopLevel;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::EnableSaveBackground( BOOL bSave )
+{
+ if( ImplGetSVData()->maWinData.mbNoSaveBackground )
+ bSave = false;
+
+ Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+ if ( pWindow->mpWindowImpl->mbOverlapWin && !pWindow->mpWindowImpl->mbFrame )
+ {
+ pWindow->mpWindowImpl->mpOverlapData->mbSaveBack = bSave;
+ if ( !bSave )
+ pWindow->ImplDeleteOverlapBackground();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SystemWindow::IsSaveBackgroundEnabled() const
+{
+ const Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+ if ( pWindow->mpWindowImpl->mpOverlapData )
+ return pWindow->mpWindowImpl->mpOverlapData->mbSaveBack;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::ShowTitleButton( USHORT nButton, BOOL bVisible )
+{
+ if ( nButton == TITLE_BUTTON_DOCKING )
+ {
+ if ( mbDockBtn != bVisible )
+ {
+ mbDockBtn = bVisible;
+ if ( mpWindowImpl->mpBorderWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetDockButton( bVisible );
+ }
+ }
+ else if ( nButton == TITLE_BUTTON_HIDE )
+ {
+ if ( mbHideBtn != bVisible )
+ {
+ mbHideBtn = bVisible;
+ if ( mpWindowImpl->mpBorderWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetHideButton( bVisible );
+ }
+ }
+ else if ( nButton == TITLE_BUTTON_MENU )
+ {
+ if ( mpWindowImpl->mpBorderWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuButton( bVisible );
+ }
+ else
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SystemWindow::IsTitleButtonVisible( USHORT nButton ) const
+{
+ if ( nButton == TITLE_BUTTON_DOCKING )
+ return mbDockBtn;
+ else /* if ( nButton == TITLE_BUTTON_HIDE ) */
+ return mbHideBtn;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetPin( BOOL bPin )
+{
+ if ( bPin != mbPined )
+ {
+ mbPined = bPin;
+ if ( mpWindowImpl->mpBorderWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetPin( bPin );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::RollUp()
+{
+ if ( !mbRollUp )
+ {
+ maOrgSize = GetOutputSizePixel();
+ mbRollFunc = TRUE;
+ Size aSize = maRollUpOutSize;
+ if ( !aSize.Width() )
+ aSize.Width() = GetOutputSizePixel().Width();
+ mbRollUp = TRUE;
+ if ( mpWindowImpl->mpBorderWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetRollUp( TRUE, aSize );
+ else
+ SetOutputSizePixel( aSize );
+ mbRollFunc = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::RollDown()
+{
+ if ( mbRollUp )
+ {
+ mbRollUp = FALSE;
+ if ( mpWindowImpl->mpBorderWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetRollUp( FALSE, maOrgSize );
+ else
+ SetOutputSizePixel( maOrgSize );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetMinOutputSizePixel( const Size& rSize )
+{
+ maMinOutSize = rSize;
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMinOutputSize( rSize.Width(), rSize.Height() );
+ if ( mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame )
+ mpWindowImpl->mpBorderWindow->mpWindowImpl->mpFrame->SetMinClientSize( rSize.Width(), rSize.Height() );
+ }
+ else if ( mpWindowImpl->mbFrame )
+ mpWindowImpl->mpFrame->SetMinClientSize( rSize.Width(), rSize.Height() );
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetMaxOutputSizePixel( const Size& rSize )
+{
+ Size aSize( rSize );
+ if( aSize.Width() > SHRT_MAX || aSize.Width() <= 0 )
+ aSize.Width() = SHRT_MAX;
+ if( aSize.Height() > SHRT_MAX || aSize.Height() <= 0 )
+ aSize.Height() = SHRT_MAX;
+
+ mpImplData->maMaxOutSize = aSize;
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMaxOutputSize( aSize.Width(), aSize.Height() );
+ if ( mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame )
+ mpWindowImpl->mpBorderWindow->mpWindowImpl->mpFrame->SetMaxClientSize( aSize.Width(), aSize.Height() );
+ }
+ else if ( mpWindowImpl->mbFrame )
+ mpWindowImpl->mpFrame->SetMaxClientSize( aSize.Width(), aSize.Height() );
+}
+
+const Size& SystemWindow::GetMaxOutputSizePixel() const
+{
+ return mpImplData->maMaxOutSize;
+}
+// -----------------------------------------------------------------------
+
+Size SystemWindow::GetResizeOutputSizePixel() const
+{
+ Size aSize = GetOutputSizePixel();
+ if ( aSize.Width() < maMinOutSize.Width() )
+ aSize.Width() = maMinOutSize.Width();
+ if ( aSize.Height() < maMinOutSize.Height() )
+ aSize.Height() = maMinOutSize.Height();
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplWindowStateFromStr( WindowStateData& rData, const ByteString& rStr )
+{
+ ULONG nValidMask = 0;
+ xub_StrLen nIndex = 0;
+ ByteString aTokenStr;
+
+ aTokenStr = rStr.GetToken( 0, ',', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetX( aTokenStr.ToInt32() );
+ if( rData.GetX() > -16384 && rData.GetX() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_X;
+ else
+ rData.SetX( 0 );
+ }
+ else
+ rData.SetX( 0 );
+ aTokenStr = rStr.GetToken( 0, ',', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetY( aTokenStr.ToInt32() );
+ if( rData.GetY() > -16384 && rData.GetY() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_Y;
+ else
+ rData.SetY( 0 );
+ }
+ else
+ rData.SetY( 0 );
+ aTokenStr = rStr.GetToken( 0, ',', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetWidth( aTokenStr.ToInt32() );
+ if( rData.GetWidth() > 0 && rData.GetWidth() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_WIDTH;
+ else
+ rData.SetWidth( 0 );
+ }
+ else
+ rData.SetWidth( 0 );
+ aTokenStr = rStr.GetToken( 0, ';', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetHeight( aTokenStr.ToInt32() );
+ if( rData.GetHeight() > 0 && rData.GetHeight() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_HEIGHT;
+ else
+ rData.SetHeight( 0 );
+ }
+ else
+ rData.SetHeight( 0 );
+ aTokenStr = rStr.GetToken( 0, ';', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ // #94144# allow Minimize again, should be masked out when read from configuration
+ // 91625 - ignore Minimize
+ ULONG nState = (ULONG)aTokenStr.ToInt32();
+ //nState &= ~(WINDOWSTATE_STATE_MINIMIZED);
+ rData.SetState( nState );
+ nValidMask |= WINDOWSTATE_MASK_STATE;
+ }
+ else
+ rData.SetState( 0 );
+
+ // read maximized pos/size
+ aTokenStr = rStr.GetToken( 0, ',', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetMaximizedX( aTokenStr.ToInt32() );
+ if( rData.GetMaximizedX() > -16384 && rData.GetMaximizedX() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_X;
+ else
+ rData.SetMaximizedX( 0 );
+ }
+ else
+ rData.SetMaximizedX( 0 );
+ aTokenStr = rStr.GetToken( 0, ',', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetMaximizedY( aTokenStr.ToInt32() );
+ if( rData.GetMaximizedY() > -16384 && rData.GetMaximizedY() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_Y;
+ else
+ rData.SetMaximizedY( 0 );
+ }
+ else
+ rData.SetMaximizedY( 0 );
+ aTokenStr = rStr.GetToken( 0, ',', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetMaximizedWidth( aTokenStr.ToInt32() );
+ if( rData.GetMaximizedWidth() > 0 && rData.GetMaximizedWidth() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_WIDTH;
+ else
+ rData.SetMaximizedWidth( 0 );
+ }
+ else
+ rData.SetMaximizedWidth( 0 );
+ aTokenStr = rStr.GetToken( 0, ';', nIndex );
+ if ( aTokenStr.Len() )
+ {
+ rData.SetMaximizedHeight( aTokenStr.ToInt32() );
+ if( rData.GetMaximizedHeight() > 0 && rData.GetMaximizedHeight() < 16384 )
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_HEIGHT;
+ else
+ rData.SetMaximizedHeight( 0 );
+ }
+ else
+ rData.SetMaximizedHeight( 0 );
+
+ // mark valid fields
+ rData.SetMask( nValidMask );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplWindowStateToStr( const WindowStateData& rData, ByteString& rStr )
+{
+ ULONG nValidMask = rData.GetMask();
+ if ( !nValidMask )
+ return;
+
+ if ( nValidMask & WINDOWSTATE_MASK_X )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetX() ) );
+ rStr.Append( ',' );
+ if ( nValidMask & WINDOWSTATE_MASK_Y )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetY() ) );
+ rStr.Append( ',' );
+ if ( nValidMask & WINDOWSTATE_MASK_WIDTH )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetWidth() ) );
+ rStr.Append( ',' );
+ if ( nValidMask & WINDOWSTATE_MASK_HEIGHT )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetHeight() ) );
+ rStr.Append( ';' );
+ if ( nValidMask & WINDOWSTATE_MASK_STATE )
+ {
+ // #94144# allow Minimize again, should be masked out when read from configuration
+ // 91625 - ignore Minimize
+ ULONG nState = rData.GetState();
+ //nState &= ~(WINDOWSTATE_STATE_MINIMIZED);
+ rStr.Append( ByteString::CreateFromInt32( (long)nState ) );
+ }
+ rStr.Append( ';' );
+ if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_X )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedX() ) );
+ rStr.Append( ',' );
+ if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_Y )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedY() ) );
+ rStr.Append( ',' );
+ if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_WIDTH )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedWidth() ) );
+ rStr.Append( ',' );
+ if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_HEIGHT )
+ rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedHeight() ) );
+ rStr.Append( ';' );
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::ImplMoveToScreen( long& io_rX, long& io_rY, long i_nWidth, long i_nHeight, Window* i_pConfigureWin )
+{
+ Rectangle aScreenRect;
+ if( Application::IsMultiDisplay() )
+ {
+ aScreenRect = Application::GetScreenPosSizePixel( GetScreenNumber() );
+ }
+ else
+ {
+ aScreenRect = Application::GetScreenPosSizePixel( 0 );
+ for( unsigned int i = 1; i < Application::GetScreenCount(); i++ )
+ aScreenRect.Union( Application::GetScreenPosSizePixel( i ) );
+ }
+ // unfortunately most of the time width and height are not really known
+ if( i_nWidth < 1 )
+ i_nWidth = 50;
+ if( i_nHeight < 1 )
+ i_nHeight = 50;
+
+ // check left border
+ bool bMove = false;
+ if( io_rX + i_nWidth < aScreenRect.Left() )
+ {
+ bMove = true;
+ io_rX = aScreenRect.Left();
+ }
+ // check right border
+ if( io_rX > aScreenRect.Right() - i_nWidth )
+ {
+ bMove = true;
+ io_rX = aScreenRect.Right() - i_nWidth;
+ }
+ // check top border
+ if( io_rY + i_nHeight < aScreenRect.Top() )
+ {
+ bMove = true;
+ io_rY = aScreenRect.Top();
+ }
+ // check bottom border
+ if( io_rY > aScreenRect.Bottom() - i_nHeight )
+ {
+ bMove = true;
+ io_rY = aScreenRect.Bottom() - i_nHeight;
+ }
+ Window* pParent = i_pConfigureWin->GetParent();
+ if( bMove && pParent )
+ {
+ // calculate absolute screen pos here, since that is what is contained in WindowState
+ Point aParentAbsPos( pParent->OutputToAbsoluteScreenPixel( Point(0,0) ) );
+ Size aParentSizePixel( pParent->GetOutputSizePixel() );
+ Point aPos( (aParentSizePixel.Width() - i_nWidth) / 2,
+ (aParentSizePixel.Height() - i_nHeight) / 2 );
+ io_rX = aParentAbsPos.X() + aPos.X();
+ io_rY = aParentAbsPos.Y() + aPos.Y();
+ }
+}
+
+void SystemWindow::SetWindowStateData( const WindowStateData& rData )
+{
+ ULONG nValidMask = rData.GetMask();
+ if ( !nValidMask )
+ return;
+
+ if ( mbSysChild )
+ return;
+
+ Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+
+ if ( pWindow->mpWindowImpl->mbFrame )
+ {
+ ULONG nState = rData.GetState();
+ SalFrameState aState;
+ aState.mnMask = rData.GetMask();
+ aState.mnX = rData.GetX();
+ aState.mnY = rData.GetY();
+ aState.mnWidth = rData.GetWidth();
+ aState.mnHeight = rData.GetHeight();
+
+ if( rData.GetMask() & (WINDOWSTATE_MASK_WIDTH|WINDOWSTATE_MASK_HEIGHT) )
+ {
+ // #i43799# adjust window state sizes if a minimial output size was set
+ // otherwise the frame and the client might get different sizes
+ if( maMinOutSize.Width() > aState.mnWidth )
+ aState.mnWidth = maMinOutSize.Width();
+ if( maMinOutSize.Height() > aState.mnHeight )
+ aState.mnHeight = maMinOutSize.Height();
+ }
+
+ aState.mnMaximizedX = rData.GetMaximizedX();
+ aState.mnMaximizedY = rData.GetMaximizedY();
+ aState.mnMaximizedWidth = rData.GetMaximizedWidth();
+ aState.mnMaximizedHeight = rData.GetMaximizedHeight();
+ // #94144# allow Minimize again, should be masked out when read from configuration
+ // 91625 - ignore Minimize
+ //nState &= ~(WINDOWSTATE_STATE_MINIMIZED);
+ aState.mnState = nState & SAL_FRAMESTATE_SYSTEMMASK;
+
+ // normalize window positions onto screen
+ ImplMoveToScreen( aState.mnX, aState.mnY, aState.mnWidth, aState.mnHeight, pWindow );
+ ImplMoveToScreen( aState.mnMaximizedX, aState.mnMaximizedY, aState.mnMaximizedWidth, aState.mnMaximizedHeight, pWindow );
+
+ // #96568# avoid having multiple frames at the same screen location
+ // do the check only if not maximized
+ if( !((rData.GetMask() & WINDOWSTATE_MASK_STATE) && (nState & WINDOWSTATE_STATE_MAXIMIZED)) )
+ if( rData.GetMask() & (WINDOWSTATE_MASK_POS|WINDOWSTATE_MASK_WIDTH|WINDOWSTATE_MASK_HEIGHT) )
+ {
+ Rectangle aDesktop = GetDesktopRectPixel();
+ ImplSVData *pSVData = ImplGetSVData();
+ Window *pWin = pSVData->maWinData.mpFirstFrame;
+ BOOL bWrapped = FALSE;
+ while( pWin )
+ {
+ if( !pWin->ImplIsRealParentPath( this ) &&
+ pWin->ImplGetWindow()->IsTopWindow() && pWin->mpWindowImpl->mbReallyVisible )
+ {
+ SalFrameGeometry g = pWin->mpWindowImpl->mpFrame->GetGeometry();
+ if( abs(g.nX-aState.mnX) < 2 && abs(g.nY-aState.mnY) < 5 )
+ {
+ long displacement = g.nTopDecoration ? g.nTopDecoration : 20;
+ if( (unsigned long) (aState.mnX + displacement + aState.mnWidth + g.nRightDecoration) > (unsigned long) aDesktop.nRight ||
+ (unsigned long) (aState.mnY + displacement + aState.mnHeight + g.nBottomDecoration) > (unsigned long) aDesktop.nBottom )
+ {
+ // displacing would leave screen
+ aState.mnX = g.nLeftDecoration ? g.nLeftDecoration : 10; // should result in (0,0)
+ aState.mnY = displacement;
+ if( bWrapped ||
+ (unsigned long) (aState.mnX + displacement + aState.mnWidth + g.nRightDecoration) > (unsigned long) aDesktop.nRight ||
+ (unsigned long) (aState.mnY + displacement + aState.mnHeight + g.nBottomDecoration) > (unsigned long) aDesktop.nBottom )
+ break; // further displacement not possible -> break
+ // avoid endless testing
+ bWrapped = TRUE;
+ }
+ else
+ {
+ // displace
+ aState.mnX += displacement;
+ aState.mnY += displacement;
+ }
+ pWin = pSVData->maWinData.mpFirstFrame; // check new pos again
+ }
+ }
+ pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ }
+
+ mpWindowImpl->mpFrame->SetWindowState( &aState );
+
+ // do a synchronous resize for layout reasons
+ // but use rData only when the window is not to be maximized (#i38089#)
+ // otherwise we have no useful size information
+ if( (rData.GetMask() & WINDOWSTATE_MASK_STATE) && (nState & WINDOWSTATE_STATE_MAXIMIZED) )
+ {
+ // query maximized size from frame
+ SalFrameGeometry aGeometry = mpWindowImpl->mpFrame->GetGeometry();
+
+ // but use it only if it is different from the restore size (rData)
+ // as currently only on windows the exact size of a maximized window
+ // can be computed without actually showing the window
+ if( aGeometry.nWidth != rData.GetWidth() || aGeometry.nHeight != rData.GetHeight() )
+ ImplHandleResize( pWindow, aGeometry.nWidth, aGeometry.nHeight );
+ }
+ else
+ if( rData.GetMask() & (WINDOWSTATE_MASK_WIDTH|WINDOWSTATE_MASK_HEIGHT) )
+ ImplHandleResize( pWindow, aState.mnWidth, aState.mnHeight ); // #i43799# use aState and not rData, see above
+ }
+ else
+ {
+ USHORT nPosSize = 0;
+ if ( nValidMask & WINDOWSTATE_MASK_X )
+ nPosSize |= WINDOW_POSSIZE_X;
+ if ( nValidMask & WINDOWSTATE_MASK_Y )
+ nPosSize |= WINDOW_POSSIZE_Y;
+ if ( nValidMask & WINDOWSTATE_MASK_WIDTH )
+ nPosSize |= WINDOW_POSSIZE_WIDTH;
+ if ( nValidMask & WINDOWSTATE_MASK_HEIGHT )
+ nPosSize |= WINDOW_POSSIZE_HEIGHT;
+
+ if( IsRollUp() )
+ RollDown();
+
+ long nX = rData.GetX();
+ long nY = rData.GetY();
+ long nWidth = rData.GetWidth();
+ long nHeight = rData.GetHeight();
+ const SalFrameGeometry& rGeom = pWindow->mpWindowImpl->mpFrame->GetGeometry();
+ if( nX < 0 )
+ nX = 0;
+ if( nX + nWidth > (long) rGeom.nWidth )
+ nX = rGeom.nWidth - nWidth;
+ if( nY < 0 )
+ nY = 0;
+ if( nY + nHeight > (long) rGeom.nHeight )
+ nY = rGeom.nHeight - nHeight;
+ SetPosSizePixel( nX, nY, nWidth, nHeight, nPosSize );
+ maOrgSize = Size( nWidth, nHeight );
+
+ // 91625 - ignore Minimize
+ if ( nValidMask & WINDOWSTATE_MASK_STATE )
+ {
+ ULONG nState = rData.GetState();
+ if ( nState & WINDOWSTATE_STATE_ROLLUP )
+ RollUp();
+ else
+ RollDown();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::GetWindowStateData( WindowStateData& rData ) const
+{
+ ULONG nValidMask = rData.GetMask();
+ if ( !nValidMask )
+ return;
+
+ if ( mbSysChild )
+ return;
+
+ const Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+
+ if ( pWindow->mpWindowImpl->mbFrame )
+ {
+ SalFrameState aState;
+ aState.mnMask = 0xFFFFFFFF;
+ if ( mpWindowImpl->mpFrame->GetWindowState( &aState ) )
+ {
+ if ( nValidMask & WINDOWSTATE_MASK_X )
+ rData.SetX( aState.mnX );
+ if ( nValidMask & WINDOWSTATE_MASK_Y )
+ rData.SetY( aState.mnY );
+ if ( nValidMask & WINDOWSTATE_MASK_WIDTH )
+ rData.SetWidth( aState.mnWidth );
+ if ( nValidMask & WINDOWSTATE_MASK_HEIGHT )
+ rData.SetHeight( aState.mnHeight );
+ if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_X )
+ {
+ rData.SetMaximizedX( aState.mnMaximizedX );
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_X;
+ }
+ if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_Y )
+ {
+ rData.SetMaximizedY( aState.mnMaximizedY );
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_Y;
+ }
+ if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH )
+ {
+ rData.SetMaximizedWidth( aState.mnMaximizedWidth );
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_WIDTH;
+ }
+ if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT )
+ {
+ rData.SetMaximizedHeight( aState.mnMaximizedHeight );
+ nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_HEIGHT;
+ }
+ if ( nValidMask & WINDOWSTATE_MASK_STATE )
+ {
+ // #94144# allow Minimize again, should be masked out when read from configuration
+ // 91625 - ignore Minimize
+ if ( !(nValidMask&WINDOWSTATE_MASK_MINIMIZED) )
+ aState.mnState &= ~(WINDOWSTATE_STATE_MINIMIZED);
+ rData.SetState( aState.mnState );
+ }
+ rData.SetMask( nValidMask );
+ }
+ else
+ rData.SetMask( 0 );
+ }
+ else
+ {
+ Point aPos = GetPosPixel();
+ Size aSize = GetSizePixel();
+ ULONG nState = 0;
+
+ if ( IsRollUp() )
+ {
+ aSize.Height() += maOrgSize.Height();
+ nState |= WINDOWSTATE_STATE_ROLLUP;
+ }
+
+ if ( nValidMask & WINDOWSTATE_MASK_X )
+ rData.SetX( aPos.X() );
+ if ( nValidMask & WINDOWSTATE_MASK_Y )
+ rData.SetY( aPos.Y() );
+ if ( nValidMask & WINDOWSTATE_MASK_WIDTH )
+ rData.SetWidth( aSize.Width() );
+ if ( nValidMask & WINDOWSTATE_MASK_HEIGHT )
+ rData.SetHeight( aSize.Height() );
+ if ( nValidMask & WINDOWSTATE_MASK_STATE )
+ rData.SetState( nState );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetWindowState( const ByteString& rStr )
+{
+ if ( !rStr.Len() )
+ return;
+
+ WindowStateData aData;
+ ImplWindowStateFromStr( aData, rStr );
+ SetWindowStateData( aData );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString SystemWindow::GetWindowState( ULONG nMask ) const
+{
+ WindowStateData aData;
+ aData.SetMask( nMask );
+ GetWindowStateData( aData );
+
+ ByteString aStr;
+ ImplWindowStateToStr( aData, aStr );
+ return aStr;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetMenuBar( MenuBar* pMenuBar )
+{
+ if ( mpMenuBar != pMenuBar )
+ {
+ MenuBar* pOldMenuBar = mpMenuBar;
+ Window* pOldWindow = NULL;
+ Window* pNewWindow=NULL;
+ mpMenuBar = pMenuBar;
+
+ if ( mpWindowImpl->mpBorderWindow && (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) )
+ {
+ if ( pOldMenuBar )
+ pOldWindow = pOldMenuBar->ImplGetWindow();
+ else
+ pOldWindow = NULL;
+ if ( pOldWindow )
+ {
+ ImplCallEventListeners( VCLEVENT_WINDOW_MENUBARREMOVED, (void*) pOldMenuBar );
+ pOldWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() );
+ }
+ if ( pMenuBar )
+ {
+ DBG_ASSERT( !pMenuBar->pWindow, "SystemWindow::SetMenuBar() - MenuBars can only set in one SystemWindow at time" );
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarWindow( pNewWindow = MenuBar::ImplCreate( mpWindowImpl->mpBorderWindow, pOldWindow, pMenuBar ) );
+ ImplCallEventListeners( VCLEVENT_WINDOW_MENUBARADDED, (void*) pMenuBar );
+ }
+ else
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarWindow( NULL );
+ ImplToBottomChild();
+ if ( pOldMenuBar )
+ {
+ BOOL bDelete = (pMenuBar == 0) ? TRUE : FALSE;
+ if( bDelete && pOldWindow )
+ {
+ if( mpImplData->mpTaskPaneList )
+ mpImplData->mpTaskPaneList->RemoveWindow( pOldWindow );
+ }
+ MenuBar::ImplDestroy( pOldMenuBar, bDelete );
+ if( bDelete )
+ pOldWindow = NULL; // will be deleted in MenuBar::ImplDestroy,
+ }
+
+ }
+ else
+ {
+ if( pMenuBar )
+ pNewWindow = pMenuBar->ImplGetWindow();
+ if( pOldMenuBar )
+ pOldWindow = pOldMenuBar->ImplGetWindow();
+ }
+
+ // update taskpane list to make menubar accessible
+ if( mpImplData->mpTaskPaneList )
+ {
+ if( pOldWindow )
+ mpImplData->mpTaskPaneList->RemoveWindow( pOldWindow );
+ if( pNewWindow )
+ mpImplData->mpTaskPaneList->AddWindow( pNewWindow );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetMenuBarMode( USHORT nMode )
+{
+ if ( mnMenuBarMode != nMode )
+ {
+ mnMenuBarMode = nMode;
+ if ( mpWindowImpl->mpBorderWindow && (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) )
+ {
+ if ( nMode == MENUBAR_MODE_HIDE )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarMode( TRUE );
+ else
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarMode( FALSE );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SystemWindow::ImplIsInTaskPaneList( Window* pWin )
+{
+ if( mpImplData && mpImplData->mpTaskPaneList )
+ return mpImplData->mpTaskPaneList->IsInList( pWin );
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+unsigned int SystemWindow::GetScreenNumber() const
+{
+ return mpWindowImpl->mpFrame->maGeometry.nScreenNumber;
+}
+
+// -----------------------------------------------------------------------
+
+void SystemWindow::SetScreenNumber( unsigned int nScreen)
+{
+ mpWindowImpl->mpFrame->SetScreenNumber( nScreen );
+}
diff --git a/vcl/source/window/tabdlg.cxx b/vcl/source/window/tabdlg.cxx
new file mode 100644
index 000000000000..874881c0c5ef
--- /dev/null
+++ b/vcl/source/window/tabdlg.cxx
@@ -0,0 +1,276 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/fixed.hxx>
+#include <vcl/tabctrl.hxx>
+#include <vcl/tabdlg.hxx>
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+
+
+
+// =======================================================================
+
+void TabDialog::ImplInitTabDialogData()
+{
+ mpFixedLine = NULL;
+ mpViewWindow = NULL;
+ meViewAlign = WINDOWALIGN_LEFT;
+ mbPosControls = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void TabDialog::ImplPosControls()
+{
+ Size aCtrlSize( IMPL_MINSIZE_BUTTON_WIDTH, IMPL_MINSIZE_BUTTON_HEIGHT );
+ long nDownCtrl = 0;
+ long nOffY = 0;
+ TabControl* pTabControl = NULL;
+
+ Window* pChild = GetWindow( WINDOW_FIRSTCHILD );
+ while ( pChild )
+ {
+ if ( pChild->IsVisible() && (pChild != mpViewWindow) )
+ {
+ if ( pChild->GetType() == WINDOW_TABCONTROL )
+ pTabControl = (TabControl*)pChild;
+ else if ( pTabControl )
+ {
+ long nTxtWidth = pChild->GetCtrlTextWidth( pChild->GetText() );
+ nTxtWidth += IMPL_EXTRA_BUTTON_WIDTH;
+ if ( nTxtWidth > aCtrlSize.Width() )
+ aCtrlSize.Width() = nTxtWidth;
+ long nTxtHeight = pChild->GetTextHeight();
+ nTxtHeight += IMPL_EXTRA_BUTTON_HEIGHT;
+ if ( nTxtHeight > aCtrlSize.Height() )
+ aCtrlSize.Height() = nTxtHeight;
+ nDownCtrl++;
+ }
+ else
+ {
+ long nHeight = pChild->GetSizePixel().Height();
+ if ( nHeight > nOffY )
+ nOffY = nHeight;
+ }
+ }
+
+ pChild = pChild->GetWindow( WINDOW_NEXT );
+ }
+
+ // Haben wir ueberhaupt ein TabControl
+ if ( pTabControl )
+ {
+ // Offset bei weiteren Controls um einen weiteren Abstand anpassen
+ if ( nOffY )
+ nOffY += IMPL_DIALOG_BAR_OFFSET*2 + 2;
+
+ Point aTabOffset( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+nOffY );
+ Size aTabSize = pTabControl->GetSizePixel();
+ Size aDlgSize( aTabSize.Width() + IMPL_DIALOG_OFFSET*2,
+ aTabSize.Height() + IMPL_DIALOG_OFFSET*2 + nOffY );
+ long nBtnEx = 0;
+
+ // Preview-Fenster beruecksichtigen und die Groessen/Offsets anpassen
+ if ( mpViewWindow && mpViewWindow->IsVisible() )
+ {
+ long nViewOffX = 0;
+ long nViewOffY = 0;
+ long nViewWidth = 0;
+ long nViewHeight = 0;
+ USHORT nViewPosFlags = WINDOW_POSSIZE_POS;
+ Size aViewSize = mpViewWindow->GetSizePixel();
+ if ( meViewAlign == WINDOWALIGN_TOP )
+ {
+ nViewOffX = aTabOffset.X();
+ nViewOffY = nOffY+IMPL_DIALOG_OFFSET;
+ nViewWidth = aTabSize.Width();
+ nViewPosFlags |= WINDOW_POSSIZE_WIDTH;
+ aTabOffset.Y() += aViewSize.Height()+IMPL_DIALOG_OFFSET;
+ aDlgSize.Height() += aViewSize.Height()+IMPL_DIALOG_OFFSET;
+ }
+ else if ( meViewAlign == WINDOWALIGN_BOTTOM )
+ {
+ nViewOffX = aTabOffset.X();
+ nViewOffY = aTabOffset.Y()+aTabSize.Height()+IMPL_DIALOG_OFFSET;
+ nViewWidth = aTabSize.Width();
+ nViewPosFlags |= WINDOW_POSSIZE_WIDTH;
+ aDlgSize.Height() += aViewSize.Height()+IMPL_DIALOG_OFFSET;
+ }
+ else if ( meViewAlign == WINDOWALIGN_RIGHT )
+ {
+ nViewOffX = aTabOffset.X()+aTabSize.Width()+IMPL_DIALOG_OFFSET;
+ nViewOffY = aTabOffset.Y();
+ nViewHeight = aTabSize.Height();
+ nViewPosFlags |= WINDOW_POSSIZE_HEIGHT;
+ aDlgSize.Width() += aViewSize.Width()+IMPL_DIALOG_OFFSET;
+ nBtnEx = aViewSize.Width()+IMPL_DIALOG_OFFSET;
+ }
+ else // meViewAlign == WINDOWALIGN_LEFT
+ {
+ nViewOffX = IMPL_DIALOG_OFFSET;
+ nViewOffY = aTabOffset.Y();
+ nViewHeight = aTabSize.Height();
+ nViewPosFlags |= WINDOW_POSSIZE_HEIGHT;
+ aTabOffset.X() += aViewSize.Width()+IMPL_DIALOG_OFFSET;
+ aDlgSize.Width() += aViewSize.Width()+IMPL_DIALOG_OFFSET;
+ nBtnEx = aViewSize.Width()+IMPL_DIALOG_OFFSET;
+ }
+
+ mpViewWindow->SetPosSizePixel( nViewOffX, nViewOffY,
+ nViewWidth, nViewHeight,
+ nViewPosFlags );
+ }
+
+ // Positionierung vornehmen
+ pTabControl->SetPosPixel( aTabOffset );
+
+ // Alle anderen Childs positionieren
+ BOOL bTabCtrl = FALSE;
+ int nLines = 0;
+ long nX;
+ long nY = aDlgSize.Height();
+ long nTopX = IMPL_DIALOG_OFFSET;
+
+ // Unter Windows 95 werden die Buttons rechtsbuendig angeordnet
+ nX = IMPL_DIALOG_OFFSET;
+ long nCtrlBarWidth = ((aCtrlSize.Width()+IMPL_DIALOG_OFFSET)*nDownCtrl)-IMPL_DIALOG_OFFSET;
+ if ( nCtrlBarWidth <= (aTabSize.Width()+nBtnEx) )
+ nX = (aTabSize.Width()+nBtnEx) - nCtrlBarWidth + IMPL_DIALOG_OFFSET;
+
+ Window* pChild2 = GetWindow( WINDOW_FIRSTCHILD );
+ while ( pChild2 )
+ {
+ if ( pChild2->IsVisible() && (pChild2 != mpViewWindow) )
+ {
+ if ( pChild2 == pTabControl )
+ bTabCtrl = TRUE;
+ else if ( bTabCtrl )
+ {
+ if ( !nLines )
+ nLines = 1;
+
+ if ( nX+aCtrlSize.Width()-IMPL_DIALOG_OFFSET > (aTabSize.Width()+nBtnEx) )
+ {
+ nY += aCtrlSize.Height()+IMPL_DIALOG_OFFSET;
+ nX = IMPL_DIALOG_OFFSET;
+ nLines++;
+ }
+
+ pChild2->SetPosSizePixel( Point( nX, nY ), aCtrlSize );
+ nX += aCtrlSize.Width()+IMPL_DIALOG_OFFSET;
+ }
+ else
+ {
+ Size aChildSize = pChild2->GetSizePixel();
+ pChild2->SetPosPixel( Point( nTopX, (nOffY-aChildSize.Height())/2 ) );
+ nTopX += aChildSize.Width()+2;
+ }
+ }
+
+ pChild2 = pChild2->GetWindow( WINDOW_NEXT );
+ }
+
+ aDlgSize.Height() += nLines * (aCtrlSize.Height()+IMPL_DIALOG_OFFSET);
+ SetOutputSizePixel( aDlgSize );
+ }
+
+ // Offset merken
+ if ( nOffY )
+ {
+ Size aDlgSize = GetOutputSizePixel();
+ if ( !mpFixedLine )
+ mpFixedLine = new FixedLine( this );
+ mpFixedLine->SetPosSizePixel( Point( 0, nOffY ),
+ Size( aDlgSize.Width(), 2 ) );
+ mpFixedLine->Show();
+ }
+
+ mbPosControls = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+TabDialog::TabDialog( Window* pParent, WinBits nStyle ) :
+ Dialog( WINDOW_TABDIALOG )
+{
+ ImplInitTabDialogData();
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+TabDialog::TabDialog( Window* pParent, const ResId& rResId ) :
+ Dialog( WINDOW_TABDIALOG )
+{
+ ImplInitTabDialogData();
+ rResId.SetRT( RSC_TABDIALOG );
+ ImplInit( pParent, ImplInitRes( rResId ) );
+ ImplLoadRes( rResId );
+}
+
+// -----------------------------------------------------------------------
+
+TabDialog::~TabDialog()
+{
+ if ( mpFixedLine )
+ delete mpFixedLine;
+}
+
+// -----------------------------------------------------------------------
+
+void TabDialog::Resize()
+{
+// !!! In the future the controls should be automaticly rearrange
+// !!! if the window is resized
+// !!! if ( !IsRollUp() )
+// !!! ImplPosControls();
+}
+
+// -----------------------------------------------------------------------
+
+void TabDialog::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ // Calculate the Layout only for the initialized state
+ if ( mbPosControls )
+ ImplPosControls();
+ }
+ Dialog::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void TabDialog::AdjustLayout()
+{
+ ImplPosControls();
+}
+
diff --git a/vcl/source/window/tabpage.cxx b/vcl/source/window/tabpage.cxx
new file mode 100644
index 000000000000..0589d57009f4
--- /dev/null
+++ b/vcl/source/window/tabpage.cxx
@@ -0,0 +1,216 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/ref.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+#include <vcl/tabpage.hxx>
+#include <vcl/tabctrl.hxx>
+#include <vcl/bitmapex.hxx>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+
+
+
+// =======================================================================
+
+void TabPage::ImplInit( Window* pParent, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NODIALOGCONTROL) )
+ nStyle |= WB_DIALOGCONTROL;
+
+ Window::ImplInit( pParent, nStyle, NULL );
+
+ ImplInitSettings();
+
+ // if the tabpage is drawn (ie filled) by a native widget, make sure all contols will have transparent background
+ // otherwise they will paint with a wrong background
+ if( IsNativeControlSupported(CTRL_TAB_BODY, PART_ENTIRE_CONTROL) && GetParent() && (GetParent()->GetType() == WINDOW_TABCONTROL) )
+ EnableChildTransparentMode( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void TabPage::ImplInitSettings()
+{
+ Window* pParent = GetParent();
+ if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() )
+ {
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TabPage::TabPage( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_TABPAGE )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+TabPage::TabPage( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_TABPAGE )
+{
+ rResId.SetRT( RSC_TABPAGE );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void TabPage::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ if ( GetSettings().GetStyleSettings().GetAutoMnemonic() )
+ ImplWindowAutoMnemonic( this );
+ // FIXME: no layouting, workaround some clipping issues
+ ImplAdjustNWFSizes();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabPage::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabPage::Paint( const Rectangle& )
+{
+ // draw native tabpage only inside tabcontrols, standalone tabpages look ugly (due to bad dialog design)
+ if( IsNativeControlSupported(CTRL_TAB_BODY, PART_ENTIRE_CONTROL) && GetParent() && (GetParent()->GetType() == WINDOW_TABCONTROL) )
+ {
+ const ImplControlValue aControlValue;
+
+ ControlState nState = CTRL_STATE_ENABLED;
+ int part = PART_ENTIRE_CONTROL;
+ if ( !IsEnabled() )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ Point aPoint;
+ // pass the whole window region to NWF as the tab body might be a gradient or bitmap
+ // that has to be scaled properly, clipping makes sure that we do not paint too much
+ Rectangle aCtrlRegion( aPoint, GetOutputSizePixel() );
+ DrawNativeControl( CTRL_TAB_BODY, part, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() );
+ }
+}
+
+// -----------------------------------------------------------------------
+void TabPage::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG )
+{
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+
+ Wallpaper aWallpaper = GetBackground();
+ if ( !aWallpaper.IsBitmap() )
+ ImplInitSettings();
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetLineColor();
+
+ if ( aWallpaper.IsBitmap() )
+ pDev->DrawBitmapEx( aPos, aSize, aWallpaper.GetBitmap() );
+ else
+ {
+ if( aWallpaper.GetColor() == COL_AUTO )
+ pDev->SetFillColor( GetSettings().GetStyleSettings().GetDialogColor() );
+ else
+ pDev->SetFillColor( aWallpaper.GetColor() );
+ pDev->DrawRect( Rectangle( aPos, aSize ) );
+ }
+
+ pDev->Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void TabPage::ActivatePage()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void TabPage::DeactivatePage()
+{
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > TabPage::CreateAccessible()
+{
+ // TODO: remove this method (incompatible)
+
+ return Window::CreateAccessible();
+}
diff --git a/vcl/source/window/taskpanelist.cxx b/vcl/source/window/taskpanelist.cxx
new file mode 100644
index 000000000000..c09dc464b809
--- /dev/null
+++ b/vcl/source/window/taskpanelist.cxx
@@ -0,0 +1,398 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <vcl/svdata.hxx>
+#include <tools/rcid.h>
+#include <vcl/dockwin.hxx>
+
+#include <vcl/taskpanelist.hxx>
+#include <functional>
+#include <algorithm>
+
+// can't have static linkage because SUNPRO 5.2 complains
+Point ImplTaskPaneListGetPos( const Window *w )
+{
+ Point pos;
+ if( w->ImplIsDockingWindow() )
+ {
+ pos = ((DockingWindow*)w)->GetPosPixel();
+ Window *pF = ((DockingWindow*)w)->GetFloatingWindow();
+ if( pF )
+ pos = pF->OutputToAbsoluteScreenPixel( pF->ScreenToOutputPixel( pos ) );
+ else
+ pos = w->OutputToAbsoluteScreenPixel( pos );
+ }
+ else
+ pos = w->OutputToAbsoluteScreenPixel( w->GetPosPixel() );
+
+ return pos;
+}
+
+// compares window pos left-to-right
+struct LTRSort : public ::std::binary_function< const Window*, const Window*, bool >
+{
+ bool operator()( const Window* w1, const Window* w2 ) const
+ {
+ Point pos1(ImplTaskPaneListGetPos( w1 ));
+ Point pos2(ImplTaskPaneListGetPos( w2 ));
+
+ if( pos1.X() == pos2.X() )
+ return ( pos1.Y() < pos2.Y() );
+ else
+ return ( pos1.X() < pos2.X() );
+ }
+};
+struct LTRSortBackward : public ::std::binary_function< const Window*, const Window*, bool >
+{
+ bool operator()( const Window* w2, const Window* w1 ) const
+ {
+ Point pos1(ImplTaskPaneListGetPos( w1 ));
+ Point pos2(ImplTaskPaneListGetPos( w2 ));
+
+ if( pos1.X() == pos2.X() )
+ return ( pos1.Y() < pos2.Y() );
+ else
+ return ( pos1.X() < pos2.X() );
+ }
+};
+
+// --------------------------------------------------
+
+static void ImplTaskPaneListGrabFocus( Window *pWindow )
+{
+ // put focus in child of floating windows which is typically a toolbar
+ // that can deal with the focus
+ if( pWindow->ImplIsFloatingWindow() && pWindow->GetWindow( WINDOW_FIRSTCHILD ) )
+ pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD );
+ pWindow->GrabFocus();
+}
+
+// --------------------------------------------------
+
+TaskPaneList::TaskPaneList()
+{
+}
+
+TaskPaneList::~TaskPaneList()
+{
+}
+
+// --------------------------------------------------
+
+void TaskPaneList::AddWindow( Window *pWindow )
+{
+#if OSL_DEBUG_LEVEL > 0
+ bool bDockingWindow=false;
+ bool bToolbox=false;
+ bool bDialog=false;
+ bool bUnknown=false;
+#endif
+
+ if( pWindow )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ if( pWindow->GetType() == RSC_DOCKINGWINDOW )
+ bDockingWindow = true;
+ else if( pWindow->GetType() == RSC_TOOLBOX )
+ bToolbox = true;
+ else if( pWindow->IsDialog() )
+ bDialog = true;
+ else
+ bUnknown = true;
+#endif
+
+ ::std::vector< Window* >::iterator insertionPos = mTaskPanes.end();
+ for ( ::std::vector< Window* >::iterator p = mTaskPanes.begin();
+ p != mTaskPanes.end();
+ ++p
+ )
+ {
+ if ( *p == pWindow )
+ // avoid duplicates
+ return;
+
+ // If the new window is the child of an existing pane window, or vice versa,
+ // ensure that in our pane list, *first* the child window appears, *then*
+ // the ancestor window.
+ // This is necessary for HandleKeyEvent: There, the list is traveled from the
+ // beginning, until the first window is found which has the ChildPathFocus. Now
+ // if this would be the ancestor window of another pane window, this would fudge
+ // the result
+ // 2004-09-27 - fs@openoffice.org, while fixing #i33573#, which included replacing
+ // the original fix for #98916# with this one here.
+ if ( pWindow->IsWindowOrChild( *p ) )
+ {
+ insertionPos = p + 1;
+ break;
+ }
+ if ( (*p)->IsWindowOrChild( pWindow ) )
+ {
+ insertionPos = p;
+ break;
+ }
+ }
+
+ mTaskPanes.insert( insertionPos, pWindow );
+ pWindow->ImplIsInTaskPaneList( TRUE );
+ }
+}
+
+// --------------------------------------------------
+
+void TaskPaneList::RemoveWindow( Window *pWindow )
+{
+ ::std::vector< Window* >::iterator p;
+ p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
+ if( p != mTaskPanes.end() )
+ {
+ mTaskPanes.erase( p );
+ pWindow->ImplIsInTaskPaneList( FALSE );
+ }
+}
+
+// --------------------------------------------------
+
+BOOL TaskPaneList::IsInList( Window *pWindow )
+{
+ ::std::vector< Window* >::iterator p;
+ p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
+ if( p != mTaskPanes.end() )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// --------------------------------------------------
+
+BOOL TaskPaneList::HandleKeyEvent( KeyEvent aKeyEvent )
+{
+
+ // F6 cycles through everything and works always
+
+ // MAV, #i104204#
+ // The old design was the following one:
+ // < Ctrl-TAB cycles through Menubar, Toolbars and Floatingwindows only and is
+ // < only active if one of those items has the focus
+ //
+ // Since the design of Ctrl-Tab looks to be inconsistent ( non-modal dialogs are not reachable
+ // and the shortcut conflicts with tab-control shortcut ), it is no more supported
+ BOOL bSplitterOnly = FALSE;
+ BOOL bFocusInList = FALSE;
+ KeyCode aKeyCode = aKeyEvent.GetKeyCode();
+ BOOL bForward = !aKeyCode.IsShift();
+ if( aKeyCode.GetCode() == KEY_F6 ) // F6
+ {
+ bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift();
+
+ // is the focus in the list ?
+ ::std::vector< Window* >::iterator p = mTaskPanes.begin();
+ while( p != mTaskPanes.end() )
+ {
+ Window *pWin = *p;
+ if( pWin->HasChildPathFocus( TRUE ) )
+ {
+ bFocusInList = TRUE;
+
+ // Ctrl-F6 goes directly to the document
+ if( !pWin->IsDialog() && aKeyCode.IsMod1() && !aKeyCode.IsShift() )
+ {
+ pWin->GrabFocusToDocument();
+ return TRUE;
+ }
+
+ // activate next task pane
+ Window *pNextWin = NULL;
+
+ if( bSplitterOnly )
+ pNextWin = FindNextSplitter( *p, TRUE );
+ else
+ pNextWin = FindNextFloat( *p, bForward );
+
+ if( pNextWin != pWin )
+ {
+ ImplGetSVData()->maWinData.mbNoSaveFocus = TRUE;
+ ImplTaskPaneListGrabFocus( pNextWin );
+ ImplGetSVData()->maWinData.mbNoSaveFocus = FALSE;
+ }
+ else
+ {
+ // forward key if no splitter found
+ if( bSplitterOnly )
+ return FALSE;
+
+ // we did not find another taskpane, so
+ // put focus back into document
+ pWin->GrabFocusToDocument();
+ }
+
+ return TRUE;
+ }
+ else
+ p++;
+ }
+
+ // the focus is not in the list: activate first float if F6 was pressed
+ if( !bFocusInList )
+ {
+ Window *pWin;
+ if( bSplitterOnly )
+ pWin = FindNextSplitter( NULL, TRUE );
+ else
+ pWin = FindNextFloat( NULL, bForward );
+ if( pWin )
+ {
+ ImplTaskPaneListGrabFocus( pWin );
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+// --------------------------------------------------
+
+// returns next valid pane
+Window* TaskPaneList::FindNextPane( Window *pWindow, BOOL bForward )
+{
+ if( bForward )
+ ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
+ else
+ ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
+
+ ::std::vector< Window* >::iterator p = mTaskPanes.begin();
+ while( p != mTaskPanes.end() )
+ {
+ if( *p == pWindow )
+ {
+ unsigned n = mTaskPanes.size();
+ while( --n )
+ {
+ if( ++p == mTaskPanes.end() )
+ p = mTaskPanes.begin();
+ if( (*p)->IsReallyVisible() && !(*p)->IsDialog() && !(*p)->ImplIsSplitter() )
+ {
+ pWindow = *p;
+ break;
+ }
+ }
+ break;
+ }
+ else
+ ++p;
+ }
+
+ return pWindow;
+}
+
+// --------------------------------------------------
+
+// returns next splitter
+Window* TaskPaneList::FindNextSplitter( Window *pWindow, BOOL bForward )
+{
+ if( bForward )
+ ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
+ else
+ ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
+
+ ::std::vector< Window* >::iterator p = mTaskPanes.begin();
+ while( p != mTaskPanes.end() )
+ {
+ if( !pWindow || *p == pWindow )
+ {
+ unsigned n = mTaskPanes.size();
+ while( --n )
+ {
+ if( pWindow ) // increment before test
+ ++p;
+ if( p == mTaskPanes.end() )
+ p = mTaskPanes.begin();
+ if( (*p)->ImplIsSplitter() && (*p)->IsReallyVisible() && !(*p)->IsDialog() && (*p)->GetParent()->HasChildPathFocus() )
+ {
+ pWindow = *p;
+ break;
+ }
+ if( !pWindow ) // increment after test, otherwise first element is skipped
+ ++p;
+ }
+ break;
+ }
+ else
+ ++p;
+ }
+
+ return pWindow;
+}
+
+// --------------------------------------------------
+
+// returns first valid item (regardless of type) if pWindow==0, otherwise returns next valid float
+Window* TaskPaneList::FindNextFloat( Window *pWindow, BOOL bForward )
+{
+ if( bForward )
+ ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
+ else
+ ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
+
+ ::std::vector< Window* >::iterator p = mTaskPanes.begin();
+ while( p != mTaskPanes.end() )
+ {
+ if( !pWindow || *p == pWindow )
+ {
+ while( p != mTaskPanes.end() )
+ {
+ if( pWindow ) // increment before test
+ ++p;
+ if( p == mTaskPanes.end() )
+ break; // do not wrap, send focus back to document at end of list
+ /* #i83908# do not use the menubar if it is native and invisible
+ this relies on MenuBar::ImplCreate setting the height of the menubar
+ to 0 in this case
+ */
+ if( (*p)->IsReallyVisible() && !(*p)->ImplIsSplitter() &&
+ ( (*p)->GetType() != WINDOW_MENUBARWINDOW || (*p)->GetSizePixel().Height() > 0 )
+ )
+ {
+ pWindow = *p;
+ break;
+ }
+ if( !pWindow ) // increment after test, otherwise first element is skipped
+ ++p;
+ }
+ break;
+ }
+ else
+ ++p;
+ }
+
+ return pWindow;
+}
+
+// --------------------------------------------------
+
diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx
new file mode 100644
index 000000000000..cde91a8dcd97
--- /dev/null
+++ b/vcl/source/window/toolbox.cxx
@@ -0,0 +1,6333 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <rtl/logfile.hxx>
+#include <tools/list.hxx>
+#include <tools/debug.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/event.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/accel.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/help.hxx>
+#include <vcl/sound.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/spin.h>
+#include <vcl/toolbox.hxx>
+#include <vcl/toolbox.h>
+#include <vcl/bitmap.hxx>
+#include <tools/poly.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/window.h>
+
+#include <string.h>
+#include <vector>
+#include <math.h>
+
+// =======================================================================
+
+DBG_NAMEEX( Window )
+
+// =======================================================================
+
+#define SMALLBUTTON_HSIZE 7
+#define SMALLBUTTON_VSIZE 7
+
+#define SMALLBUTTON_OFF_NORMAL_X 3
+#define SMALLBUTTON_OFF_NORMAL_Y 3
+#define SMALLBUTTON_OFF_CHECKED_X 4
+#define SMALLBUTTON_OFF_CHECKED_Y 4
+#define SMALLBUTTON_OFF_PRESSED_X 5
+#define SMALLBUTTON_OFF_PRESSED_Y 5
+
+#define OUTBUTTON_SIZE 6
+#define OUTBUTTON_BORDER 4
+#define OUTBUTTON_OFF_NORMAL_X 1
+#define OUTBUTTON_OFF_NORMAL_Y 1
+
+// -----------------------------------------------------------------------
+
+#define DEF_MIN_WIDTH 8
+#define DEF_MIN_HEIGHT 8
+#define DEF_TEXT_WIDTH 40
+
+#define TB_TEXTOFFSET 2
+#define TB_IMAGETEXTOFFSET 3
+#define TB_LINESPACING 3
+#define TB_SPIN_SIZE 14
+#define TB_SPIN_OFFSET 2
+#define TB_NEXT_SIZE 22
+#define TB_NEXT_OFFSET 2
+#define TB_BORDER_OFFSET1 4
+#define TB_BORDER_OFFSET2 2
+#define TB_CUSTOMIZE_OFFSET 2
+#define TB_RESIZE_OFFSET 3
+#define TB_MAXLINES 5
+#define TB_MAXNOSCROLL 32765
+
+#define TB_MIN_WIN_WIDTH 20
+
+#define TB_CALCMODE_HORZ 1
+#define TB_CALCMODE_VERT 2
+#define TB_CALCMODE_FLOAT 3
+
+#define TB_WBLINESIZING (WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL)
+
+#define TB_MAX_GROUPS 100
+
+#define DOCK_LINEHSIZE ((USHORT)0x0001)
+#define DOCK_LINEVSIZE ((USHORT)0x0002)
+#define DOCK_LINERIGHT ((USHORT)0x1000)
+#define DOCK_LINEBOTTOM ((USHORT)0x2000)
+#define DOCK_LINELEFT ((USHORT)0x4000)
+#define DOCK_LINETOP ((USHORT)0x8000)
+#define DOCK_LINEOFFSET 3
+
+
+// -----------------------------------------------------------------------
+static void ImplDrawButton( ToolBox* pThis, const Rectangle &rRect, USHORT highlight, BOOL bChecked, BOOL bEnabled, BOOL bIsWindow );
+// -----------------------------------------------------------------------
+
+struct ImplToolSize
+{
+ long mnWidth;
+ long mnHeight;
+ USHORT mnLines;
+};
+
+struct ImplToolSizeArray
+{
+ long mnLength;
+ long mnLastEntry;
+ ImplToolSize* mpSize;
+
+ ImplToolSizeArray() { mpSize = NULL; mnLength = 0; mnLastEntry = 0; }
+ ~ImplToolSizeArray() { if( mpSize ) delete [] mpSize; mnLength = 0; }
+};
+
+// -----------------------------------------------------------------------
+
+DECLARE_LIST( ImplTBList, ToolBox* )
+
+class ImplTBDragMgr
+{
+private:
+ ImplTBList* mpBoxList;
+ ToolBox* mpDragBox;
+ Point maMouseOff;
+ Rectangle maRect;
+ Rectangle maStartRect;
+ Accelerator maAccel;
+ long mnMinWidth;
+ long mnMaxWidth;
+ USHORT mnLineMode;
+ USHORT mnStartLines;
+ void* mpCustomizeData;
+ BOOL mbCustomizeMode;
+ BOOL mbResizeMode;
+ BOOL mbShowDragRect;
+
+public:
+ ImplTBDragMgr();
+ ~ImplTBDragMgr();
+
+ void Insert( ToolBox* pBox )
+ { mpBoxList->Insert( pBox ); }
+ void Remove( ToolBox* pBox )
+ { mpBoxList->Remove( pBox ); }
+ ULONG Count() const
+ { return mpBoxList->Count(); }
+
+ ToolBox* FindToolBox( const Rectangle& rRect );
+
+ void StartDragging( ToolBox* pDragBox,
+ const Point& rPos, const Rectangle& rRect,
+ USHORT nLineMode, BOOL bResizeItem,
+ void* pData = NULL );
+ void Dragging( const Point& rPos );
+ void EndDragging( BOOL bOK = TRUE );
+ void HideDragRect() { if ( mbShowDragRect ) mpDragBox->HideTracking(); }
+ void UpdateDragRect();
+ DECL_LINK( SelectHdl, Accelerator* );
+
+ void StartCustomizeMode();
+ void EndCustomizeMode();
+ BOOL IsCustomizeMode() { return mbCustomizeMode; }
+ BOOL IsResizeMode() { return mbResizeMode; }
+};
+
+// -----------------------------------------------------------------------
+
+static ImplTBDragMgr* ImplGetTBDragMgr()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maCtrlData.mpTBDragMgr )
+ pSVData->maCtrlData.mpTBDragMgr = new ImplTBDragMgr;
+ return pSVData->maCtrlData.mpTBDragMgr;
+}
+
+// -----------------------------------------------------------------------
+
+int ToolBox::ImplGetDragWidth( ToolBox* pThis )
+{
+ #define TB_DRAGWIDTH 8 // the default width of the grip
+
+ int width = TB_DRAGWIDTH;
+ if( pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) )
+ {
+
+ ImplControlValue aControlValue;
+ Point aPoint;
+ Rectangle aContent, aBound;
+ Rectangle aArea( aPoint, pThis->GetOutputSizePixel() );
+
+ if ( pThis->GetNativeControlRegion(CTRL_TOOLBAR, pThis->mbHorz ? PART_THUMB_VERT : PART_THUMB_HORZ,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ width = pThis->mbHorz ? aContent.GetWidth() : aContent.GetHeight();
+ }
+ }
+ return width;
+}
+
+ButtonType determineButtonType( ImplToolItem* pItem, ButtonType defaultType )
+{
+ ButtonType tmpButtonType = defaultType;
+ ToolBoxItemBits nBits( pItem->mnBits & 0x300 );
+ if ( nBits & TIB_TEXTICON ) // item has custom setting
+ {
+ tmpButtonType = BUTTON_SYMBOLTEXT;
+ if ( nBits == TIB_TEXT_ONLY )
+ tmpButtonType = BUTTON_TEXT;
+ else if ( nBits == TIB_ICON_ONLY )
+ tmpButtonType = BUTTON_SYMBOL;
+ }
+ return tmpButtonType;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplUpdateDragArea( ToolBox *pThis )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
+ if( pWrapper )
+ {
+ if ( pThis->ImplIsFloatingMode() || pWrapper->IsLocked() )
+ pWrapper->SetDragArea( Rectangle() );
+ else
+ {
+ if( pThis->meAlign == WINDOWALIGN_TOP || pThis->meAlign == WINDOWALIGN_BOTTOM )
+ pWrapper->SetDragArea( Rectangle( 0, 0, ImplGetDragWidth( pThis ), pThis->GetOutputSizePixel().Height() ) );
+ else
+ pWrapper->SetDragArea( Rectangle( 0, 0, pThis->GetOutputSizePixel().Width(), ImplGetDragWidth( pThis ) ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplCalcBorder( WindowAlign eAlign, long& rLeft, long& rTop,
+ long& rRight, long& rBottom, const ToolBox *pThis )
+{
+ if( pThis->ImplIsFloatingMode() || !(pThis->mnWinStyle & WB_BORDER) )
+ {
+ // no border in floating mode
+ rLeft = rTop = rRight = rBottom = 0;
+ return;
+ }
+
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
+
+ // reserve dragarea only for dockable toolbars
+ int dragwidth = ( pWrapper && !pWrapper->IsLocked() ) ? ImplGetDragWidth( (ToolBox*)pThis ) : 0;
+
+ // no shadow border for dockable toolbars
+ int borderwidth = pWrapper ? 0: 2;
+
+ if ( eAlign == WINDOWALIGN_TOP )
+ {
+ rLeft = borderwidth+dragwidth;
+ rTop = borderwidth;
+ rRight = borderwidth;
+ rBottom = 0;
+ }
+ else if ( eAlign == WINDOWALIGN_LEFT )
+ {
+ rLeft = borderwidth;
+ rTop = borderwidth+dragwidth;
+ rRight = 0;
+ rBottom = borderwidth;
+ }
+ else if ( eAlign == WINDOWALIGN_BOTTOM )
+ {
+ rLeft = borderwidth+dragwidth;
+ rTop = 0;
+ rRight = borderwidth;
+ rBottom = borderwidth;
+ }
+ else
+ {
+ rLeft = 0;
+ rTop = borderwidth+dragwidth;
+ rRight = borderwidth;
+ rBottom = borderwidth;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCheckUpdate( ToolBox *pThis )
+{
+ // remove any pending invalidates to avoid
+ // have them triggered when paint is locked (see mpData->mbIsPaintLocked)
+ // which would result in erasing the background only and not painting any items
+ // this must not be done when we're already in Paint()
+
+ // this is only required for transparent toolbars (see ImplDrawTransparentBackground() )
+ if( !pThis->IsBackground() && pThis->HasPaintEvent() && !pThis->IsInPaint() )
+ pThis->Update();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplDrawGrip( ToolBox* pThis )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
+ if( pWrapper && !pWrapper->GetDragArea().IsEmpty() )
+ {
+ // execute pending paint requests
+ ImplCheckUpdate( pThis );
+
+ BOOL bNativeOk = FALSE;
+ if( pThis->IsNativeControlSupported( CTRL_TOOLBAR, pThis->mbHorz ? PART_THUMB_HORZ : PART_THUMB_VERT ) )
+ {
+ ToolbarValue aToolbarValue;
+ aToolbarValue.maGripRect = pWrapper->GetDragArea();
+ Point aPt;
+ Rectangle aCtrlRegion( aPt, pThis->GetOutputSizePixel() );
+ ControlState nState = CTRL_STATE_ENABLED;
+
+ bNativeOk = pThis->DrawNativeControl( CTRL_TOOLBAR, pThis->mbHorz ? PART_THUMB_VERT : PART_THUMB_HORZ,
+ aCtrlRegion, nState, aToolbarValue, rtl::OUString() );
+ }
+
+ if( bNativeOk )
+ return;
+
+ const StyleSettings& rStyleSettings = pThis->GetSettings().GetStyleSettings();
+ pThis->SetLineColor( rStyleSettings.GetShadowColor() );
+
+ Size aSz ( pThis->GetOutputSizePixel() );
+
+ if ( pThis->meAlign == WINDOWALIGN_TOP || pThis->meAlign == WINDOWALIGN_BOTTOM )
+ {
+ int height = (int) (0.6 * aSz.Height() + 0.5);
+ int i = (aSz.Height() - height) / 2;
+ height += i;
+ while( i <= height )
+ {
+ int x = ImplGetDragWidth( pThis ) / 2;
+
+ pThis->DrawPixel( Point(x, i), rStyleSettings.GetDarkShadowColor() );
+ pThis->DrawPixel( Point(x+1, i), rStyleSettings.GetShadowColor() );
+
+ pThis->DrawPixel( Point(x, i+1), rStyleSettings.GetShadowColor() );
+ pThis->DrawPixel( Point(x+1, i+1), rStyleSettings.GetFaceColor() );
+ pThis->DrawPixel( Point(x+2, i+1), Color(COL_WHITE) );
+
+ pThis->DrawPixel( Point(x+1, i+2), Color(COL_WHITE) );
+ pThis->DrawPixel( Point(x+2, i+2), Color(COL_WHITE) );
+ i+=4;
+ }
+ }
+ else
+ {
+ int width = (int) (0.6 * aSz.Width() + 0.5);
+ int i = (aSz.Width() - width) / 2;
+ width += i;
+ while( i <= width )
+ {
+ int y = ImplGetDragWidth(pThis) / 2;
+
+ pThis->DrawPixel( Point(i, y), rStyleSettings.GetDarkShadowColor() );
+ pThis->DrawPixel( Point(i+1, y), rStyleSettings.GetShadowColor() );
+
+ pThis->DrawPixel( Point(i, y+1), rStyleSettings.GetShadowColor() );
+ pThis->DrawPixel( Point(i+1, y+1), rStyleSettings.GetFaceColor() );
+ pThis->DrawPixel( Point(i+2, y+1), Color(COL_WHITE) );
+
+ pThis->DrawPixel( Point(i+1, y+2), Color(COL_WHITE) );
+ pThis->DrawPixel( Point(i+2, y+2), Color(COL_WHITE) );
+ i+=4;
+ }
+ }
+ }
+}
+
+void ToolBox::ImplDrawGradientBackground( ToolBox* pThis, ImplDockingWindowWrapper * )
+{
+ // draw a nice gradient
+
+ Color startCol, endCol;
+ startCol = pThis->GetSettings().GetStyleSettings().GetFaceGradientColor();
+ endCol = pThis->GetSettings().GetStyleSettings().GetFaceColor();
+ if( pThis->GetSettings().GetStyleSettings().GetHighContrastMode() )
+ // no 'extreme' gradient when high contrast
+ startCol = endCol;
+
+ Gradient g;
+ g.SetAngle( pThis->mbHorz ? 0 : 900 );
+ g.SetStyle( GRADIENT_LINEAR );
+
+ g.SetStartColor( startCol );
+ g.SetEndColor( endCol );
+
+ BOOL bLineColor = pThis->IsLineColor();
+ Color aOldCol = pThis->GetLineColor();
+ pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetShadowColor() );
+
+ Size aFullSz( pThis->GetOutputSizePixel() );
+ Size aLineSz( aFullSz );
+
+ // use the linesize only when floating
+ // full window height is used when docked (single line)
+ if( pThis->ImplIsFloatingMode() )
+ {
+ long nLineSize;
+ if( pThis->mbHorz )
+ {
+ nLineSize = pThis->mnMaxItemHeight;
+ if ( pThis->mnWinHeight > pThis->mnMaxItemHeight )
+ nLineSize = pThis->mnWinHeight;
+
+ aLineSz.Height() = nLineSize;
+ }
+ else
+ {
+ nLineSize = pThis->mnMaxItemWidth;
+ aLineSz.Width() = nLineSize;
+ }
+ }
+
+ long nLeft, nTop, nRight, nBottom;
+ ImplCalcBorder( pThis->meAlign, nLeft, nTop, nRight, nBottom, pThis );
+
+ Size aTopLineSz( aLineSz );
+ Size aBottomLineSz( aLineSz );
+
+ if ( pThis->mnWinStyle & WB_BORDER )
+ {
+ if( pThis->mbHorz )
+ {
+ aTopLineSz.Height() += TB_BORDER_OFFSET2 + nTop;
+ aBottomLineSz.Height() += TB_BORDER_OFFSET2 + nBottom;
+
+ if( pThis->mnCurLines == 1 )
+ aTopLineSz.Height() += TB_BORDER_OFFSET2 + nBottom;
+ }
+ else
+ {
+ aTopLineSz.Width() += TB_BORDER_OFFSET1 + nLeft;
+ aBottomLineSz.Width() += TB_BORDER_OFFSET1 + nRight;
+
+ if( pThis->mnCurLines == 1 )
+ aTopLineSz.Width() += TB_BORDER_OFFSET1 + nLeft;
+ }
+ }
+
+ if( pThis->mbHorz )
+ {
+ aTopLineSz.Height() += pThis->mnBorderY;
+ if( pThis->mnCurLines == 1 )
+ aTopLineSz.Height() += pThis->mnBorderY;
+
+ aBottomLineSz.Height() += pThis->mnBorderY;
+ }
+ else
+ {
+ aTopLineSz.Width() += pThis->mnBorderX;
+ if( pThis->mnCurLines == 1 )
+ aTopLineSz.Width() += pThis->mnBorderX;
+
+ aBottomLineSz.Width() += pThis->mnBorderX;
+ }
+
+
+ if ( pThis->mnWinStyle & WB_LINESPACING )
+ {
+ if( pThis->mbHorz )
+ {
+ aLineSz.Height() += TB_LINESPACING;
+ if( pThis->mnCurLines > 1 )
+ aTopLineSz.Height() += TB_LINESPACING;
+ }
+ else
+ {
+ aLineSz.Width() += TB_LINESPACING;
+ if( pThis->mnCurLines > 1 )
+ aTopLineSz.Width() += TB_LINESPACING;
+ }
+ }
+
+ if( pThis->mbHorz )
+ {
+ long y = 0;
+ BOOL bDrawSep = FALSE; // pThis->ImplIsFloatingMode() && ( pThis->mnWinStyle & WB_LINESPACING );
+
+ pThis->DrawGradient( Rectangle( 0, y, aTopLineSz.Width(), y+aTopLineSz.Height()), g );
+ y += aTopLineSz.Height();
+
+ if ( bDrawSep )
+ pThis->DrawLine( Point(0, y-2), Point(aTopLineSz.Width(), y-2) );
+
+ while( y < (pThis->mnDY - aBottomLineSz.Height()) )
+ {
+ pThis->DrawGradient( Rectangle( 0, y, aLineSz.Width(), y+aLineSz.Height()), g);
+ y += aLineSz.Height();
+
+ if ( bDrawSep )
+ pThis->DrawLine( Point(0, y-2), Point(aLineSz.Width(), y-2) );
+ }
+
+ pThis->DrawGradient( Rectangle( 0, y, aBottomLineSz.Width(), y+aBottomLineSz.Height()), g );
+ if ( bDrawSep )
+ pThis->DrawLine( Point(0, y-2), Point(aBottomLineSz.Width(), y-2) );
+ }
+ else
+ {
+ long x = 0;
+
+ pThis->DrawGradient( Rectangle( x, 0, x+aTopLineSz.Width(), aTopLineSz.Height()), g );
+ x += aTopLineSz.Width();
+
+ while( x < (pThis->mnDX - aBottomLineSz.Width()) )
+ {
+ pThis->DrawGradient( Rectangle( x, 0, x+aLineSz.Width(), aLineSz.Height()), g);
+ x += aLineSz.Width();
+ }
+
+ pThis->DrawGradient( Rectangle( x, 0, x+aBottomLineSz.Width(), aBottomLineSz.Height()), g );
+ }
+
+ if( bLineColor )
+ pThis->SetLineColor( aOldCol );
+
+}
+
+BOOL ToolBox::ImplDrawNativeBackground( ToolBox* pThis, const Region & )
+{
+ // use NWF
+ Point aPt;
+ Rectangle aCtrlRegion( aPt, pThis->GetOutputSizePixel() );
+ ControlState nState = CTRL_STATE_ENABLED;
+
+ return pThis->DrawNativeControl( CTRL_TOOLBAR, pThis->mbHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT,
+ aCtrlRegion, nState, ImplControlValue(), rtl::OUString() );
+}
+
+void ToolBox::ImplDrawTransparentBackground( ToolBox* pThis, const Region &rRegion )
+{
+ // just invalidate to trigger paint of the parent
+
+ const bool bOldPaintLock = pThis->mpData->mbIsPaintLocked;
+ pThis->mpData->mbIsPaintLocked = true;
+
+ // send an invalidate to the first opaque parent and invalidate the whole hierarchy from there (noclipchildren)
+ pThis->Invalidate( rRegion, INVALIDATE_UPDATE|INVALIDATE_NOCLIPCHILDREN );
+
+ pThis->mpData->mbIsPaintLocked = bOldPaintLock;
+}
+
+void ToolBox::ImplDrawConstantBackground( ToolBox* pThis, const Region &rRegion, BOOL bIsInPopupMode )
+{
+ // draw a constant color
+ if( !bIsInPopupMode )
+ // default background
+ pThis->Erase( rRegion.GetBoundRect() );
+ else
+ {
+ // use different color in popupmode
+ pThis->DrawWallpaper( rRegion.GetBoundRect(),
+ Wallpaper( pThis->GetSettings().GetStyleSettings().GetFaceGradientColor() ) );
+ }
+}
+
+
+void ToolBox::ImplDrawBackground( ToolBox* pThis, const Rectangle &rRect )
+{
+ // execute pending paint requests
+ ImplCheckUpdate( pThis );
+
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
+ BOOL bIsInPopupMode = pThis->ImplIsInPopupMode();
+
+ Region aPaintRegion( rRect );
+
+ // make sure we do not invalidate/erase too much
+ if( pThis->IsInPaint() )
+ aPaintRegion.Intersect( pThis->GetActiveClipRegion() );
+
+ pThis->Push( PUSH_CLIPREGION );
+ pThis->IntersectClipRegion( aPaintRegion );
+
+
+ if( !pWrapper /*|| bIsInPopupMode*/ )
+ {
+ // no gradient for ordinary toolbars (not dockable)
+ if( !pThis->IsBackground() && !pThis->IsInPaint() )
+ ImplDrawTransparentBackground( pThis, aPaintRegion );
+ else
+ ImplDrawConstantBackground( pThis, aPaintRegion, bIsInPopupMode );
+ }
+ else
+ {
+ // toolbars known to the dockingmanager will be drawn using NWF or a gradient
+ // docked toolbars are transparent and NWF is already used in the docking area which is their common background
+ // so NWF is used here for floating toolbars only
+ BOOL bNativeOk = FALSE;
+ if( pThis->ImplIsFloatingMode() && pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL) )
+ bNativeOk = ImplDrawNativeBackground( pThis, aPaintRegion );
+
+ if( !bNativeOk )
+ {
+ if( !pThis->IsBackground() )
+ {
+ if( !pThis->IsInPaint() )
+ ImplDrawTransparentBackground( pThis, aPaintRegion );
+ }
+ else
+ ImplDrawGradientBackground( pThis, pWrapper );
+ }
+ }
+
+ // restore clip region
+ pThis->Pop();
+}
+
+void ToolBox::ImplErase( ToolBox* pThis, const Rectangle &rRect, BOOL bHighlight, BOOL bHasOpenPopup )
+{
+ // the background of non NWF buttons is painted in a constant color
+ // to have the same highlight color (transparency in DrawSelectionBackground())
+ // items with open popups will also painted using a constant color
+ if( !pThis->mpData->mbNativeButtons &&
+ (bHighlight || ! (((Window*) pThis)->GetStyle() & WB_3DLOOK ) ) )
+ {
+ if( (((Window*) pThis)->GetStyle() & WB_3DLOOK ) )
+ {
+ pThis->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ pThis->SetLineColor();
+ if( bHasOpenPopup )
+ // choose the same color as the popup will use
+ pThis->SetFillColor( pThis->GetSettings().GetStyleSettings().GetFaceGradientColor() );
+ else
+ pThis->SetFillColor( Color( COL_WHITE ) );
+
+ pThis->DrawRect( rRect );
+ pThis->Pop();
+ }
+ else
+ ImplDrawBackground( pThis, rRect );
+ }
+ else
+ ImplDrawBackground( pThis, rRect );
+}
+
+void ToolBox::ImplDrawBorder( ToolBox* pWin )
+{
+ const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
+ long nDX = pWin->mnDX;
+ long nDY = pWin->mnDY;
+
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pWin );
+
+ // draw borders for ordinary toolbars only (not dockable)
+ if( pWrapper )
+ return;
+
+ if ( pWin->meAlign == WINDOWALIGN_BOTTOM )
+ {
+ // draw bottom border
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ else
+ {
+ // draw top border
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 0, 1 ), Point( nDX-1, 1 ) );
+
+ if ( (pWin->meAlign == WINDOWALIGN_LEFT) || (pWin->meAlign == WINDOWALIGN_RIGHT) )
+ {
+ if ( pWin->meAlign == WINDOWALIGN_LEFT )
+ {
+ // draw left-bottom border
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ else
+ {
+ // draw right-bottom border
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) );
+ pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
+ pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
+ }
+ }
+ }
+
+
+ if ( pWin->meAlign == WINDOWALIGN_BOTTOM || pWin->meAlign == WINDOWALIGN_TOP )
+ {
+ // draw right border
+ pWin->SetLineColor( rStyleSettings.GetShadowColor() );
+ pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-1 ) );
+ pWin->SetLineColor( rStyleSettings.GetLightColor() );
+ pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static bool ImplIsFixedControl( const ImplToolItem *pItem )
+{
+ return ( pItem->mpWindow &&
+ (pItem->mpWindow->GetType() == WINDOW_FIXEDTEXT ||
+ pItem->mpWindow->GetType() == WINDOW_FIXEDLINE ||
+ pItem->mpWindow->GetType() == WINDOW_GROUPBOX) );
+}
+
+// -----------------------------------------------------------------------
+
+const ImplToolItem *ToolBox::ImplGetFirstClippedItem( const ToolBox* pThis )
+{
+ std::vector< ImplToolItem >::const_iterator it;
+ it = pThis->mpData->m_aItems.begin();
+ while ( it != pThis->mpData->m_aItems.end() )
+ {
+ if( it->IsClipped() )
+ return &(*it);
+ ++it;
+ }
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Size ToolBox::ImplCalcSize( const ToolBox* pThis, USHORT nCalcLines, USHORT nCalcMode )
+{
+ long nMax;
+ long nLeft = 0;
+ long nTop = 0;
+ long nRight = 0;
+ long nBottom = 0;
+ Size aSize;
+ WindowAlign eOldAlign = pThis->meAlign;
+ BOOL bOldHorz = pThis->mbHorz;
+ BOOL bOldAssumeDocked = pThis->mpData->mbAssumeDocked;
+ BOOL bOldAssumeFloating = pThis->mpData->mbAssumeFloating;
+
+ if ( nCalcMode )
+ {
+ BOOL bOldFloatingMode = pThis->ImplIsFloatingMode();
+
+ pThis->mpData->mbAssumeDocked = FALSE;
+ pThis->mpData->mbAssumeFloating = FALSE;
+
+ if ( nCalcMode == TB_CALCMODE_HORZ )
+ {
+ pThis->mpData->mbAssumeDocked = TRUE; // force non-floating mode during calculation
+ ImplCalcBorder( WINDOWALIGN_TOP, nLeft, nTop, nRight, nBottom, pThis );
+ ((ToolBox*)pThis)->mbHorz = TRUE;
+ if ( pThis->mbHorz != bOldHorz )
+ ((ToolBox*)pThis)->meAlign = WINDOWALIGN_TOP;
+ }
+ else if ( nCalcMode == TB_CALCMODE_VERT )
+ {
+ pThis->mpData->mbAssumeDocked = TRUE; // force non-floating mode during calculation
+ ImplCalcBorder( WINDOWALIGN_LEFT, nLeft, nTop, nRight, nBottom, pThis );
+ ((ToolBox*)pThis)->mbHorz = FALSE;
+ if ( pThis->mbHorz != bOldHorz )
+ ((ToolBox*)pThis)->meAlign = WINDOWALIGN_LEFT;
+ }
+ else if ( nCalcMode == TB_CALCMODE_FLOAT )
+ {
+ pThis->mpData->mbAssumeFloating = TRUE; // force non-floating mode during calculation
+ nLeft = nTop = nRight = nBottom = 0;
+ ((ToolBox*)pThis)->mbHorz = TRUE;
+ if ( pThis->mbHorz != bOldHorz )
+ ((ToolBox*)pThis)->meAlign = WINDOWALIGN_TOP;
+ }
+
+ if ( (pThis->meAlign != eOldAlign) || (pThis->mbHorz != bOldHorz) ||
+ (pThis->ImplIsFloatingMode() != bOldFloatingMode ) )
+ ((ToolBox*)pThis)->mbCalc = TRUE;
+ }
+ else
+ ImplCalcBorder( pThis->meAlign, nLeft, nTop, nRight, nBottom, pThis );
+
+ ((ToolBox*)pThis)->ImplCalcItem();
+
+ if( !nCalcMode && pThis->ImplIsFloatingMode() )
+ {
+ aSize = ImplCalcFloatSize( ((ToolBox*)pThis), nCalcLines );
+ }
+ else
+ {
+ if ( pThis->mbHorz )
+ {
+ if ( pThis->mnWinHeight > pThis->mnMaxItemHeight )
+ aSize.Height() = nCalcLines * pThis->mnWinHeight;
+ else
+ aSize.Height() = nCalcLines * pThis->mnMaxItemHeight;
+
+ if ( pThis->mnWinStyle & WB_LINESPACING )
+ aSize.Height() += (nCalcLines-1)*TB_LINESPACING;
+
+ if ( pThis->mnWinStyle & WB_BORDER )
+ aSize.Height() += (TB_BORDER_OFFSET2*2) + nTop + nBottom;
+
+ nMax = 0;
+ ((ToolBox*)pThis)->ImplCalcBreaks( TB_MAXNOSCROLL, &nMax, pThis->mbHorz );
+ if ( nMax )
+ aSize.Width() += nMax;
+
+ if ( pThis->mnWinStyle & WB_BORDER )
+ aSize.Width() += (TB_BORDER_OFFSET1*2) + nLeft + nRight;
+ }
+ else
+ {
+ aSize.Width() = nCalcLines * pThis->mnMaxItemWidth;
+
+ if ( pThis->mnWinStyle & WB_LINESPACING )
+ aSize.Width() += (nCalcLines-1)*TB_LINESPACING;
+
+ if ( pThis->mnWinStyle & WB_BORDER )
+ aSize.Width() += (TB_BORDER_OFFSET2*2) + nLeft + nRight;
+
+ nMax = 0;
+ ((ToolBox*)pThis)->ImplCalcBreaks( TB_MAXNOSCROLL, &nMax, pThis->mbHorz );
+ if ( nMax )
+ aSize.Height() += nMax;
+
+ if ( pThis->mnWinStyle & WB_BORDER )
+ aSize.Height() += (TB_BORDER_OFFSET1*2) + nTop + nBottom;
+ }
+ }
+ // restore previous values
+ if ( nCalcMode )
+ {
+ pThis->mpData->mbAssumeDocked = bOldAssumeDocked;
+ pThis->mpData->mbAssumeFloating = bOldAssumeFloating;
+ if ( (pThis->meAlign != eOldAlign) || (pThis->mbHorz != bOldHorz) )
+ {
+ ((ToolBox*)pThis)->meAlign = eOldAlign;
+ ((ToolBox*)pThis)->mbHorz = bOldHorz;
+ ((ToolBox*)pThis)->mbCalc = TRUE;
+ }
+ }
+
+ if ( aSize.Width() )
+ aSize.Width() += pThis->mnBorderX*2;
+ if ( aSize.Height() )
+ aSize.Height() += pThis->mnBorderY*2;
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplCalcFloatSizes( ToolBox* pThis )
+{
+ if ( pThis->mpFloatSizeAry )
+ return;
+
+ // calculate the minimal size, i.e. where the biggest item just fits
+ long nCalcSize = 0;
+
+ std::vector< ImplToolItem >::const_iterator it;
+ it = pThis->mpData->m_aItems.begin();
+ while ( it != pThis->mpData->m_aItems.end() )
+ {
+ if ( it->mbVisible )
+ {
+ if ( it->mpWindow )
+ {
+ long nTempSize = it->mpWindow->GetSizePixel().Width();
+ if ( nTempSize > nCalcSize )
+ nCalcSize = nTempSize;
+ }
+ else
+ {
+ if( it->maItemSize.Width() > nCalcSize )
+ nCalcSize = it->maItemSize.Width();
+ }
+ }
+ ++it;
+ }
+
+ // calc an upper bound for ImplCalcBreaks below
+ long upperBoundWidth = nCalcSize * pThis->mpData->m_aItems.size();
+
+ USHORT i;
+ USHORT nLines;
+ USHORT nCalcLines;
+ USHORT nTempLines;
+ long nHeight;
+ long nMaxLineWidth;
+ nCalcLines = pThis->ImplCalcBreaks( nCalcSize, &nMaxLineWidth, TRUE );
+
+ pThis->mpFloatSizeAry = new ImplToolSizeArray;
+ pThis->mpFloatSizeAry->mpSize = new ImplToolSize[nCalcLines];
+ pThis->mpFloatSizeAry->mnLength = nCalcLines;
+
+ memset( pThis->mpFloatSizeAry->mpSize, 0, sizeof( ImplToolSize )*nCalcLines );
+ i = 0;
+ nTempLines = nLines = nCalcLines;
+ while ( nLines )
+ {
+ nHeight = ImplCalcSize( pThis, nTempLines, TB_CALCMODE_FLOAT ).Height();
+ pThis->mpFloatSizeAry->mnLastEntry = i;
+ pThis->mpFloatSizeAry->mpSize[i].mnHeight = nHeight;
+ pThis->mpFloatSizeAry->mpSize[i].mnLines = nTempLines;
+ pThis->mpFloatSizeAry->mpSize[i].mnWidth = nMaxLineWidth+(TB_BORDER_OFFSET1*2);
+ nLines--;
+ if ( nLines )
+ {
+ do
+ {
+ nCalcSize += pThis->mnMaxItemWidth;
+ nTempLines = pThis->ImplCalcBreaks( nCalcSize, &nMaxLineWidth, TRUE );
+ }
+ while ( (nCalcSize < upperBoundWidth) && (nLines < nTempLines) && (nTempLines != 1) );
+ if ( nTempLines < nLines )
+ nLines = nTempLines;
+ }
+ i++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size ToolBox::ImplCalcFloatSize( ToolBox* pThis, USHORT& rLines )
+{
+ ImplCalcFloatSizes( pThis );
+
+ if ( !rLines )
+ {
+ rLines = pThis->mnFloatLines;
+ if ( !rLines )
+ rLines = pThis->mnLines;
+ }
+
+ USHORT i = 0;
+ while ( i < pThis->mpFloatSizeAry->mnLastEntry &&
+ rLines < pThis->mpFloatSizeAry->mpSize[i].mnLines )
+ i++;
+
+ Size aSize( pThis->mpFloatSizeAry->mpSize[i].mnWidth,
+ pThis->mpFloatSizeAry->mpSize[i].mnHeight );
+ rLines = pThis->mpFloatSizeAry->mpSize[i].mnLines;
+ if ( pThis->maNextToolBoxStr.Len() && pThis->mbScroll )
+ aSize.Width() += TB_NEXT_SIZE-TB_NEXT_OFFSET;
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplCalcMinMaxFloatSize( ToolBox* pThis, Size& rMinSize, Size& rMaxSize )
+{
+ ImplCalcFloatSizes( pThis );
+
+ USHORT i = 0;
+ rMinSize = Size( pThis->mpFloatSizeAry->mpSize[i].mnWidth, pThis->mpFloatSizeAry->mpSize[i].mnHeight );
+ rMaxSize = Size( pThis->mpFloatSizeAry->mpSize[i].mnWidth, pThis->mpFloatSizeAry->mpSize[i].mnHeight );
+ while ( ++i <= pThis->mpFloatSizeAry->mnLastEntry )
+ {
+ if( pThis->mpFloatSizeAry->mpSize[i].mnWidth < rMinSize.Width() )
+ rMinSize.Width() = pThis->mpFloatSizeAry->mpSize[i].mnWidth;
+ if( pThis->mpFloatSizeAry->mpSize[i].mnHeight < rMinSize.Height() )
+ rMinSize.Height() = pThis->mpFloatSizeAry->mpSize[i].mnHeight;
+
+ if( pThis->mpFloatSizeAry->mpSize[i].mnWidth > rMaxSize.Width() )
+ rMaxSize.Width() = pThis->mpFloatSizeAry->mpSize[i].mnWidth;
+ if( pThis->mpFloatSizeAry->mpSize[i].mnHeight > rMaxSize.Height() )
+ rMaxSize.Height() = pThis->mpFloatSizeAry->mpSize[i].mnHeight;
+ }
+}
+
+void ToolBox::ImplSetMinMaxFloatSize( ToolBox *pThis )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
+ Size aMinSize, aMaxSize;
+ ImplCalcMinMaxFloatSize( pThis, aMinSize, aMaxSize );
+ if( pWrapper )
+ {
+ pWrapper->SetMinOutputSizePixel( aMinSize );
+ pWrapper->SetMaxOutputSizePixel( aMaxSize );
+ pWrapper->ShowTitleButton( TITLE_BUTTON_MENU, ( pThis->GetMenuType() & TOOLBOX_MENUTYPE_CUSTOMIZE) ? TRUE : FALSE );
+ }
+ else
+ {
+ // TODO: change SetMinOutputSizePixel to be not inline
+ pThis->SetMinOutputSizePixel( aMinSize );
+ pThis->SetMaxOutputSizePixel( aMaxSize );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+
+USHORT ToolBox::ImplCalcLines( ToolBox* pThis, long nToolSize )
+{
+ long nLineHeight;
+
+ if ( pThis->mbHorz )
+ {
+ if ( pThis->mnWinHeight > pThis->mnMaxItemHeight )
+ nLineHeight = pThis->mnWinHeight;
+ else
+ nLineHeight = pThis->mnMaxItemHeight;
+ }
+ else
+ nLineHeight = pThis->mnMaxItemWidth;
+
+ if ( pThis->mnWinStyle & WB_BORDER )
+ nToolSize -= TB_BORDER_OFFSET2*2;
+
+ if ( pThis->mnWinStyle & WB_LINESPACING )
+ {
+ nLineHeight += TB_LINESPACING;
+ nToolSize += TB_LINESPACING;
+ }
+
+ // #i91917# always report at least one line
+ long nLines = nToolSize/nLineHeight;
+ if( nLines < 1 )
+ nLines = 1;
+
+ return static_cast<USHORT>(nLines);
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::ImplTestLineSize( ToolBox* pThis, const Point& rPos )
+{
+ if ( !pThis->ImplIsFloatingMode() &&
+ (!pThis->mbScroll || (pThis->mnLines > 1) || (pThis->mnCurLines > pThis->mnVisLines)) )
+ {
+ WindowAlign eAlign = pThis->GetAlign();
+
+ if ( eAlign == WINDOWALIGN_LEFT )
+ {
+ if ( rPos.X() > pThis->mnDX-DOCK_LINEOFFSET )
+ return DOCK_LINEHSIZE | DOCK_LINERIGHT;
+ }
+ else if ( eAlign == WINDOWALIGN_TOP )
+ {
+ if ( rPos.Y() > pThis->mnDY-DOCK_LINEOFFSET )
+ return DOCK_LINEVSIZE | DOCK_LINEBOTTOM;
+ }
+ else if ( eAlign == WINDOWALIGN_RIGHT )
+ {
+ if ( rPos.X() < DOCK_LINEOFFSET )
+ return DOCK_LINEHSIZE | DOCK_LINELEFT;
+ }
+ else if ( eAlign == WINDOWALIGN_BOTTOM )
+ {
+ if ( rPos.Y() < DOCK_LINEOFFSET )
+ return DOCK_LINEVSIZE | DOCK_LINETOP;
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplLineSizing( ToolBox* pThis, const Point& rPos, Rectangle& rRect,
+ USHORT nLineMode )
+{
+ BOOL mbHorz;
+ long nOneLineSize;
+ long nCurSize;
+ long nMaxSize;
+ long nSize;
+ Size aSize;
+
+ if ( nLineMode & DOCK_LINERIGHT )
+ {
+ nCurSize = rPos.X() - rRect.Left();
+ mbHorz = FALSE;
+ }
+ else if ( nLineMode & DOCK_LINEBOTTOM )
+ {
+ nCurSize = rPos.Y() - rRect.Top();
+ mbHorz = TRUE;
+ }
+ else if ( nLineMode & DOCK_LINELEFT )
+ {
+ nCurSize = rRect.Right() - rPos.X();
+ mbHorz = FALSE;
+ }
+ else if ( nLineMode & DOCK_LINETOP )
+ {
+ nCurSize = rRect.Bottom() - rPos.Y();
+ mbHorz = TRUE;
+ }
+ else {
+ DBG_ERROR( "ImplLineSizing: Trailing else" );
+ nCurSize = 0;
+ mbHorz = FALSE;
+ }
+
+ Size aWinSize = pThis->GetSizePixel();
+ USHORT nMaxLines = (pThis->mnLines > pThis->mnCurLines) ? pThis->mnLines : pThis->mnCurLines;
+ if ( nMaxLines > TB_MAXLINES )
+ nMaxLines = TB_MAXLINES;
+ if ( mbHorz )
+ {
+ nOneLineSize = ImplCalcSize( pThis, 1 ).Height();
+ nMaxSize = pThis->maOutDockRect.GetHeight() - 20;
+ if ( nMaxSize < aWinSize.Height() )
+ nMaxSize = aWinSize.Height();
+ }
+ else
+ {
+ nOneLineSize = ImplCalcSize( pThis, 1 ).Width();
+ nMaxSize = pThis->maOutDockRect.GetWidth() - 20;
+ if ( nMaxSize < aWinSize.Width() )
+ nMaxSize = aWinSize.Width();
+ }
+
+ USHORT i = 1;
+ if ( nCurSize <= nOneLineSize )
+ nSize = nOneLineSize;
+ else
+ {
+ nSize = 0;
+ while ( (nSize < nCurSize) && (i < nMaxLines) )
+ {
+ i++;
+ aSize = ImplCalcSize( pThis, i );
+ if ( mbHorz )
+ nSize = aSize.Height();
+ else
+ nSize = aSize.Width();
+ if ( nSize > nMaxSize )
+ {
+ i--;
+ aSize = ImplCalcSize( pThis, i );
+ if ( mbHorz )
+ nSize = aSize.Height();
+ else
+ nSize = aSize.Width();
+ break;
+ }
+ }
+ }
+
+ if ( nLineMode & DOCK_LINERIGHT )
+ rRect.Right() = rRect.Left()+nSize-1;
+ else if ( nLineMode & DOCK_LINEBOTTOM )
+ rRect.Bottom() = rRect.Top()+nSize-1;
+ else if ( nLineMode & DOCK_LINELEFT )
+ rRect.Left() = rRect.Right()-nSize;
+ else //if ( nLineMode & DOCK_LINETOP )
+ rRect.Top() = rRect.Bottom()-nSize;
+
+ pThis->mnDockLines = i;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::ImplFindItemPos( ToolBox* pBox, const Point& rPos )
+{
+ USHORT nPos = 0;
+ long nLast = 0;
+ Point aPos = rPos;
+ Size aSize( pBox->mnDX, pBox->mnDY );
+
+ if ( aPos.X() > aSize.Width()-TB_BORDER_OFFSET1 )
+ aPos.X() = aSize.Width()-TB_BORDER_OFFSET1;
+ if ( aPos.Y() > aSize.Height()-TB_BORDER_OFFSET1 )
+ aPos.Y() = aSize.Height()-TB_BORDER_OFFSET1;
+
+ // Item suchen, das geklickt wurde
+ std::vector< ImplToolItem >::const_iterator it = pBox->mpData->m_aItems.begin();
+ while ( it != pBox->mpData->m_aItems.end() )
+ {
+ if ( it->mbVisible )
+ {
+ if ( nLast || !it->maRect.IsEmpty() )
+ {
+ if ( pBox->mbHorz )
+ {
+ if ( nLast &&
+ ((nLast < it->maRect.Top()) || it->maRect.IsEmpty()) )
+ return nPos;
+
+ if ( aPos.Y() <= it->maRect.Bottom() )
+ {
+ if ( aPos.X() < it->maRect.Left() )
+ return nPos;
+ else if ( aPos.X() < it->maRect.Right() )
+ return nPos+1;
+ else if ( !nLast )
+ nLast = it->maRect.Bottom();
+ }
+ }
+ else
+ {
+ if ( nLast &&
+ ((nLast < it->maRect.Left()) || it->maRect.IsEmpty()) )
+ return nPos;
+
+ if ( aPos.X() <= it->maRect.Right() )
+ {
+ if ( aPos.Y() < it->maRect.Top() )
+ return nPos;
+ else if ( aPos.Y() < it->maRect.Bottom() )
+ return nPos+1;
+ else if ( !nLast )
+ nLast = it->maRect.Right();
+ }
+ }
+ }
+ }
+
+ nPos++;
+ ++it;
+ }
+
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+ImplTBDragMgr::ImplTBDragMgr()
+{
+ mpBoxList = new ImplTBList( 4, 4 );
+ mnLineMode = 0;
+ mnStartLines = 0;
+ mbCustomizeMode = FALSE;
+ mbResizeMode = FALSE;
+ mbShowDragRect = FALSE;
+ mpDragBox = NULL;
+
+ maAccel.InsertItem( KEY_RETURN, KeyCode( KEY_RETURN ) );
+ maAccel.InsertItem( KEY_ESCAPE, KeyCode( KEY_ESCAPE ) );
+ maAccel.SetSelectHdl( LINK( this, ImplTBDragMgr, SelectHdl ) );
+}
+
+// -----------------------------------------------------------------------
+
+ImplTBDragMgr::~ImplTBDragMgr()
+{
+ delete mpBoxList;
+}
+
+// -----------------------------------------------------------------------
+
+ToolBox* ImplTBDragMgr::FindToolBox( const Rectangle& rRect )
+{
+ ToolBox* pBox = mpBoxList->First();
+ while ( pBox )
+ {
+ /*
+ * FIXME: since we can have multiple frames now we cannot
+ * find the drag target by its position alone.
+ * As long as the toolbar config dialogue is not a system window
+ * this works in one frame only anyway. If the dialogue
+ * changes to a system window, we need a new implementation here
+ */
+ if ( pBox->IsReallyVisible() && pBox->ImplGetWindowImpl()->mpFrame == mpDragBox->ImplGetWindowImpl()->mpFrame )
+ {
+ if ( !pBox->ImplIsFloatingMode() )
+ {
+ Point aPos = pBox->GetPosPixel();
+ aPos = pBox->GetParent()->OutputToScreenPixel( aPos );
+ Rectangle aTempRect( aPos, pBox->GetSizePixel() );
+ if ( aTempRect.IsOver( rRect ) )
+ return pBox;
+ }
+ }
+
+ pBox = mpBoxList->Next();
+ }
+
+ return pBox;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplTBDragMgr::StartDragging( ToolBox* pToolBox,
+ const Point& rPos, const Rectangle& rRect,
+ USHORT nDragLineMode, BOOL bResizeItem,
+ void* pData )
+{
+ mpDragBox = pToolBox;
+ pToolBox->CaptureMouse();
+ pToolBox->mbDragging = TRUE;
+ Application::InsertAccel( &maAccel );
+
+ if ( nDragLineMode )
+ {
+ mnLineMode = nDragLineMode;
+ mnStartLines = pToolBox->mnDockLines;
+ }
+ else
+ {
+ mpCustomizeData = pData;
+ mbResizeMode = bResizeItem;
+ pToolBox->Activate();
+ pToolBox->mnCurItemId = pToolBox->mnConfigItem;
+ pToolBox->Highlight();
+ pToolBox->mnCurItemId = 0;
+ if ( mbResizeMode )
+ {
+ if ( rRect.GetWidth() < TB_MIN_WIN_WIDTH )
+ mnMinWidth = rRect.GetWidth();
+ else
+ mnMinWidth = TB_MIN_WIN_WIDTH;
+ mnMaxWidth = pToolBox->GetSizePixel().Width()-rRect.Left()-
+ TB_SPIN_SIZE-TB_BORDER_OFFSET1-(TB_SPIN_OFFSET*2);
+ }
+ }
+
+ // MouseOffset berechnen
+ maMouseOff.X() = rRect.Left() - rPos.X();
+ maMouseOff.Y() = rRect.Top() - rPos.Y();
+ maRect = rRect;
+ maStartRect = rRect;
+ mbShowDragRect = TRUE;
+ pToolBox->ShowTracking( maRect );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplTBDragMgr::Dragging( const Point& rPos )
+{
+ if ( mnLineMode )
+ {
+ ToolBox::ImplLineSizing( mpDragBox, rPos, maRect, mnLineMode );
+ Point aOff = mpDragBox->OutputToScreenPixel( Point() );
+ maRect.Move( aOff.X(), aOff.Y() );
+ mpDragBox->Docking( rPos, maRect );
+ maRect.Move( -aOff.X(), -aOff.Y() );
+ mpDragBox->ShowTracking( maRect );
+ }
+ else
+ {
+ if ( mbResizeMode )
+ {
+ long nXOff = rPos.X()-maStartRect.Left();
+ nXOff += maMouseOff.X()+(maStartRect.Right()-maStartRect.Left());
+ if ( nXOff < mnMinWidth )
+ nXOff = mnMinWidth;
+ if ( nXOff > mnMaxWidth )
+ nXOff = mnMaxWidth;
+ maRect.Right() = maStartRect.Left()+nXOff;
+ }
+ else
+ {
+ maRect.SetPos( rPos );
+ maRect.Move( maMouseOff.X(), maMouseOff.Y() );
+ }
+ mpDragBox->ShowTracking( maRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplTBDragMgr::EndDragging( BOOL bOK )
+{
+ mpDragBox->HideTracking();
+ mpDragBox->ReleaseMouse();
+ mpDragBox->mbDragging = FALSE;
+ mbShowDragRect = FALSE;
+ Application::RemoveAccel( &maAccel );
+
+ if ( mnLineMode )
+ {
+ if ( !bOK )
+ {
+ mpDragBox->mnDockLines = mnStartLines;
+ mpDragBox->EndDocking( maStartRect, FALSE );
+ }
+ else
+ mpDragBox->EndDocking( maRect, FALSE );
+ mnLineMode = 0;
+ mnStartLines = 0;
+ }
+ else
+ {
+ USHORT nTempItem = mpDragBox->mnConfigItem;
+ if ( nTempItem )
+ {
+ mpDragBox->mnConfigItem = 0;
+ if ( !mbResizeMode )
+ mpDragBox->Invalidate( mpDragBox->GetItemRect( nTempItem ) );
+ }
+
+ if ( bOK && (maRect != maStartRect) )
+ {
+ if ( mbResizeMode )
+ {
+ ImplToolItem* pItem = mpDragBox->ImplGetItem( nTempItem );
+ Size aSize = pItem->mpWindow->GetSizePixel();
+ aSize.Width() = maRect.GetWidth();
+ pItem->mpWindow->SetSizePixel( aSize );
+
+ // ToolBox neu brechnen und neu ausgeben
+ mpDragBox->ImplInvalidate( TRUE );
+ mpDragBox->Customize( ToolBoxCustomizeEvent( mpDragBox, nTempItem,
+ TOOLBOX_CUSTOMIZE_RESIZE,
+ mpCustomizeData ) );
+ }
+ else
+ {
+ Point aOff = mpDragBox->OutputToScreenPixel( Point() );
+ Rectangle aScreenRect( maRect );
+ aScreenRect.Move( aOff.X(), aOff.Y() );
+ ToolBox* pDropBox = FindToolBox( aScreenRect );
+ if ( pDropBox )
+ {
+ // Such-Position bestimmen
+ Point aPos;
+ if ( pDropBox->mbHorz )
+ {
+ aPos.X() = aScreenRect.Left()-TB_CUSTOMIZE_OFFSET;
+ aPos.Y() = aScreenRect.Center().Y();
+ }
+ else
+ {
+ aPos.X() = aScreenRect.Center().X();
+ aPos.Y() = aScreenRect.Top()-TB_CUSTOMIZE_OFFSET;
+ }
+
+ aPos = pDropBox->ScreenToOutputPixel( aPos );
+ USHORT nPos = ToolBox::ImplFindItemPos( pDropBox, aPos );
+ mpDragBox->Customize( ToolBoxCustomizeEvent( pDropBox, nTempItem,
+ nPos, mpCustomizeData ) );
+ }
+ else
+ {
+ mpDragBox->Customize( ToolBoxCustomizeEvent( NULL, nTempItem,
+ 0, mpCustomizeData ) );
+ }
+ }
+ }
+ mpCustomizeData = NULL;
+ mbResizeMode = FALSE;
+ mpDragBox->Deactivate();
+ }
+
+ mpDragBox = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplTBDragMgr::UpdateDragRect()
+{
+ // Nur Updaten, wenn wir schon im Dragging sind
+ if ( !mbShowDragRect )
+ return;
+
+ mpDragBox->ShowTracking( maRect );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplTBDragMgr, SelectHdl, Accelerator*, pAccel )
+{
+ if ( pAccel->GetCurItemId() == KEY_ESCAPE )
+ EndDragging( FALSE );
+ else
+ EndDragging( TRUE );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplTBDragMgr::StartCustomizeMode()
+{
+ mbCustomizeMode = TRUE;
+
+ ToolBox* pBox = mpBoxList->First();
+ while ( pBox )
+ {
+ pBox->ImplStartCustomizeMode();
+ pBox = mpBoxList->Next();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplTBDragMgr::EndCustomizeMode()
+{
+ mbCustomizeMode = FALSE;
+
+ ToolBox* pBox = mpBoxList->First();
+ while ( pBox )
+ {
+ pBox->ImplEndCustomizeMode();
+ pBox = mpBoxList->Next();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+
+static void ImplDrawOutButton( OutputDevice* pOutDev, const Rectangle& rRect,
+ USHORT nStyle )
+{
+ const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
+ Color aShadowColor = rStyleSettings.GetShadowColor();
+ Point aPos( rRect.TopLeft() );
+ Size aSize( rRect.GetSize() );
+ long nOffset = 0;
+
+ if ( pOutDev->GetBackground().GetColor() == aShadowColor )
+ aShadowColor = rStyleSettings.GetDarkShadowColor();
+
+ if ( nStyle & BUTTON_DRAW_PRESSED )
+ {
+ aPos.X()++;
+ aPos.Y()++;
+ nOffset++;
+ }
+
+ // Hintergrund loeschen
+ pOutDev->Erase( rRect );
+
+ // Button zeichnen
+ pOutDev->SetLineColor( rStyleSettings.GetLightColor() );
+ pOutDev->DrawLine( aPos,
+ Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y() ) );
+ pOutDev->DrawLine( aPos,
+ Point( aPos.X(), aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ) );
+ pOutDev->SetLineColor( aShadowColor );
+ pOutDev->DrawLine( Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y() ),
+ Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ) );
+ pOutDev->DrawLine( Point( aPos.X(), aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ),
+ Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ) );
+ for ( long i = 0; i < OUTBUTTON_BORDER-1-nOffset; i++ )
+ {
+ pOutDev->DrawLine( Point( aPos.X()+aSize.Width()-(OUTBUTTON_BORDER-i-1), aPos.Y()+OUTBUTTON_BORDER ),
+ Point( aPos.X()+aSize.Width()-(OUTBUTTON_BORDER-i-1), aPos.Y()+aSize.Height()-1 ) );
+ pOutDev->DrawLine( Point( aPos.X()+OUTBUTTON_BORDER, aPos.Y()+aSize.Height()-(OUTBUTTON_BORDER-i-1) ),
+ Point( aPos.X()+aSize.Width()-1, aPos.Y()+aSize.Height()-(OUTBUTTON_BORDER-i-1) ) );
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplInit( Window* pParent, WinBits nStyle )
+{
+
+ // Variablen initialisieren
+ ImplGetWindowImpl()->mbToolBox = TRUE;
+ mpBtnDev = NULL;
+ mpFloatSizeAry = NULL;
+ mpData = new ImplToolBoxPrivateData;
+ mpFloatWin = NULL;
+ mnDX = 0;
+ mnDY = 0;
+ mnMaxItemWidth = 0;
+ mnMaxItemHeight = 0;
+ mnWinHeight = 0;
+ mnBorderX = 0;
+ mnBorderY = 0;
+ mnLeftBorder = 0;
+ mnTopBorder = 0;
+ mnRightBorder = 0;
+ mnBottomBorder = 0;
+ mnLastResizeDY = 0;
+ mnOutStyle = TOOLBOX_STYLE_FLAT; // force flat buttons since NWF
+ mnHighItemId = 0;
+ mnCurItemId = 0;
+ mnDownItemId = 0;
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ mnFocusPos = TOOLBOX_ITEM_NOTFOUND; // current position during keyboard access
+ mnLines = 1;
+ mnCurLine = 1;
+ mnCurLines = 1;
+ mnVisLines = 1;
+ mnFloatLines = 0;
+ mnConfigItem = 0;
+ mnMouseClicks = 0;
+ mnMouseModifier = 0;
+ mbDrag = FALSE;
+ mbSelection = FALSE;
+ mbCommandDrag = FALSE;
+ mbUpper = FALSE;
+ mbLower = FALSE;
+ mbNextTool = FALSE;
+ mbIn = FALSE;
+ mbCalc = TRUE;
+ mbFormat = FALSE;
+ mbFullPaint = FALSE;
+ mbHorz = TRUE;
+ mbScroll = (nStyle & WB_SCROLL) != 0;
+ mbCustomize = FALSE;
+ mbCustomizeMode = FALSE;
+ mbDragging = FALSE;
+ mbHideStatusText = FALSE;
+ mbMenuStrings = FALSE;
+ mbIsShift = FALSE;
+ mbIsKeyEvent = FALSE;
+ mbChangingHighlight = FALSE;
+ meButtonType = BUTTON_SYMBOL;
+ meAlign = WINDOWALIGN_TOP;
+ meLastStyle = POINTER_ARROW;
+ mnWinStyle = nStyle;
+ mnLastFocusItemId = 0;
+ mnKeyModifier = 0;
+ mnActivateCount = 0;
+
+ maTimer.SetTimeout( 50 );
+ maTimer.SetTimeoutHdl( LINK( this, ToolBox, ImplUpdateHdl ) );
+
+ // set timeout and handler for dropdown items
+ mpData->maDropdownTimer.SetTimeout( 250 );
+ mpData->maDropdownTimer.SetTimeoutHdl( LINK( this, ToolBox, ImplDropdownLongClickHdl ) );
+
+ DockingWindow::ImplInit( pParent, nStyle & ~(WB_BORDER) );
+
+
+ // always set WB_TABSTOP for ToolBars !!! if( mnWinStyle & WB_TABSTOP )
+ {
+ // dockingwindow's ImplInit removes some bits, so restore them here
+ // to allow keyboard handling for toolbars
+ ImplGetWindowImpl()->mnStyle |= WB_TABSTOP|WB_NODIALOGCONTROL;
+ ImplGetWindowImpl()->mnStyle &= ~WB_DIALOGCONTROL;
+ }
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ mpData->mbNativeButtons = IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON );
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if ( bFont )
+ {
+ Font aFont = rStyleSettings.GetToolFont();
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ SetZoomedPointFont( aFont );
+ }
+
+ if ( bForeground || bFont )
+ {
+ Color aColor;
+ if ( IsControlForeground() )
+ aColor = GetControlForeground();
+ else if ( Window::GetStyle() & WB_3DLOOK )
+ aColor = rStyleSettings.GetButtonTextColor();
+ else
+ aColor = rStyleSettings.GetWindowTextColor();
+ SetTextColor( aColor );
+ SetTextFillColor();
+ }
+
+ if ( bBackground )
+ {
+ Color aColor;
+ if ( IsControlBackground() )
+ {
+ aColor = GetControlBackground();
+ SetBackground( aColor );
+ SetPaintTransparent( FALSE );
+ SetParentClipMode( 0 );
+ }
+ else
+ {
+ if( IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) )
+ {
+ SetBackground();
+ SetPaintTransparent( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ mpData->maDisplayBackground = Wallpaper( rStyleSettings.GetFaceColor() );
+ }
+ else
+ {
+ if ( Window::GetStyle() & WB_3DLOOK )
+ aColor = rStyleSettings.GetFaceColor();
+ else
+ aColor = rStyleSettings.GetWindowColor();
+
+ SetBackground( aColor );
+ SetPaintTransparent( FALSE );
+ SetParentClipMode( 0 );
+
+ ImplUpdateImageList();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplLoadRes( const ResId& rResId )
+{
+ ResMgr* pMgr = rResId.GetResMgr();
+ if( ! pMgr )
+ return;
+
+ DockingWindow::ImplLoadRes( rResId );
+
+ ULONG nObjMask;
+
+ nObjMask = ReadLongRes();
+
+ if ( nObjMask & RSC_TOOLBOX_BUTTONTYPE )
+ SetButtonType( (ButtonType)ReadLongRes() );
+
+ if ( nObjMask & RSC_TOOLBOX_ALIGN )
+ SetAlign( (WindowAlign)ReadLongRes() );
+
+ if ( nObjMask & RSC_TOOLBOX_LINECOUNT )
+ SetLineCount( sal::static_int_cast<USHORT>(ReadLongRes()) );
+
+ if ( nObjMask & RSC_TOOLBOX_CUSTOMIZE )
+ {
+ BOOL bCust = (BOOL)ReadShortRes();
+ EnableCustomize( bCust );
+ }
+
+ if ( nObjMask & RSC_TOOLBOX_MENUSTRINGS )
+ {
+ BOOL bCust = (BOOL)ReadShortRes();
+ EnableMenuStrings( bCust );
+ }
+
+ if ( nObjMask & RSC_TOOLBOX_FLOATLINES )
+ SetFloatingLines( ReadShortRes() );
+
+ if ( nObjMask & RSC_TOOLBOX_ITEMIMAGELIST )
+ {
+ maImageList = ImageList( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ }
+
+ if ( nObjMask & RSC_TOOLBOX_ITEMLIST )
+ {
+ ULONG nEle = ReadLongRes();
+
+ // Item hinzufuegen
+ for ( ULONG i = 0; i < nEle; i++ )
+ {
+ InsertItem( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ToolBox::ToolBox( Window* pParent, WinBits nStyle ) :
+ DockingWindow( WINDOW_TOOLBOX )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+ToolBox::ToolBox( Window* pParent, const ResId& rResId ) :
+ DockingWindow( WINDOW_TOOLBOX )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "vcl: ToolBox::ToolBox( Window* pParent, const ResId& rResId )" );
+
+ rResId.SetRT( RSC_TOOLBOX );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ // Groesse des FloatingWindows berechnen und umschalten, wenn die
+ // ToolBox initial im FloatingModus ist
+ if ( ImplIsFloatingMode() )
+ mbHorz = TRUE;
+ else
+ Resize();
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+ToolBox::~ToolBox()
+{
+ // custom menu event still running?
+ if( mpData->mnEventId )
+ Application::RemoveUserEvent( mpData->mnEventId );
+
+ // #103005# make sure our activate/deactivate balance is right
+ while( mnActivateCount > 0 )
+ Deactivate();
+
+ // Falls noch ein Floating-Window connected ist, dann den
+ // PopupModus beenden
+ if ( mpFloatWin )
+ mpFloatWin->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL );
+
+ // delete private data
+ delete mpData;
+
+ // FloatSizeAry gegebenenfalls loeschen
+ if ( mpFloatSizeAry )
+ delete mpFloatSizeAry;
+
+ // Wenn keine ToolBox-Referenzen mehr auf die Listen bestehen, dann
+ // Listen mit wegloeschen
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maCtrlData.mpTBDragMgr )
+ {
+ // Wenn im TBDrag-Manager, dann wieder rausnehmen
+ if ( mbCustomize )
+ pSVData->maCtrlData.mpTBDragMgr->Remove( this );
+
+ if ( !pSVData->maCtrlData.mpTBDragMgr->Count() )
+ {
+ delete pSVData->maCtrlData.mpTBDragMgr;
+ pSVData->maCtrlData.mpTBDragMgr = NULL;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplToolItem* ToolBox::ImplGetItem( USHORT nItemId ) const
+{
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ if ( it->mnId == nItemId )
+ return &(*it);
+ ++it;
+ }
+
+ return NULL;
+}
+// -----------------------------------------------------------------------
+
+static void ImplAddButtonBorder( long &rWidth, long& rHeight, USHORT aOutStyle, BOOL bNativeButtons )
+{
+ if ( aOutStyle & TOOLBOX_STYLE_OUTBUTTON )
+ {
+ rWidth += OUTBUTTON_SIZE;
+ rHeight += OUTBUTTON_SIZE;
+ }
+ else
+ {
+ rWidth += SMALLBUTTON_HSIZE;
+ rHeight += SMALLBUTTON_VSIZE;
+ }
+
+ if( bNativeButtons )
+ {
+ // give more border space for rounded buttons
+ rWidth += 2;
+ rHeight += 4;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::ImplCalcItem()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ // recalc required ?
+ if ( !mbCalc )
+ return FALSE;
+
+ ImplDisableFlatButtons();
+
+ long nDefWidth;
+ long nDefHeight;
+ long nMaxWidth = 0;
+ long nMaxHeight = 0;
+ long nHeight;
+ long nMinWidth = 6;
+ long nMinHeight = 6;
+ long nDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
+
+ // set defaults if image or text is needed but empty
+ nDefWidth = GetDefaultImageSize().Width();
+ nDefHeight = GetDefaultImageSize().Height();
+
+ mnWinHeight = 0;
+ // determine minimum size necessary in NWF
+ {
+ Rectangle aRect( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
+ Rectangle aReg( aRect );
+ ImplControlValue aVal;
+ Rectangle aNativeBounds, aNativeContent;
+ if( IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
+ {
+ if( GetNativeControlRegion( CTRL_TOOLBAR, PART_BUTTON,
+ aReg,
+ CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER,
+ aVal, OUString(),
+ aNativeBounds, aNativeContent ) )
+ {
+ aRect = aNativeBounds;
+ if( aRect.GetWidth() > nMinWidth )
+ nMinWidth = aRect.GetWidth();
+ if( aRect.GetHeight() > nMinHeight )
+ nMinHeight = aRect.GetHeight();
+ if( nDropDownArrowWidth < nMinWidth )
+ nDropDownArrowWidth = nMinWidth;
+ if( nMinWidth > mpData->mnMenuButtonWidth )
+ mpData->mnMenuButtonWidth = nMinWidth;
+ else if( nMinWidth < TB_MENUBUTTON_SIZE )
+ mpData->mnMenuButtonWidth = TB_MENUBUTTON_SIZE;
+ }
+ }
+
+ // also calculate the area for comboboxes, drop down list boxes and spinfields
+ // as these are often inserted into toolboxes; set mnWinHeight to the
+ // greater of those values to prevent toolbar flickering (#i103385#)
+ aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
+ aReg = aRect;
+ if( GetNativeControlRegion( CTRL_COMBOBOX, PART_ENTIRE_CONTROL,
+ aReg,
+ CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER,
+ aVal, OUString(),
+ aNativeBounds, aNativeContent ) )
+ {
+ aRect = aNativeBounds;
+ if( aRect.GetHeight() > mnWinHeight )
+ mnWinHeight = aRect.GetHeight();
+ }
+ aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
+ aReg = aRect;
+ if( GetNativeControlRegion( CTRL_LISTBOX, PART_ENTIRE_CONTROL,
+ aReg,
+ CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER,
+ aVal, OUString(),
+ aNativeBounds, aNativeContent ) )
+ {
+ aRect = aNativeBounds;
+ if( aRect.GetHeight() > mnWinHeight )
+ mnWinHeight = aRect.GetHeight();
+ }
+ aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
+ aReg = aRect;
+ if( GetNativeControlRegion( CTRL_SPINBOX, PART_ENTIRE_CONTROL,
+ aReg,
+ CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER,
+ aVal, OUString(),
+ aNativeBounds, aNativeContent ) )
+ {
+ aRect = aNativeBounds;
+ if( aRect.GetHeight() > mnWinHeight )
+ mnWinHeight = aRect.GetHeight();
+ }
+ }
+
+ if ( ! mpData->m_aItems.empty() )
+ {
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ BOOL bImage;
+ BOOL bText;
+
+ it->mbVisibleText = FALSE; // indicates if text will definitely be drawn, influences dropdown pos
+
+ if ( it->meType == TOOLBOXITEM_BUTTON )
+ {
+ // check if image and/or text exists
+ if ( !(it->maImage) )
+ bImage = FALSE;
+ else
+ bImage = TRUE;
+ if ( !it->maText.Len() )
+ bText = FALSE;
+ else
+ bText = TRUE;
+ ButtonType tmpButtonType = determineButtonType( &(*it), meButtonType ); // default to toolbox setting
+ if ( bImage || bText )
+ {
+
+ it->mbEmptyBtn = FALSE;
+
+ if ( tmpButtonType == BUTTON_SYMBOL )
+ {
+ // we're drawing images only
+ if ( bImage || !bText )
+ {
+ it->maItemSize = it->maImage.GetSizePixel();
+ }
+ else
+ {
+ it->maItemSize = Size( GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET,
+ GetTextHeight() );
+ it->mbVisibleText = TRUE;
+ }
+ }
+ else if ( tmpButtonType == BUTTON_TEXT )
+ {
+ // we're drawing text only
+ if ( bText || !bImage )
+ {
+ it->maItemSize = Size( GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET,
+ GetTextHeight() );
+ it->mbVisibleText = TRUE;
+ }
+ else
+ {
+ it->maItemSize = it->maImage.GetSizePixel();
+ }
+ }
+ else
+ {
+ // we're drawing images and text
+ it->maItemSize.Width() = bText ? GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET : 0;
+ it->maItemSize.Height() = bText ? GetTextHeight() : 0;
+
+ // leave space between image and text
+ if( bText )
+ it->maItemSize.Width() += TB_IMAGETEXTOFFSET;
+
+ // image and text side by side
+ it->maItemSize.Width() += it->maImage.GetSizePixel().Width();
+ if ( it->maImage.GetSizePixel().Height() > it->maItemSize.Height() )
+ it->maItemSize.Height() = it->maImage.GetSizePixel().Height();
+
+ it->mbVisibleText = bText;
+ }
+ }
+ else
+ { // no image and no text
+ it->maItemSize = Size( nDefWidth, nDefHeight );
+ it->mbEmptyBtn = TRUE;
+ }
+
+ // Gegebenenfalls die Fensterhoehe mit beruecksichtigen
+ if ( it->mpWindow )
+ {
+ nHeight = it->mpWindow->GetSizePixel().Height();
+ if ( nHeight > mnWinHeight )
+ mnWinHeight = nHeight;
+ }
+
+ // add in drop down arrow
+ if( it->mnBits & TIB_DROPDOWN )
+ {
+ it->maItemSize.Width() += nDropDownArrowWidth;
+ it->mnDropDownArrowWidth = nDropDownArrowWidth;
+ }
+
+ // text items will be rotated in vertical mode
+ // -> swap width and height
+ if( it->mbVisibleText && !mbHorz )
+ {
+ long tmp = it->maItemSize.Width();
+ it->maItemSize.Width() = it->maItemSize.Height();
+ it->maItemSize.Height() = tmp;
+ }
+ }
+ else if ( it->meType == TOOLBOXITEM_SPACE )
+ {
+ it->maItemSize = Size( nDefWidth, nDefHeight );
+ }
+
+ if ( it->meType == TOOLBOXITEM_BUTTON || it->meType == TOOLBOXITEM_SPACE )
+ {
+ // add borders
+ ImplAddButtonBorder( it->maItemSize.Width(), it->maItemSize.Height(), mnOutStyle, mpData->mbNativeButtons );
+
+ if( it->meType == TOOLBOXITEM_BUTTON )
+ {
+ if( it->maItemSize.Width() < nMinWidth )
+ it->maItemSize.Width() = nMinWidth;
+ if( it->maItemSize.Height() < nMinHeight )
+ it->maItemSize.Height() = nMinHeight;
+ }
+
+ // keep track of max item size
+ if ( it->maItemSize.Width() > nMaxWidth )
+ nMaxWidth = it->maItemSize.Width();
+ if ( it->maItemSize.Height() > nMaxHeight )
+ nMaxHeight = it->maItemSize.Height();
+ }
+
+ ++it;
+ }
+ }
+ else
+ {
+ nMaxWidth = nDefWidth;
+ nMaxHeight = nDefHeight;
+
+ ImplAddButtonBorder( nMaxWidth, nMaxHeight, mnOutStyle, mpData->mbNativeButtons );
+ }
+
+ if( !ImplIsFloatingMode() && GetToolboxButtonSize() != TOOLBOX_BUTTONSIZE_DONTCARE )
+ {
+ // make sure all vertical toolbars have the same width and horizontal have the same height
+ // this depends on the used button sizes
+ // as this is used for alignement of multiple toolbars
+ // it is only required for docked toolbars
+
+ long nFixedWidth = nDefWidth+nDropDownArrowWidth;
+ long nFixedHeight = nDefHeight;
+ ImplAddButtonBorder( nFixedWidth, nFixedHeight, mnOutStyle, mpData->mbNativeButtons );
+
+ if( mbHorz )
+ nMaxHeight = nFixedHeight;
+ else
+ nMaxWidth = nFixedWidth;
+ }
+
+ mbCalc = FALSE;
+ mbFormat = TRUE;
+
+ // do we have to recalc the sizes ?
+ if ( (nMaxWidth != mnMaxItemWidth) || (nMaxHeight != mnMaxItemHeight) )
+ {
+ mnMaxItemWidth = nMaxWidth;
+ mnMaxItemHeight = nMaxHeight;
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::ImplCalcBreaks( long nWidth, long* pMaxLineWidth, BOOL bCalcHorz )
+{
+ ULONG nLineStart = 0;
+ ULONG nGroupStart = 0;
+ long nLineWidth = 0;
+ long nCurWidth;
+ long nLastGroupLineWidth = 0;
+ long nMaxLineWidth = 0;
+ USHORT nLines = 1;
+ BOOL bWindow;
+ BOOL bBreak = FALSE;
+ long nWidthTotal = nWidth;
+
+ // when docked the menubutton will be in the first line
+ // ->initialize first linewidth with button
+ if( IsMenuEnabled() && !ImplIsFloatingMode() )
+ nLineWidth = mpData->maMenubuttonItem.maItemSize.Width();
+
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ it->mbBreak = bBreak;
+ bBreak = FALSE;
+
+ if ( it->mbVisible )
+ {
+ bWindow = FALSE;
+ bBreak = FALSE;
+ nCurWidth = 0;
+
+ if ( it->meType == TOOLBOXITEM_BUTTON || it->meType == TOOLBOXITEM_SPACE )
+ {
+ if ( bCalcHorz )
+ nCurWidth = it->maItemSize.Width();
+ else
+ nCurWidth = it->maItemSize.Height();
+
+ if ( it->mpWindow && bCalcHorz )
+ {
+ long nWinItemWidth = it->mpWindow->GetSizePixel().Width();
+ if ( !mbScroll || (nWinItemWidth <= nWidthTotal) )
+ {
+ nCurWidth = nWinItemWidth;
+ bWindow = TRUE;
+ }
+ else
+ {
+ if ( it->mbEmptyBtn )
+ {
+ nCurWidth = 0;
+ }
+ }
+ }
+
+ // check for line break
+ if ( (nLineWidth+nCurWidth > nWidthTotal) && mbScroll )
+ bBreak = TRUE;
+ }
+ else if ( it->meType == TOOLBOXITEM_SEPARATOR )
+ nCurWidth = it->mnSepSize;
+ // treat breaks as separators, except when using old style toolbars (ie. no menu button)
+ else if ( (it->meType == TOOLBOXITEM_BREAK) && !IsMenuEnabled() )
+ bBreak = TRUE;
+
+ if ( bBreak )
+ {
+ nLines++;
+
+ // Gruppe auseinanderbrechen oder ganze Gruppe umbrechen?
+ if ( (it->meType == TOOLBOXITEM_BREAK) ||
+ (nLineStart == nGroupStart) )
+ {
+ if ( nLineWidth > nMaxLineWidth )
+ nMaxLineWidth = nLineWidth;
+
+ nLineWidth = 0;
+ nLineStart = it - mpData->m_aItems.begin();
+ nGroupStart = nLineStart;
+ it->mbBreak = TRUE;
+ bBreak = FALSE;
+ }
+ else
+ {
+ if ( nLastGroupLineWidth > nMaxLineWidth )
+ nMaxLineWidth = nLastGroupLineWidth;
+
+ // Wenn ganze Gruppe umgebrochen wird, diese auf
+ // Zeilenanfang setzen und wieder neu berechnen
+ nLineWidth = 0;
+ nLineStart = nGroupStart;
+ it = mpData->m_aItems.begin() + nGroupStart;
+ continue;
+ }
+ }
+ else
+ {
+ if( ImplIsFloatingMode() || !IsMenuEnabled() ) // no group breaking when being docked single-line
+ {
+ if ( (it->meType != TOOLBOXITEM_BUTTON) || bWindow )
+ {
+ // found separator or break
+ nLastGroupLineWidth = nLineWidth;
+ nGroupStart = it - mpData->m_aItems.begin();
+ if ( !bWindow )
+ nGroupStart++;
+ }
+ }
+ }
+
+ nLineWidth += nCurWidth;
+ }
+
+ ++it;
+ }
+
+
+ if ( pMaxLineWidth )
+ {
+ if ( nLineWidth > nMaxLineWidth )
+ nMaxLineWidth = nLineWidth;
+
+ if( ImplIsFloatingMode() && !ImplIsInPopupMode() )
+ {
+ // leave enough space to display buttons in the decoration
+ long aMinWidth = 2 * GetSettings().GetStyleSettings().GetFloatTitleHeight();
+ if( nMaxLineWidth < aMinWidth )
+ nMaxLineWidth = aMinWidth;
+ }
+
+ // Wegen Separatoren kann MaxLineWidth > Width werden, hat aber
+ // auf die Umbrueche keine Auswirkung
+ //if ( nMaxLineWidth > nWidth )
+ // nMaxLineWidth = nWidth;
+
+ *pMaxLineWidth = nMaxLineWidth;
+ }
+
+ return nLines;
+}
+
+// -----------------------------------------------------------------------
+namespace
+{
+ BOOL ImplFollowedByVisibleButton( std::vector< ImplToolItem >::iterator _aSeparator, std::vector< ImplToolItem >::iterator _aEnd )
+ {
+ std::vector< ImplToolItem >::iterator aLookup = _aSeparator;
+ while ( ++aLookup != _aEnd )
+ {
+ if ( aLookup->meType == TOOLBOXITEM_SEPARATOR )
+ return ImplFollowedByVisibleButton( aLookup, _aEnd );
+
+ if ( ( aLookup->meType == TOOLBOXITEM_BUTTON ) && aLookup->mbVisible )
+ return TRUE;
+ }
+ return FALSE;
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+Size ToolBox::ImplGetOptimalFloatingSize( FloatingSizeMode eMode )
+{
+ if( !ImplIsFloatingMode() )
+ return Size();
+
+ Size aCurrentSize( mnDX, mnDY );
+ Size aSize1( aCurrentSize );
+ Size aSize2( aCurrentSize );
+
+ // try to preserve current height
+ if( eMode == FSMODE_AUTO || eMode == FSMODE_FAVOURHEIGHT )
+ {
+ // calc number of floating lines for current window height
+ USHORT nFloatLinesHeight = ImplCalcLines( this, mnDY );
+ // calc window size according to this number
+ aSize1 = ImplCalcFloatSize( this, nFloatLinesHeight );
+
+ if( eMode == FSMODE_FAVOURHEIGHT || aCurrentSize == aSize1 )
+ return aSize1;
+ }
+
+ if( eMode == FSMODE_AUTO || eMode == FSMODE_FAVOURWIDTH )
+ {
+ // try to preserve current width
+ long nLineHeight = ( mnWinHeight > mnMaxItemHeight ) ? mnWinHeight : mnMaxItemHeight;
+ int nBorderX = 2*TB_BORDER_OFFSET1 + mnLeftBorder + mnRightBorder + 2*mnBorderX;
+ int nBorderY = 2*TB_BORDER_OFFSET2 + mnTopBorder + mnBottomBorder + 2*mnBorderY;
+ Size aSz( aCurrentSize );
+ long maxX;
+ USHORT nLines = ImplCalcBreaks( aSz.Width()-nBorderX, &maxX, mbHorz );
+
+ USHORT manyLines = 1000;
+ Size aMinimalFloatSize = ImplCalcFloatSize( this, manyLines );
+
+ aSz.Height() = nBorderY + nLineHeight * nLines;
+ // line space when more than one line
+ if ( mnWinStyle & WB_LINESPACING )
+ aSz.Height() += (nLines-1)*TB_LINESPACING;
+
+ aSz.Width() = nBorderX + maxX;
+
+ // avoid clipping of any items
+ if( aSz.Width() < aMinimalFloatSize.Width() )
+ aSize2 = ImplCalcFloatSize( this, nLines );
+ else
+ aSize2 = aSz;
+
+ if( eMode == FSMODE_FAVOURWIDTH || aCurrentSize == aSize2 )
+ return aSize2;
+ else
+ {
+ // set the size with the smallest delta as the current size
+ long dx1 = abs( mnDX - aSize1.Width() );
+ long dy1 = abs( mnDY - aSize1.Height() );
+
+ long dx2 = abs( mnDX - aSize2.Width() );
+ long dy2 = abs( mnDY - aSize2.Height() );
+
+ if( dx1*dy1 < dx2*dy2 )
+ aCurrentSize = aSize1;
+ else
+ aCurrentSize = aSize2;
+ }
+ }
+ return aCurrentSize;
+}
+
+
+void ToolBox::ImplFormat( BOOL bResize )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ // Muss ueberhaupt neu formatiert werden
+ if ( !mbFormat )
+ return;
+
+ mpData->ImplClearLayoutData();
+
+ // Positionen/Groessen berechnen
+ Rectangle aEmptyRect;
+ long nLineSize;
+ long nLeft;
+ long nRight;
+ long nTop;
+ long nBottom;
+ long nMax; // width of layoutarea in pixels
+ long nX;
+ long nY;
+ USHORT nFormatLine;
+ BOOL bMustFullPaint;
+ BOOL bLastSep;
+
+ std::vector< ImplToolItem >::iterator it;
+ std::vector< ImplToolItem >::iterator temp_it;
+
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ BOOL bIsInPopupMode = ImplIsInPopupMode();
+
+ // FloatSizeAry gegebenenfalls loeschen
+ if ( mpFloatSizeAry )
+ {
+ delete mpFloatSizeAry;
+ mpFloatSizeAry = NULL;
+ }
+
+ // compute border sizes
+ ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder, mnRightBorder, mnBottomBorder, this );
+
+ // update drag area (where the 'grip' will be placed)
+ Rectangle aOldDragRect;
+ if( pWrapper )
+ aOldDragRect = pWrapper->GetDragArea();
+ ImplUpdateDragArea( this );
+
+ if ( ImplCalcItem() )
+ bMustFullPaint = TRUE;
+ else
+ bMustFullPaint = FALSE;
+
+
+ // calculate new size during interactive resize or
+ // set computed size when formatting only
+ if ( ImplIsFloatingMode() )
+ {
+ if ( bResize )
+ mnFloatLines = ImplCalcLines( this, mnDY );
+ else
+ SetOutputSizePixel( ImplGetOptimalFloatingSize( FSMODE_AUTO ) );
+ }
+
+ // Horizontal
+ if ( mbHorz )
+ {
+ // nLineSize: height of a single line, will fit highest item
+ nLineSize = mnMaxItemHeight;
+
+ if ( mnWinHeight > mnMaxItemHeight )
+ nLineSize = mnWinHeight;
+
+ if ( mbScroll )
+ {
+ nMax = mnDX;
+ mnVisLines = ImplCalcLines( this, mnDY );
+ }
+ else
+ {
+ // layout over all lines
+ mnVisLines = mnLines;
+ nMax = TB_MAXNOSCROLL;
+ }
+
+ // add in all border offsets
+ // inner border as well as custom border (mnBorderX, mnBorderY)
+ if ( mnWinStyle & WB_BORDER )
+ {
+ nLeft = TB_BORDER_OFFSET1 + mnLeftBorder;
+ nTop = TB_BORDER_OFFSET2 + mnTopBorder;
+ nBottom = TB_BORDER_OFFSET1 + mnBottomBorder;
+ nMax -= nLeft + TB_BORDER_OFFSET1 + mnRightBorder;
+ }
+ else
+ {
+ nLeft = 0;
+ nTop = 0;
+ nBottom = 0;
+ }
+
+ nLeft += mnBorderX;
+ nTop += mnBorderY;
+ nBottom += mnBorderY;
+ nMax -= mnBorderX*2;
+
+ // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu)
+ // we have to center all items in the window height
+ if( IsMenuEnabled() && !ImplIsFloatingMode() )
+ {
+ long nWinHeight = mnDY - nTop - nBottom;
+ if( nWinHeight > nLineSize )
+ nLineSize = nWinHeight;
+ }
+ }
+ else
+ {
+ nLineSize = mnMaxItemWidth;
+
+ if ( mbScroll )
+ {
+ mnVisLines = ImplCalcLines( this, mnDX );
+ nMax = mnDY;
+ }
+ else
+ {
+ mnVisLines = mnLines;
+ nMax = TB_MAXNOSCROLL;
+ }
+
+ if ( mnWinStyle & WB_BORDER )
+ {
+ nTop = TB_BORDER_OFFSET1 + mnTopBorder;
+ nLeft = TB_BORDER_OFFSET2 + mnLeftBorder;
+ nRight = TB_BORDER_OFFSET2 + mnRightBorder;
+ nMax -= nTop + TB_BORDER_OFFSET1 + mnBottomBorder;
+ }
+ else
+ {
+ nLeft = 0;
+ nTop = 0;
+ nRight = 0;
+ }
+
+ nLeft += mnBorderX;
+ nRight+= mnBorderX;
+ nTop += mnBorderY;
+ nMax -= mnBorderY*2;
+
+ // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu)
+ // we have to center all items in the window height
+ if( !ImplIsFloatingMode() && IsMenuEnabled() )
+ {
+ long nWinWidth = mnDX - nLeft - nRight;
+ if( nWinWidth > nLineSize )
+ nLineSize = nWinWidth;
+ }
+ }
+
+ // no calculation if the window has no size (nMax=0)
+ // non scrolling toolboxes must be computed though
+ if ( (nMax <= 0) && mbScroll )
+ {
+ mnVisLines = 1;
+ mnCurLine = 1;
+ mnCurLines = 1;
+
+ it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ it->maRect = aEmptyRect;
+
+ // For items not visible, release resources only needed during
+ // painting the items (on Win98, for example, these are system-wide
+ // resources that are easily exhausted, so be nice):
+
+ /* !!!
+ it->maImage.ClearCaches();
+ it->maHighImage.ClearCaches();
+ */
+
+ ++it;
+ }
+
+ maLowerRect = aEmptyRect;
+ maUpperRect = aEmptyRect;
+ maNextToolRect = aEmptyRect;
+ }
+ else
+ {
+ // init start values
+ nX = nLeft; // top-left offset
+ nY = nTop;
+ nFormatLine = 1;
+ bLastSep = TRUE;
+
+ // save old scroll rectangles and reset them
+ Rectangle aOldLowerRect = maLowerRect;
+ Rectangle aOldUpperRect = maUpperRect;
+ Rectangle aOldNextToolRect = maNextToolRect;
+ Rectangle aOldMenubuttonRect = mpData->maMenubuttonItem.maRect;
+ maUpperRect = aEmptyRect;
+ maLowerRect = aEmptyRect;
+ maNextToolRect = aEmptyRect;
+ mpData->maMenubuttonItem.maRect = aEmptyRect;
+
+ // additional toolboxes require a toggle button (maNextToolRect)
+ if ( maNextToolBoxStr.Len() && mbScroll )
+ {
+ nMax -= TB_NEXT_SIZE-TB_NEXT_OFFSET;
+ if ( mbHorz )
+ {
+ maNextToolRect.Left() = nLeft+nMax;
+ maNextToolRect.Right() = maNextToolRect.Left()+TB_NEXT_SIZE-1;
+ maNextToolRect.Top() = nTop;
+ maNextToolRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1;
+ }
+ else
+ {
+ maNextToolRect.Top() = nTop+nMax;
+ maNextToolRect.Bottom() = maNextToolRect.Top()+TB_NEXT_SIZE-1;
+ maNextToolRect.Left() = nLeft;
+ maNextToolRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1;
+ }
+ }
+
+ // do we have any toolbox items at all ?
+ if ( !mpData->m_aItems.empty() || IsMenuEnabled() )
+ {
+ // compute line breaks and visible lines give the current window width (nMax)
+ // the break indicators will be stored within each item (it->mbBreak)
+ mnCurLines = ImplCalcBreaks( nMax, NULL, mbHorz );
+
+ // check for scrollbar buttons or dropdown menu
+ // (if a menu is enabled, this will be used to store clipped
+ // items and no scroll buttons will appear)
+ if ( (!ImplIsFloatingMode() && (mnCurLines > mnVisLines) && mbScroll ) ||
+ IsMenuEnabled() )
+ {
+ // compute linebreaks again, incorporating scrollbar buttons
+ if( !IsMenuEnabled() )
+ {
+ nMax -= TB_SPIN_SIZE+TB_SPIN_OFFSET;
+ mnCurLines = ImplCalcBreaks( nMax, NULL, mbHorz );
+ }
+
+ // compute scroll rectangles or menu button
+ if ( mbHorz )
+ {
+ if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
+ {
+ if( !ImplIsFloatingMode() )
+ {
+ mpData->maMenubuttonItem.maRect.Right() = mnDX - 2;
+ mpData->maMenubuttonItem.maRect.Top() = nTop;
+ mpData->maMenubuttonItem.maRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1;
+ }
+ else
+ {
+ mpData->maMenubuttonItem.maRect.Right() = mnDX - mnRightBorder-mnBorderX-TB_BORDER_OFFSET1-1;
+ mpData->maMenubuttonItem.maRect.Top() = nTop;
+ mpData->maMenubuttonItem.maRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1;
+ }
+ mpData->maMenubuttonItem.maRect.Left() = mpData->maMenubuttonItem.maRect.Right() - mpData->mnMenuButtonWidth;
+ }
+ else
+ {
+ maUpperRect.Left() = nLeft+nMax+TB_SPIN_OFFSET;
+ maUpperRect.Right() = maUpperRect.Left()+TB_SPIN_SIZE-1;
+ maUpperRect.Top() = nTop;
+ maLowerRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1;
+ maLowerRect.Left() = maUpperRect.Left();
+ maLowerRect.Right() = maUpperRect.Right();
+ maUpperRect.Bottom() = maUpperRect.Top() +
+ (maLowerRect.Bottom()-maUpperRect.Top())/2;
+ maLowerRect.Top() = maUpperRect.Bottom();
+ }
+ }
+ else
+ {
+ if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
+ {
+ if( !ImplIsFloatingMode() )
+ {
+ mpData->maMenubuttonItem.maRect.Bottom() = mnDY - 2;
+ mpData->maMenubuttonItem.maRect.Left() = nLeft;
+ mpData->maMenubuttonItem.maRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1;
+ }
+ else
+ {
+ mpData->maMenubuttonItem.maRect.Bottom() = mnDY - mnBottomBorder-mnBorderY-TB_BORDER_OFFSET1-1;
+ mpData->maMenubuttonItem.maRect.Left() = nLeft;
+ mpData->maMenubuttonItem.maRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1;
+ }
+ mpData->maMenubuttonItem.maRect.Top() = mpData->maMenubuttonItem.maRect.Bottom() - mpData->mnMenuButtonWidth;
+ }
+ else
+ {
+ maUpperRect.Top() = nTop+nMax+TB_SPIN_OFFSET;;
+ maUpperRect.Bottom() = maUpperRect.Top()+TB_SPIN_SIZE-1;
+ maUpperRect.Left() = nLeft;
+ maLowerRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1;
+ maLowerRect.Top() = maUpperRect.Top();
+ maLowerRect.Bottom() = maUpperRect.Bottom();
+ maUpperRect.Right() = maUpperRect.Left() +
+ (maLowerRect.Right()-maUpperRect.Left())/2;
+ maLowerRect.Left() = maUpperRect.Right();
+ }
+ }
+ }
+
+ // no scrolling when there is a "more"-menu
+ // anything will "fit" in a single line then
+ if( IsMenuEnabled() )
+ mnCurLines = 1;
+
+ // determine the currently visible line
+ if ( mnVisLines >= mnCurLines )
+ mnCurLine = 1;
+ else if ( mnCurLine+mnVisLines-1 > mnCurLines )
+ mnCurLine = mnCurLines - (mnVisLines-1);
+
+ it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ // hide double separators
+ if ( it->meType == TOOLBOXITEM_SEPARATOR )
+ {
+ it->mbVisible = FALSE;
+ if ( !bLastSep )
+ {
+ // check if any visible items have to appear behind it
+ temp_it = it+1;
+ while ( temp_it != mpData->m_aItems.end() )
+ {
+ if ( (temp_it->meType == TOOLBOXITEM_SEPARATOR) ||
+ ((temp_it->meType == TOOLBOXITEM_BUTTON) &&
+ temp_it->mbVisible) )
+ {
+ it->mbVisible = TRUE;
+ break;
+ }
+ ++temp_it;
+ }
+ }
+ bLastSep = TRUE;
+ }
+ else if ( it->mbVisible )
+ bLastSep = FALSE;
+
+ it->mbShowWindow = FALSE;
+
+ // check for line break and advance nX/nY accordingly
+ if ( it->mbBreak )
+ {
+ nFormatLine++;
+
+ // increment starting with the second line
+ if ( nFormatLine > mnCurLine )
+ {
+ if ( mbHorz )
+ {
+ nX = nLeft;
+ if ( mnWinStyle & WB_LINESPACING )
+ nY += nLineSize+TB_LINESPACING;
+ else
+ nY += nLineSize;
+ }
+ else
+ {
+ nY = nTop;
+ if ( mnWinStyle & WB_LINESPACING )
+ nX += nLineSize+TB_LINESPACING;
+ else
+ nX += nLineSize;
+ }
+ }
+ }
+
+ if ( !it->mbVisible || (nFormatLine < mnCurLine) ||
+ (nFormatLine > mnCurLine+mnVisLines-1) )
+ // item is not visible
+ it->maCalcRect = aEmptyRect;
+ else
+ {
+ // 1. determine current item width/height
+ // take window size and orientation into account, because this affects the size of item windows
+
+ Size aCurrentItemSize( it->GetSize( mbHorz, mbScroll, nMax, Size(mnMaxItemWidth, mnMaxItemHeight) ) );
+
+ // 2. position item rect and use size from step 1
+ // items will be centered horizontally (if mbHorz) or vertically
+ // advance nX and nY accordingly
+ if ( mbHorz )
+ {
+ it->maCalcRect.Left() = nX;
+ it->maCalcRect.Top() = nY+(nLineSize-aCurrentItemSize.Height())/2;
+ it->maCalcRect.Right() = nX+aCurrentItemSize.Width()-1;
+ it->maCalcRect.Bottom() = it->maCalcRect.Top()+aCurrentItemSize.Height()-1;
+ nX += aCurrentItemSize.Width();
+ }
+ else
+ {
+ it->maCalcRect.Left() = nX+(nLineSize-aCurrentItemSize.Width())/2;
+ it->maCalcRect.Top() = nY;
+ it->maCalcRect.Right() = it->maCalcRect.Left()+aCurrentItemSize.Width()-1;
+ it->maCalcRect.Bottom() = nY+aCurrentItemSize.Height()-1;
+ nY += aCurrentItemSize.Height();
+ }
+ }
+
+ // position window items into calculated item rect
+ if ( it->mpWindow )
+ {
+ if ( it->mbShowWindow )
+ {
+ Point aPos( it->maCalcRect.Left(), it->maCalcRect.Top() );
+ it->mpWindow->SetPosPixel( aPos );
+ if ( !mbCustomizeMode )
+ it->mpWindow->Show();
+ }
+ else
+ it->mpWindow->Hide();
+ }
+
+ ++it;
+ } // end of loop over all items
+ }
+ else
+ // we have no toolbox items
+ mnCurLines = 1;
+
+
+ if( IsMenuEnabled() && ImplIsFloatingMode() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
+ {
+ // custom menu will be the last button in floating mode
+ ImplToolItem &rIt = mpData->maMenubuttonItem;
+
+ if ( mbHorz )
+ {
+ rIt.maRect.Left() = nX+TB_MENUBUTTON_OFFSET;
+ rIt.maRect.Top() = nY;
+ rIt.maRect.Right() = rIt.maRect.Left() + mpData->mnMenuButtonWidth;
+ rIt.maRect.Bottom() = nY+nLineSize-1;
+ nX += rIt.maItemSize.Width();
+ }
+ else
+ {
+ rIt.maRect.Left() = nX;
+ rIt.maRect.Top() = nY+TB_MENUBUTTON_OFFSET;
+ rIt.maRect.Right() = nX+nLineSize-1;
+ rIt.maRect.Bottom() = rIt.maRect.Top() + mpData->mnMenuButtonWidth;
+ nY += rIt.maItemSize.Height();
+ }
+ }
+
+
+ // if toolbox visible trigger paint for changed regions
+ if ( IsVisible() && !mbFullPaint )
+ {
+ if ( bMustFullPaint )
+ {
+ maPaintRect = Rectangle( mnLeftBorder, mnTopBorder,
+ mnDX-mnRightBorder, mnDY-mnBottomBorder );
+ }
+ else
+ {
+ if ( aOldLowerRect != maLowerRect )
+ {
+ maPaintRect.Union( maLowerRect );
+ maPaintRect.Union( aOldLowerRect );
+ }
+ if ( aOldUpperRect != maUpperRect )
+ {
+ maPaintRect.Union( maUpperRect );
+ maPaintRect.Union( aOldUpperRect );
+ }
+ if ( aOldNextToolRect != maNextToolRect )
+ {
+ maPaintRect.Union( maNextToolRect );
+ maPaintRect.Union( aOldNextToolRect );
+ }
+ if ( aOldMenubuttonRect != mpData->maMenubuttonItem.maRect )
+ {
+ maPaintRect.Union( mpData->maMenubuttonItem.maRect );
+ maPaintRect.Union( aOldMenubuttonRect );
+ }
+ if ( pWrapper && aOldDragRect != pWrapper->GetDragArea() )
+ {
+ maPaintRect.Union( pWrapper->GetDragArea() );
+ maPaintRect.Union( aOldDragRect );
+ }
+
+ it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ if ( it->maRect != it->maCalcRect )
+ {
+ maPaintRect.Union( it->maRect );
+ maPaintRect.Union( it->maCalcRect );
+ }
+ ++it;
+ }
+ }
+
+ Invalidate( maPaintRect );
+ }
+
+ // store the new calculated item rects
+ maPaintRect = aEmptyRect;
+ Rectangle aVisibleRect(Point(0, 0), GetOutputSizePixel());
+ it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ it->maRect = it->maCalcRect;
+ if (!it->maRect.IsOver(aVisibleRect))
+ {
+ // For items not visible, release resources only needed during
+ // painting the items (on Win98, for example, these are system-
+ // wide resources that are easily exhausted, so be nice):
+
+ /* !!!
+ it->maImage.ClearCaches();
+ it->maHighImage.ClearCaches();
+ */
+ }
+ ++it;
+ }
+ }
+
+ // indicate formatting is done
+ mbFormat = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ToolBox, ImplDropdownLongClickHdl, ToolBox*, EMPTYARG )
+{
+ if( mnCurPos != TOOLBOX_ITEM_NOTFOUND &&
+ (mpData->m_aItems[ mnCurPos ].mnBits & TIB_DROPDOWN)
+ )
+ {
+ mpData->mbDropDownByKeyboard = FALSE;
+ GetDropdownClickHdl().Call( this );
+
+ // do not reset data if the dropdown handler opened a floating window
+ // see ImplFloatControl()
+ if( mpFloatWin == NULL )
+ {
+ // no floater was opened
+ Deactivate();
+ ImplDrawItem( mnCurPos, FALSE );
+
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ mnCurItemId = 0;
+ mnDownItemId = 0;
+ mnMouseClicks = 0;
+ mnMouseModifier = 0;
+ mnHighItemId = 0;
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ToolBox, ImplUpdateHdl, void*, EMPTYARG )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( mbFormat )
+ ImplFormat();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDrawMoreIndicator( ToolBox *pBox, const Rectangle& rRect, BOOL bSetColor, BOOL bRotate )
+{
+ Color aOldFillColor = pBox->GetFillColor();
+ Color aOldLineColor = pBox->GetLineColor();
+ pBox->SetLineColor();
+
+ if ( bSetColor )
+ {
+ if ( pBox->GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
+ pBox->SetFillColor( Color( COL_WHITE ) );
+ else
+ pBox->SetFillColor( Color( COL_BLACK ) );
+ }
+
+ if( !bRotate )
+ {
+ long width = 8;
+ long height = 5;
+ long x = rRect.Left() + (rRect.getWidth() - width)/2 + 1;
+ long y = rRect.Top() + (rRect.getHeight() - height)/2 + 1;
+ while( height >= 1)
+ {
+ pBox->DrawRect( Rectangle( x, y, x+1, y ) );
+ x+=4;
+ pBox->DrawRect( Rectangle( x, y, x+1, y ) );
+ x-=4;
+ y++;
+ if( height <= 3) x--;
+ else x++;
+ height--;
+ }
+ }
+ else
+ {
+ long width = 5;
+ long height = 8;
+ long x = rRect.Left() + (rRect.getWidth() - width)/2 + 1;
+ long y = rRect.Top() + (rRect.getHeight() - height)/2 + 1;
+ while( width >= 1)
+ {
+ pBox->DrawRect( Rectangle( x, y, x, y+1 ) );
+ y+=4;
+ pBox->DrawRect( Rectangle( x, y, x, y+1 ) );
+ y-=4;
+ x++;
+ if( width <= 3) y--;
+ else y++;
+ width--;
+ }
+ }
+
+ pBox->SetFillColor( aOldFillColor );
+ pBox->SetLineColor( aOldLineColor );
+}
+
+static void ImplDrawDropdownArrow( ToolBox *pBox, const Rectangle& rDropDownRect, BOOL bSetColor, BOOL bRotate )
+{
+ BOOL bLineColor = pBox->IsLineColor();
+ BOOL bFillColor = pBox->IsFillColor();
+ Color aOldFillColor = pBox->GetFillColor();
+ Color aOldLineColor = pBox->GetLineColor();
+ pBox->SetLineColor();
+
+ if ( bSetColor )
+ {
+ if ( pBox->GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
+ pBox->SetFillColor( Color( COL_WHITE ) );
+ else
+ pBox->SetFillColor( Color( COL_BLACK ) );
+ }
+
+ if( !bRotate )
+ {
+ long width = 5;
+ long height = 3;
+ long x = rDropDownRect.Left() + (rDropDownRect.getWidth() - width)/2;
+ long y = rDropDownRect.Top() + (rDropDownRect.getHeight() - height)/2;
+ while( width >= 1)
+ {
+ pBox->DrawRect( Rectangle( x, y, x+width-1, y ) );
+ y++; x++;
+ width -= 2;
+ }
+ }
+ else
+ {
+ long width = 3;
+ long height = 5;
+ long x = rDropDownRect.Left() + (rDropDownRect.getWidth() - width)/2;
+ long y = rDropDownRect.Top() + (rDropDownRect.getHeight() - height)/2;
+ while( height >= 1)
+ {
+ pBox->DrawRect( Rectangle( x, y, x, y+height-1 ) );
+ y++; x++;
+ height -= 2;
+ }
+ }
+
+ if( bFillColor )
+ pBox->SetFillColor( aOldFillColor );
+ else
+ pBox->SetFillColor();
+ if( bLineColor )
+ pBox->SetLineColor( aOldLineColor );
+ else
+ pBox->SetLineColor( );
+}
+
+void ToolBox::ImplDrawToolArrow( ToolBox* pBox, long nX, long nY, BOOL bBlack, BOOL bColTransform,
+ BOOL bLeft, BOOL bTop, long nSize )
+{
+ Color aOldFillColor = pBox->GetFillColor();
+ WindowAlign eAlign = pBox->meAlign;
+ long n = 0;
+ long nHalfSize;
+ if ( bLeft )
+ eAlign = WINDOWALIGN_RIGHT;
+ else if ( bTop )
+ eAlign = WINDOWALIGN_BOTTOM;
+
+ nHalfSize = nSize/2;
+
+ switch ( eAlign )
+ {
+ case WINDOWALIGN_LEFT:
+ if ( bBlack )
+ pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) );
+ while ( n <= nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+n, nY+n, nX+n, nY+nSize-n ) );
+ n++;
+ }
+ if ( bBlack )
+ {
+ pBox->SetFillColor( aOldFillColor );
+ n = 1;
+ while ( n < nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+n, nY+1+n, nX+n, nY+nSize-1-n ) );
+ n++;
+ }
+ }
+ break;
+ case WINDOWALIGN_TOP:
+ if ( bBlack )
+ pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) );
+ while ( n <= nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+n, nY+n, nX+nSize-n, nY+n ) );
+ n++;
+ }
+ if ( bBlack )
+ {
+ pBox->SetFillColor( aOldFillColor );
+ n = 1;
+ while ( n < nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+1+n, nY+n, nX+nSize-1-n, nY+n ) );
+ n++;
+ }
+ }
+ break;
+ case WINDOWALIGN_RIGHT:
+ if ( bBlack )
+ pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) );
+ while ( n <= nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+nHalfSize-n, nY+n, nX+nHalfSize-n, nY+nSize-n ) );
+ n++;
+ }
+ if ( bBlack )
+ {
+ pBox->SetFillColor( aOldFillColor );
+ n = 1;
+ while ( n < nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+nHalfSize-n, nY+1+n, nX+nHalfSize-n, nY+nSize-1-n ) );
+ n++;
+ }
+ }
+ break;
+ case WINDOWALIGN_BOTTOM:
+ if ( bBlack )
+ pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) );
+ while ( n <= nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+n, nY+nHalfSize-n, nX+nSize-n, nY+nHalfSize-n ) );
+ n++;
+ }
+ if ( bBlack )
+ {
+ pBox->SetFillColor( aOldFillColor );
+ n = 1;
+ while ( n < nHalfSize )
+ {
+ pBox->DrawRect( Rectangle( nX+1+n, nY+nHalfSize-n, nX+nSize-1-n, nY+nHalfSize-n ) );
+ n++;
+ }
+ }
+ break;
+ }
+}
+
+void ToolBox::SetToolArrowClipregion( ToolBox* pBox, long nX, long nY,
+ BOOL bLeft, BOOL bTop, long nSize )
+{
+ WindowAlign eAlign = pBox->meAlign;
+ long nHalfSize;
+ if ( bLeft )
+ eAlign = WINDOWALIGN_RIGHT;
+ else if ( bTop )
+ eAlign = WINDOWALIGN_BOTTOM;
+
+ nHalfSize = nSize/2;
+
+ Point p[6];
+
+ switch ( eAlign )
+ {
+ case WINDOWALIGN_LEFT:
+ p[0].X() = nX-1; p[0].Y() = nY-1;
+ p[1].X() = nX-1; p[1].Y() = nY+nSize+1;
+ p[2].X() = nX+1; p[2].Y() = nY+nSize+1;
+ p[3].X() = nX+nHalfSize+1; p[3].Y() = nY+nHalfSize+1;
+ p[4].X() = nX+nHalfSize+1; p[4].Y() = nY+nHalfSize-1;
+ p[5].X() = nX+1; p[5].Y() = nY-1;
+ break;
+ case WINDOWALIGN_TOP:
+ p[0].X() = nX-1; p[0].Y() = nY-1;
+ p[1].X() = nX-1; p[1].Y() = nY+1;
+ p[2].X() = nX+nHalfSize-1; p[2].Y() = nY+nHalfSize+1;
+ p[3].X() = nX+nHalfSize+1; p[3].Y() = nY+nHalfSize+1;
+ p[4].X() = nX+nSize+1; p[4].Y() = nY+1;
+ p[5].X() = nX+nSize+1; p[5].Y() = nY-1;
+ break;
+ case WINDOWALIGN_RIGHT:
+ p[0].X() = nX+nHalfSize-1; p[0].Y() = nY-1;
+ p[1].X() = nX-1; p[1].Y() = nY+nHalfSize-1;
+ p[2].X() = nX-1; p[2].Y() = nY+nHalfSize+1;
+ p[3].X() = nX+nHalfSize-1; p[3].Y() = nY+nSize+1;
+ p[4].X() = nX+nHalfSize+1; p[4].Y() = nY+nSize+1;
+ p[5].X() = nX+nHalfSize+1; p[5].Y() = nY-1;
+ break;
+ case WINDOWALIGN_BOTTOM:
+ p[0].X() = nX-1; p[0].Y() = nY+nHalfSize-1;
+ p[1].X() = nX-1; p[1].Y() = nY+nHalfSize+1;
+ p[2].X() = nX+nSize+1; p[2].Y() = nY+nHalfSize+1;
+ p[3].X() = nX+nSize+1; p[3].Y() = nY+nHalfSize-1;
+ p[4].X() = nX+nHalfSize+1; p[4].Y() = nY-1;
+ p[5].X() = nX+nHalfSize-1; p[5].Y() = nY-1;
+ break;
+ }
+ Polygon aPoly(6,p);
+ Region aRgn( aPoly );
+ pBox->SetClipRegion( aRgn );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplDrawMenubutton( ToolBox *pThis, BOOL bHighlight )
+{
+ if( !pThis->mpData->maMenubuttonItem.maRect.IsEmpty() )
+ {
+ // #i53937# paint menu button only if necessary
+ if( !(pThis->GetMenuType() & TOOLBOX_MENUTYPE_CUSTOMIZE) && !pThis->ImplHasClippedItems() )
+ return;
+
+ // execute pending paint requests
+ ImplCheckUpdate( pThis );
+
+ BOOL bFillColor = pThis->IsFillColor();
+ BOOL bLineColor = pThis->IsLineColor();
+ Color aOldFillCol = pThis->GetFillColor();
+ Color aOldLineCol = pThis->GetLineColor();
+ BOOL bNativeButtons = pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON );
+
+ Rectangle aInnerRect( pThis->mpData->maMenubuttonItem.maRect );
+ if( pThis->mpData->mnMenuButtonWidth > TB_MENUBUTTON_SIZE )
+ {
+ long nDiff = pThis->mpData->mnMenuButtonWidth - TB_MENUBUTTON_SIZE;
+ long nDiff1 = nDiff/2;
+ long nDiff2 = nDiff - nDiff1;
+ if( pThis->IsHorizontal() )
+ {
+ aInnerRect.Left() += nDiff1;
+ aInnerRect.Right() -= nDiff2;
+ }
+ else
+ {
+ aInnerRect.Top() += nDiff1;
+ aInnerRect.Bottom() -= nDiff2;
+ }
+ }
+
+ if( pThis->IsHorizontal() )
+ {
+ aInnerRect.nLeft+=2;
+ aInnerRect.nRight-=1;
+ aInnerRect.nTop+=1;
+ aInnerRect.nBottom-=1;
+ }
+ else
+ {
+ aInnerRect.nLeft+=1;
+ aInnerRect.nRight-=1;
+ aInnerRect.nTop+=2;
+ aInnerRect.nBottom-=1;
+ }
+
+ ImplErase( pThis, bNativeButtons ? pThis->mpData->maMenubuttonItem.maRect : aInnerRect, bHighlight );
+
+ if( bHighlight )
+ {
+ if( bNativeButtons )
+ ImplDrawButton( pThis, pThis->mpData->maMenubuttonItem.maRect, 2, FALSE, TRUE, FALSE );
+ else
+ pThis->DrawSelectionBackground( aInnerRect, 2, FALSE, FALSE, FALSE );
+ }
+ else
+ {
+ // improve visibility by using a dark gradient
+ Gradient g;
+ g.SetAngle( pThis->mbHorz ? 0 : 900 );
+ g.SetStyle( GRADIENT_LINEAR );
+
+ g.SetStartColor( pThis->GetSettings().GetStyleSettings().GetFaceColor() );
+ g.SetEndColor( pThis->GetSettings().GetStyleSettings().GetShadowColor() );
+
+ pThis->DrawGradient( aInnerRect, g );
+ }
+
+ Rectangle aRect( aInnerRect );
+ if( pThis->mbHorz )
+ aRect.Top() = aRect.Bottom() - aRect.getHeight()/3;
+ else
+ aRect.Left() = aRect.Right() - aRect.getWidth()/3;
+
+ if( pThis->mpData->maMenuType & TOOLBOX_MENUTYPE_CUSTOMIZE )
+ ImplDrawDropdownArrow( pThis, aRect, TRUE, !pThis->mbHorz );
+
+ if( pThis->ImplHasClippedItems() )
+ {
+ aRect = aInnerRect;
+ if( pThis->mbHorz )
+ aRect.Bottom() = aRect.Top() + aRect.getHeight()/3;
+ else
+ aRect.Right() = aRect.Left() + aRect.getWidth()/3;
+
+ ImplDrawMoreIndicator( pThis, aRect, TRUE, !pThis->mbHorz );
+ }
+
+ // store highlight state
+ pThis->mpData->mbMenubuttonSelected = bHighlight;
+
+ // restore colors
+ if( bFillColor )
+ pThis->SetFillColor( aOldFillCol );
+ else
+ pThis->SetFillColor();
+ if( bLineColor )
+ pThis->SetLineColor( aOldLineCol );
+ else
+ pThis->SetLineColor();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplDrawSpin( BOOL bUpperIn, BOOL bLowerIn )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ BOOL bTmpUpper;
+ BOOL bTmpLower;
+
+ if ( maUpperRect.IsEmpty() || maLowerRect.IsEmpty() )
+ return;
+
+ if ( mnCurLine > 1 )
+ bTmpUpper = TRUE;
+ else
+ bTmpUpper = FALSE;
+
+ if ( mnCurLine+mnVisLines-1 < mnCurLines )
+ bTmpLower = TRUE;
+ else
+ bTmpLower = FALSE;
+
+ if ( !IsEnabled() )
+ {
+ bTmpUpper = FALSE;
+ bTmpLower = FALSE;
+ }
+
+ ImplDrawSpinButton( this, maUpperRect, maLowerRect,
+ bUpperIn, bLowerIn, bTmpUpper, bTmpLower, !mbHorz );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplDrawNext( BOOL bIn )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( maNextToolRect.IsEmpty() )
+ return;
+
+ DecorationView aDecoView( this );
+
+ // Button malen
+ long nX = SMALLBUTTON_OFF_NORMAL_X;
+ long nY = SMALLBUTTON_OFF_NORMAL_Y;
+ USHORT nStyle = 0;
+ if ( bIn == 1 )
+ {
+ nStyle |= BUTTON_DRAW_PRESSED;
+ nX = SMALLBUTTON_OFF_PRESSED_X;
+ nY = SMALLBUTTON_OFF_PRESSED_Y;
+ }
+ aDecoView.DrawButton( maNextToolRect, nStyle );
+
+ // Inhalt ausgeben
+ BOOL bLeft = FALSE;
+ BOOL bTop = FALSE;
+ if ( mbHorz )
+ {
+ bLeft = TRUE;
+ nX += (maNextToolRect.GetWidth()-6)/2-4;
+ nY += (maNextToolRect.GetHeight()-6)/2-6;
+ }
+ else
+ {
+ bTop = TRUE;
+ nY += (maNextToolRect.GetHeight()-6)/2-4;
+ nX += (maNextToolRect.GetWidth()-6)/2-6;
+ }
+
+ nX += maNextToolRect.Left();
+ nY += maNextToolRect.Top();
+ SetLineColor();
+ SetFillColor( COL_LIGHTBLUE );
+ ImplDrawToolArrow( this, nX, nY, TRUE, FALSE, bLeft, bTop, 10 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDrawButton( ToolBox* pThis, const Rectangle &rRect, USHORT highlight, BOOL bChecked, BOOL bEnabled, BOOL bIsWindow )
+{
+ // draws toolbar button background either native or using a coloured selection
+ // if bIsWindow is TRUE, the corresponding item is a control and only a selection border will be drawn
+
+ BOOL bNativeOk = FALSE;
+ if( !bIsWindow && pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
+ {
+ ImplControlValue aControlValue;
+ ControlState nState = 0;
+
+ if ( highlight == 1 ) nState |= CTRL_STATE_PRESSED;
+ if ( highlight == 2 ) nState |= CTRL_STATE_ROLLOVER;
+ if ( bEnabled ) nState |= CTRL_STATE_ENABLED;
+
+ aControlValue.setTristateVal( bChecked ? BUTTONVALUE_ON : BUTTONVALUE_OFF );
+
+
+ bNativeOk = pThis->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON,
+ rRect, nState, aControlValue, rtl::OUString() );
+ }
+
+ if( !bNativeOk )
+ pThis->DrawSelectionBackground( rRect, bIsWindow ? 3 : highlight, bChecked, TRUE, bIsWindow, 2, NULL, NULL );
+}
+
+void ToolBox::ImplDrawItem( USHORT nPos, BOOL bHighlight, BOOL bPaint, BOOL bLayout )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( nPos >= mpData->m_aItems.size() )
+ return;
+
+ // execute pending paint requests
+ ImplCheckUpdate( this );
+
+ ImplDisableFlatButtons();
+
+ SetFillColor();
+
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+ MetricVector* pVector = bLayout ? &mpData->m_pLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpData->m_pLayoutData->m_aDisplayText : NULL;
+
+ // Falls Rechteck ausserhalb des sichbaren Bereichs liegt
+ if ( pItem->maRect.IsEmpty() )
+ return;
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ // no gradient background for items that have a popup open
+ BOOL bHasOpenPopup = (mpFloatWin != NULL) && (mnDownItemId==pItem->mnId);
+
+ BOOL bHighContrastWhite = FALSE;
+ // check the face color as highcontrast indicator
+ // because the toolbox itself might have a gradient
+ if( rStyleSettings.GetFaceColor() == Color( COL_WHITE ) )
+ bHighContrastWhite = TRUE;
+
+ // draw separators in flat style only
+ if ( !bLayout &&
+ (mnOutStyle & TOOLBOX_STYLE_FLAT) &&
+ (pItem->meType == TOOLBOXITEM_SEPARATOR) &&
+ nPos > 0
+ )
+ {
+ // no separator before or after windows or at breaks
+ ImplToolItem* pTempItem = &mpData->m_aItems[nPos-1];
+ if ( pTempItem && !pTempItem->mbShowWindow && nPos < mpData->m_aItems.size()-1 )
+ {
+ pTempItem = &mpData->m_aItems[nPos+1];
+ if ( !pTempItem->mbShowWindow && !pTempItem->mbBreak )
+ {
+ long nCenterPos, nSlim;
+ SetLineColor( rStyleSettings.GetSeparatorColor() );
+ if ( IsHorizontal() )
+ {
+ nSlim = (pItem->maRect.Bottom() - pItem->maRect.Top ()) / 4;
+ nCenterPos = pItem->maRect.Center().X();
+ DrawLine( Point( nCenterPos, pItem->maRect.Top() + nSlim ),
+ Point( nCenterPos, pItem->maRect.Bottom() - nSlim ) );
+ }
+ else
+ {
+ nSlim = (pItem->maRect.Right() - pItem->maRect.Left ()) / 4;
+ nCenterPos = pItem->maRect.Center().Y();
+ DrawLine( Point( pItem->maRect.Left() + nSlim, nCenterPos ),
+ Point( pItem->maRect.Right() - nSlim, nCenterPos ) );
+ }
+ }
+ }
+ }
+
+ // do nothing if item is no button or will be displayed as window
+ if ( (pItem->meType != TOOLBOXITEM_BUTTON) ||
+ (pItem->mbShowWindow && !mbCustomizeMode) )
+ return;
+
+ // we need a TBDragMananger to draw the configuration item
+ ImplTBDragMgr* pMgr;
+ if ( pItem->mnId == mnConfigItem )
+ {
+ pMgr = ImplGetTBDragMgr();
+ pMgr->HideDragRect();
+ }
+ else
+ pMgr = NULL;
+
+ // during configuration mode visible windows will be drawn in a special way
+ if ( mbCustomizeMode && pItem->mbShowWindow )
+ {
+ Font aOldFont = GetFont();
+ Color aOldTextColor = GetTextColor();
+
+ SetZoomedPointFont( rStyleSettings.GetAppFont() );
+ SetLineColor( Color( COL_BLACK ) );
+ SetFillColor( rStyleSettings.GetFieldColor() );
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ if( !bLayout )
+ DrawRect( pItem->maRect );
+
+ Size aSize( GetCtrlTextWidth( pItem->maText ), GetTextHeight() );
+ Point aPos( pItem->maRect.Left()+2, pItem->maRect.Top() );
+ aPos.Y() += (pItem->maRect.GetHeight()-aSize.Height())/2;
+ BOOL bClip;
+ if ( (aSize.Width() > pItem->maRect.GetWidth()-2) ||
+ (aSize.Height() > pItem->maRect.GetHeight()-2) )
+ {
+ bClip = TRUE;
+ Rectangle aTempRect( pItem->maRect.Left()+1, pItem->maRect.Top()+1,
+ pItem->maRect.Right()-1, pItem->maRect.Bottom()-1 );
+ Region aTempRegion( aTempRect );
+ SetClipRegion( aTempRegion );
+ }
+ else
+ bClip = FALSE;
+ if( bLayout )
+ {
+ mpData->m_pLayoutData->m_aLineIndices.push_back( mpData->m_pLayoutData->m_aDisplayText.Len() );
+ mpData->m_pLayoutData->m_aLineItemIds.push_back( pItem->mnId );
+ mpData->m_pLayoutData->m_aLineItemPositions.push_back( nPos );
+ }
+ DrawCtrlText( aPos, pItem->maText, 0, STRING_LEN, TEXT_DRAW_MNEMONIC, pVector, pDisplayText );
+ if ( bClip )
+ SetClipRegion();
+ SetFont( aOldFont );
+ SetTextColor( aOldTextColor );
+
+ // Gegebenenfalls noch Config-Frame zeichnen
+ if ( pMgr && !bLayout)
+ pMgr->UpdateDragRect();
+ return;
+ }
+
+ // draw button
+ Size aBtnSize = pItem->maRect.GetSize();
+ if( ImplGetSVData()->maNWFData.mbToolboxDropDownSeparate )
+ {
+ // separate button not for dropdown only where the whole button is painted
+ if ( pItem->mnBits & TIB_DROPDOWN &&
+ ((pItem->mnBits & TIB_DROPDOWNONLY) != TIB_DROPDOWNONLY) )
+ {
+ Rectangle aArrowRect = pItem->GetDropDownRect( mbHorz );
+ if( aArrowRect.Top() == pItem->maRect.Top() ) // dropdown arrow on right side
+ aBtnSize.Width() -= aArrowRect.GetWidth();
+ else // dropdown arrow on bottom side
+ aBtnSize.Height() -= aArrowRect.GetHeight();
+ }
+ }
+ Rectangle aButtonRect( pItem->maRect.TopLeft(), aBtnSize );
+ long nOffX = SMALLBUTTON_OFF_NORMAL_X;
+ long nOffY = SMALLBUTTON_OFF_NORMAL_Y;
+ long nImageOffX=0;
+ long nImageOffY=0;
+ long nTextOffX=0;
+ long nTextOffY=0;
+ USHORT nStyle = 0;
+
+ if ( pItem->meState == STATE_CHECK )
+ {
+ nStyle |= BUTTON_DRAW_CHECKED;
+ }
+ else if ( pItem->meState == STATE_DONTKNOW )
+ {
+ nStyle |= BUTTON_DRAW_DONTKNOW;
+ }
+ if ( bHighlight == 1 )
+ {
+ nStyle |= BUTTON_DRAW_PRESSED;
+ }
+
+ if ( mnOutStyle & TOOLBOX_STYLE_OUTBUTTON )
+ {
+ nOffX = OUTBUTTON_OFF_NORMAL_X;
+ nOffY = OUTBUTTON_OFF_NORMAL_Y;
+ if ( bHighlight )
+ {
+ nOffX++;
+ nOffY++;
+ }
+ }
+
+ if( ! bLayout )
+ {
+ if ( mnOutStyle & TOOLBOX_STYLE_FLAT )
+ {
+ if ( (pItem->meState != STATE_NOCHECK) || !bPaint )
+ {
+ ImplErase( this, pItem->maRect, bHighlight, bHasOpenPopup );
+ }
+ }
+ else
+ {
+ if ( mnOutStyle & TOOLBOX_STYLE_OUTBUTTON )
+ ImplDrawOutButton( this, aButtonRect, nStyle );
+ else
+ {
+ DecorationView aDecoView( this );
+ aDecoView.DrawButton( aButtonRect, nStyle );
+ }
+ }
+ }
+
+ nOffX += pItem->maRect.Left();
+ nOffY += pItem->maRect.Top();
+
+ // determine what has to be drawn on the button: image, text or both
+ BOOL bImage;
+ BOOL bText;
+ ButtonType tmpButtonType = determineButtonType( pItem, meButtonType ); // default to toolbox setting
+ pItem->DetermineButtonDrawStyle( tmpButtonType, bImage, bText );
+
+ // compute output values
+ long nBtnWidth = aBtnSize.Width()-SMALLBUTTON_HSIZE;
+ long nBtnHeight = aBtnSize.Height()-SMALLBUTTON_VSIZE;
+ Size aImageSize;
+ Size aTxtSize;
+
+ if ( bText )
+ {
+ aTxtSize.Width() = GetCtrlTextWidth( pItem->maText );
+ aTxtSize.Height() = GetTextHeight();
+ }
+
+ if ( bImage && ! bLayout )
+ {
+ const Image* pImage;
+ if ( bHighlight && (!(pItem->maHighImage)) == FALSE )
+ pImage = &(pItem->maHighImage);
+ else
+ pImage = &(pItem->maImage);
+
+ aImageSize = pImage->GetSizePixel();
+
+ // determine drawing flags
+ USHORT nImageStyle = 0;
+
+ if ( !pItem->mbEnabled || !IsEnabled() )
+ nImageStyle |= IMAGE_DRAW_DISABLE;
+
+ // #i35563# the dontknow state indicates different states at the same time
+ // which should not be rendered disabled but normal
+ //if ( pItem->meState == STATE_DONTKNOW )
+ // nImageStyle |= IMAGE_DRAW_DISABLE;
+
+ // draw the image
+ nImageOffX = nOffX;
+ nImageOffY = nOffY;
+ if ( (pItem->mnBits & (TIB_LEFT|TIB_DROPDOWN)) || bText )
+ {
+ // left align also to leave space for drop down arrow
+ // and when drawing text+image
+ // just center in y, except for vertical (ie rotated text)
+ if( mbHorz || !bText )
+ nImageOffY += (nBtnHeight-aImageSize.Height())/2;
+ }
+ else
+ {
+ nImageOffX += (nBtnWidth-aImageSize.Width())/2;
+ nImageOffY += (nBtnHeight-aImageSize.Height())/2;
+ }
+ if ( bHighlight || (pItem->meState == STATE_CHECK) )
+ {
+ if( bHasOpenPopup )
+ ImplDrawFloatwinBorder( pItem );
+ else
+ ImplDrawButton( this, aButtonRect, bHighlight, pItem->meState == STATE_CHECK, pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow ? TRUE : FALSE );
+
+ if( bHighlight )
+ {
+ if( bHighContrastWhite )
+ nImageStyle |= IMAGE_DRAW_COLORTRANSFORM;
+ }
+ }
+ DrawImage( Point( nImageOffX, nImageOffY ), *pImage, nImageStyle );
+ }
+
+ // draw the text
+ BOOL bRotate = FALSE;
+ if ( bText )
+ {
+ nTextOffX = nOffX;
+ nTextOffY = nOffY;
+
+ // rotate text when vertically docked
+ Font aOldFont = GetFont();
+ if( pItem->mbVisibleText && !ImplIsFloatingMode() &&
+ ((meAlign == WINDOWALIGN_LEFT) || (meAlign == WINDOWALIGN_RIGHT)) )
+ {
+ bRotate = TRUE;
+
+ Font aRotateFont = aOldFont;
+ /*
+ if ( meAlign == WINDOWALIGN_LEFT )
+ {
+ aRotateFont.SetOrientation( 900 );
+ nTextOffX += (nBtnWidth-aTxtSize.Height())/2;
+ nTextOffY += aTxtSize.Width();
+ nTextOffY += (nBtnHeight-aTxtSize.Width())/2;
+ }
+ else*/
+ {
+ aRotateFont.SetOrientation( 2700 );
+
+ // center horizontally
+ nTextOffX += aTxtSize.Height();
+ nTextOffX += (nBtnWidth-aTxtSize.Height())/2;
+
+ // add in image offset
+ if( bImage )
+ nTextOffY = nImageOffY + aImageSize.Height() + TB_IMAGETEXTOFFSET;
+ }
+
+ SetFont( aRotateFont );
+ }
+ else
+ {
+ // center vertically
+ nTextOffY += (nBtnHeight-aTxtSize.Height())/2;
+
+ // add in image offset
+ if( bImage )
+ nTextOffX = nImageOffX + aImageSize.Width() + TB_IMAGETEXTOFFSET;
+ //nTextOffX += TB_TEXTOFFSET/2;
+ }
+
+ // draw selection only if not already drawn during image output (see above)
+ if ( !bLayout && !bImage && (bHighlight || (pItem->meState == STATE_CHECK) ) )
+ {
+ if( bHasOpenPopup )
+ ImplDrawFloatwinBorder( pItem );
+ else
+ ImplDrawButton( this, pItem->maRect, bHighlight, pItem->meState == STATE_CHECK, pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow ? TRUE : FALSE );
+ }
+
+ USHORT nTextStyle = 0;
+ if ( !pItem->mbEnabled )
+ nTextStyle |= TEXT_DRAW_DISABLE;
+ if( bLayout )
+ {
+ mpData->m_pLayoutData->m_aLineIndices.push_back( mpData->m_pLayoutData->m_aDisplayText.Len() );
+ mpData->m_pLayoutData->m_aLineItemIds.push_back( pItem->mnId );
+ mpData->m_pLayoutData->m_aLineItemPositions.push_back( nPos );
+ }
+ DrawCtrlText( Point( nTextOffX, nTextOffY ), pItem->maText,
+ 0, STRING_LEN, nTextStyle, pVector, pDisplayText );
+ if ( bRotate )
+ SetFont( aOldFont );
+ }
+
+ if( bLayout )
+ return;
+
+ // paint optional drop down arrow
+ if ( pItem->mnBits & TIB_DROPDOWN )
+ {
+ Rectangle aDropDownRect( pItem->GetDropDownRect( mbHorz ) );
+ BOOL bSetColor = TRUE;
+ if ( !pItem->mbEnabled || !IsEnabled() )
+ {
+ bSetColor = FALSE;
+ SetFillColor( rStyleSettings.GetShadowColor() );
+ }
+
+ // dropdown only will be painted without inner border
+ if( (pItem->mnBits & TIB_DROPDOWNONLY) != TIB_DROPDOWNONLY )
+ {
+ ImplErase( this, aDropDownRect, bHighlight, bHasOpenPopup );
+
+ if( bHighlight || (pItem->meState == STATE_CHECK) )
+ {
+ if( bHasOpenPopup )
+ ImplDrawFloatwinBorder( pItem );
+ else
+ ImplDrawButton( this, aDropDownRect, bHighlight, pItem->meState == STATE_CHECK, pItem->mbEnabled && IsEnabled(), FALSE );
+ }
+ }
+ ImplDrawDropdownArrow( this, aDropDownRect, bSetColor, bRotate );
+ }
+
+ // Gegebenenfalls noch Config-Frame zeichnen
+ if ( pMgr )
+ pMgr->UpdateDragRect();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplStartCustomizeMode()
+{
+ mbCustomizeMode = TRUE;
+
+ mpData->ImplClearLayoutData();
+
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ if ( it->mbShowWindow )
+ {
+ it->mpWindow->Hide();
+
+ if ( !(it->maRect.IsEmpty()) )
+ Invalidate( it->maRect );
+ }
+
+ ++it;
+ }
+}
+
+void ToolBox::SetCustomizeMode( BOOL bSet )
+{
+ if ( bSet )
+ ImplStartCustomizeMode();
+ else
+ ImplEndCustomizeMode();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplEndCustomizeMode()
+{
+ mbCustomizeMode = FALSE;
+
+ mpData->ImplClearLayoutData();
+
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ if ( it->mbShowWindow )
+ {
+ if ( !(it->maRect.IsEmpty()) )
+ Invalidate( it->maRect );
+
+ it->mpWindow->Show();
+ }
+
+ ++it;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplDrawFloatwinBorder( ImplToolItem* pItem )
+{
+ if ( !pItem->maRect.IsEmpty() )
+ {
+ Rectangle aRect( mpFloatWin->ImplGetItemEdgeClipRect() );
+ aRect.SetPos( AbsoluteScreenToOutputPixel( aRect.TopLeft() ) );
+ SetLineColor( GetSettings().GetStyleSettings().GetShadowColor() );
+ Point p1, p2;
+
+ p1 = pItem->maRect.TopLeft();
+ p1.X()++;
+ p2 = pItem->maRect.TopRight();
+ p2.X()--;
+ DrawLine( p1, p2);
+ p1 = pItem->maRect.BottomLeft();
+ p1.X()++;
+ p2 = pItem->maRect.BottomRight();
+ p2.X()--;
+ DrawLine( p1, p2);
+
+ p1 = pItem->maRect.TopLeft();
+ p1.Y()++;
+ p2 = pItem->maRect.BottomLeft();
+ p2.Y()--;
+ DrawLine( p1, p2);
+ p1 = pItem->maRect.TopRight();
+ p1.Y()++;
+ p2 = pItem->maRect.BottomRight();
+ p2.Y()--;
+ DrawLine( p1, p2);
+
+ //DrawRect( pItem->maRect );
+ }
+}
+
+void ToolBox::ImplFloatControl( BOOL bStart, FloatingWindow* pFloatWindow )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( bStart )
+ {
+ mpFloatWin = pFloatWindow;
+
+ // redraw item, to trigger drawing of a special border
+ ImplDrawItem( mnCurPos, TRUE );
+
+ mbDrag = FALSE;
+ EndTracking();
+ ReleaseMouse();
+ }
+ else
+ {
+ mpFloatWin = NULL;
+
+ // if focus is still in this toolbox, then the floater was opened by keyboard
+ // draw current item with highlight and keep old state
+ BOOL bWasKeyboardActivate = mpData->mbDropDownByKeyboard;
+
+
+ if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
+ ImplDrawItem( mnCurPos, bWasKeyboardActivate ? 2 : 0 );
+ Deactivate();
+
+ if( !bWasKeyboardActivate )
+ {
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ mnCurItemId = 0;
+ mnHighItemId = 0;
+ }
+ mnDownItemId = 0;
+
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ShowLine( BOOL bNext )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ mbFormat = TRUE;
+
+ if ( mpData->mbPageScroll )
+ {
+ USHORT delta = mnVisLines;
+ if ( bNext )
+ {
+ mnCurLine = mnCurLine + delta;
+ if ( mnCurLine+mnVisLines-1 > mnCurLines )
+ mnCurLine = mnCurLines - mnVisLines+1;
+ }
+ else
+ {
+ if( mnCurLine >= delta+1 )
+ mnCurLine = mnCurLine - delta;
+ else
+ mnCurLine = 1;
+ }
+ }
+ else
+ {
+ if ( bNext )
+ mnCurLine++;
+ else
+ mnCurLine--;
+ }
+
+ ImplFormat();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::ImplHandleMouseMove( const MouseEvent& rMEvt, BOOL bRepeat )
+{
+ Point aMousePos = rMEvt.GetPosPixel();
+
+ // Ist ToolBox aktiv
+ if ( mbDrag && mnCurPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ // Befindet sich Maus ueber dem Item
+ ImplToolItem* pItem = &mpData->m_aItems[mnCurPos];
+ if ( pItem->maRect.IsInside( aMousePos ) )
+ {
+ if ( !mnCurItemId )
+ {
+ ImplDrawItem( mnCurPos, TRUE );
+ mnCurItemId = pItem->mnId;
+ Highlight();
+ }
+
+ if ( (pItem->mnBits & TIB_REPEAT) && bRepeat )
+ Select();
+ }
+ else
+ {
+ if ( mnCurItemId )
+ {
+ ImplDrawItem( mnCurPos );
+ mnCurItemId = 0;
+ ImplDrawItem( mnCurPos );
+ Highlight();
+ }
+ }
+
+ return TRUE;
+ }
+
+ if ( mbUpper )
+ {
+ BOOL bNewIn = maUpperRect.IsInside( aMousePos );
+ if ( bNewIn != mbIn )
+ {
+ mbIn = bNewIn;
+ ImplDrawSpin( mbIn, FALSE );
+ }
+ return TRUE;
+ }
+
+ if ( mbLower )
+ {
+ BOOL bNewIn = maLowerRect.IsInside( aMousePos );
+ if ( bNewIn != mbIn )
+ {
+ mbIn = bNewIn;
+ ImplDrawSpin( FALSE, mbIn );
+ }
+ return TRUE;
+ }
+
+ if ( mbNextTool )
+ {
+ BOOL bNewIn = maNextToolRect.IsInside( aMousePos );
+ if ( bNewIn != mbIn )
+ {
+ mbIn = bNewIn;
+ ImplDrawNext( mbIn );
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::ImplHandleMouseButtonUp( const MouseEvent& rMEvt, BOOL bCancel )
+{
+ ImplDisableFlatButtons();
+
+ // stop eventual running dropdown timer
+ if( mnCurPos < mpData->m_aItems.size() &&
+ (mpData->m_aItems[mnCurPos].mnBits & TIB_DROPDOWN ) )
+ {
+ mpData->maDropdownTimer.Stop();
+ }
+
+ if ( mbDrag || mbSelection )
+ {
+ // Hier die MouseDaten setzen, wenn Selection-Modus, da dann kein
+ // MouseButtonDown-Handler gerufen wird
+ if ( mbSelection )
+ {
+ mnMouseClicks = rMEvt.GetClicks();
+ mnMouseModifier = rMEvt.GetModifier();
+ }
+
+ Deactivate();
+
+ if ( mbDrag )
+ mbDrag = FALSE;
+ else
+ {
+ mbSelection = FALSE;
+ if ( mnCurPos == TOOLBOX_ITEM_NOTFOUND )
+ return TRUE;
+ }
+
+ // Wurde Maus ueber dem Item losgelassen
+ if( mnCurPos < mpData->m_aItems.size() )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[mnCurPos];
+ if ( pItem->maRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ mnCurItemId = pItem->mnId;
+ if ( !bCancel )
+ {
+ // Gegebenenfalls ein AutoCheck durchfuehren
+ if ( pItem->mnBits & TIB_AUTOCHECK )
+ {
+ if ( pItem->mnBits & TIB_RADIOCHECK )
+ {
+ if ( pItem->meState != STATE_CHECK )
+ SetItemState( pItem->mnId, STATE_CHECK );
+ }
+ else
+ {
+ if ( pItem->meState != STATE_CHECK )
+ pItem->meState = STATE_CHECK;
+ else
+ pItem->meState = STATE_NOCHECK;
+ }
+ }
+
+ // Select nicht bei Repeat ausloesen, da dies schon im
+ // MouseButtonDown ausgeloest wurde
+ if ( !(pItem->mnBits & TIB_REPEAT) )
+ {
+ // Gegen zerstoeren im Select-Handler sichern
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ Select();
+ if ( aDelData.IsDelete() )
+ return TRUE;
+ ImplRemoveDel( &aDelData );
+ }
+ }
+
+ {
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ // Items nicht geloescht, im Select-Handler
+ if ( mnCurItemId )
+ {
+ BOOL bHighlight;
+ if ( (mnCurItemId == mnHighItemId) && (mnOutStyle & TOOLBOX_STYLE_FLAT) )
+ bHighlight = 2;
+ else
+ bHighlight = FALSE;
+ // Get current pos for the case that items are inserted/removed
+ // in the toolBox
+ mnCurPos = GetItemPos( mnCurItemId );
+ if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplDrawItem( mnCurPos, bHighlight );
+ Flush();
+ }
+ }
+ }
+ }
+
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ mnCurItemId = 0;
+ mnDownItemId = 0;
+ mnMouseClicks = 0;
+ mnMouseModifier = 0;
+ return TRUE;
+ }
+ else if ( mbUpper || mbLower )
+ {
+ if ( mbIn )
+ ShowLine( !mbUpper );
+ mbUpper = FALSE;
+ mbLower = FALSE;
+ mbIn = FALSE;
+ ImplDrawSpin( FALSE, FALSE );
+ return TRUE;
+ }
+ else if ( mbNextTool )
+ {
+ mbNextTool = FALSE;
+ mbIn = FALSE;
+ ImplDrawNext( FALSE );
+ NextToolBox();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::MouseMove( const MouseEvent& rMEvt )
+{
+ // pressing a modifier generates synthetic mouse moves
+ // ignore it if keyboard selection is acive
+ if( HasFocus() && ( rMEvt.GetMode() & MOUSE_MODIFIERCHANGED ) )
+ return;
+
+ if ( ImplHandleMouseMove( rMEvt ) )
+ return;
+
+ ImplDisableFlatButtons();
+
+ Point aMousePos = rMEvt.GetPosPixel();
+
+ // only highlight when the focus is not inside a child window of a toolbox
+ // eg, in a edit control
+ // and do not hilight when focus is in a different toolbox
+ BOOL bDrawHotSpot = TRUE;
+ Window *pWin = Application::GetFocusWindow();
+ if( pWin && pWin->ImplGetWindowImpl()->mbToolBox && pWin != this )
+ bDrawHotSpot = FALSE;
+ /*
+ else
+ if( pWin && !pWin->ImplGetWindowImpl()->mbToolBox )
+ while( pWin )
+ {
+ pWin = pWin->GetParent();
+ if( pWin && pWin->ImplGetWindowImpl()->mbToolBox )
+ {
+ bDrawHotSpot = FALSE;
+ break;
+ }
+ }
+ */
+
+ if ( mbSelection && bDrawHotSpot )
+ {
+ USHORT i = 0;
+ USHORT nNewPos = TOOLBOX_ITEM_NOTFOUND;
+
+ // Item suchen, das geklickt wurde
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ // Wenn Mausposition in diesem Item vorhanden, kann die
+ // Suche abgebrochen werden
+ if ( it->maRect.IsInside( aMousePos ) )
+ {
+ // Wenn es ein Button ist, dann wird er selektiert
+ if ( it->meType == TOOLBOXITEM_BUTTON )
+ {
+ // Wenn er disablet ist, findet keine Aenderung
+ // statt
+ if ( !it->mbEnabled || it->mbShowWindow )
+ nNewPos = mnCurPos;
+ else
+ nNewPos = i;
+ }
+
+ break;
+ }
+
+ i++;
+ ++it;
+ }
+
+ // was a new entery selected ?
+ // don't change selection if keyboard selection is active and
+ // mouse leaves the toolbox
+ if ( nNewPos != mnCurPos && !( HasFocus() && nNewPos == TOOLBOX_ITEM_NOTFOUND ) )
+ {
+ if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplDrawItem( mnCurPos );
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( mnCurPos ) );
+ }
+
+ mnCurPos = nNewPos;
+ if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ mnCurItemId = mnHighItemId = it->mnId;
+ ImplDrawItem( mnCurPos, 2 /*TRUE*/ ); // always use shadow effect (2)
+ }
+ else
+ mnCurItemId = mnHighItemId = 0;
+
+ Highlight();
+ }
+ return;
+ }
+
+ if ( mbDragging )
+ {
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ pMgr->Dragging( aMousePos );
+ return;
+ }
+
+ PointerStyle eStyle = POINTER_ARROW;
+
+ // change mouse cursor over drag area
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper && pWrapper->GetDragArea().IsInside( rMEvt.GetPosPixel() ) )
+ eStyle = POINTER_MOVE;
+
+ if ( (mnWinStyle & TB_WBLINESIZING) == TB_WBLINESIZING )
+ {
+ if ( rMEvt.GetMode() & MOUSE_SIMPLEMOVE )
+ {
+ USHORT nLinePtr = ImplTestLineSize( this, rMEvt.GetPosPixel() );
+ if ( nLinePtr & DOCK_LINEHSIZE )
+ {
+ if ( meAlign == WINDOWALIGN_LEFT )
+ eStyle = POINTER_WINDOW_ESIZE;
+ else
+ eStyle = POINTER_WINDOW_WSIZE;
+ }
+ else if ( nLinePtr & DOCK_LINEVSIZE )
+ {
+ if ( meAlign == WINDOWALIGN_TOP )
+ eStyle = POINTER_WINDOW_SSIZE;
+ else
+ eStyle = POINTER_WINDOW_NSIZE;
+ }
+ }
+ }
+
+ if ( (eStyle == POINTER_ARROW) && mbCustomizeMode )
+ {
+ // Item suchen, das geklickt wurde
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ // Wenn es ein Customize-Window ist, gegebenenfalls den
+ // Resize-Pointer anzeigen
+ if ( it->mbShowWindow )
+ {
+ if ( it->maRect.IsInside( aMousePos ) )
+ {
+ if ( it->maRect.Right()-TB_RESIZE_OFFSET <= aMousePos.X() )
+ eStyle = POINTER_HSIZEBAR;
+ break;
+ }
+ }
+
+ ++it;
+ }
+ }
+
+ if ( bDrawHotSpot && ( ((eStyle == POINTER_ARROW) && (mnOutStyle & TOOLBOX_STYLE_HANDPOINTER)) ||
+ (mnOutStyle & TOOLBOX_STYLE_FLAT) || !mnOutStyle ) )
+ {
+ BOOL bClearHigh = TRUE;
+ if ( !rMEvt.IsLeaveWindow() && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
+ {
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ if ( it->maRect.IsInside( aMousePos ) )
+ {
+ if ( (it->meType == TOOLBOXITEM_BUTTON) && it->mbEnabled )
+ {
+ if ( !mnOutStyle || (mnOutStyle & TOOLBOX_STYLE_FLAT) )
+ {
+ bClearHigh = FALSE;
+ if ( mnHighItemId != it->mnId )
+ {
+ USHORT nTempPos = sal::static_int_cast<USHORT>(it - mpData->m_aItems.begin());
+ if ( mnHighItemId )
+ {
+ ImplHideFocus();
+ USHORT nPos = GetItemPos( mnHighItemId );
+ ImplDrawItem( nPos );
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nPos ) );
+ }
+ if ( mpData->mbMenubuttonSelected )
+ {
+ // remove highlight from menubutton
+ ImplDrawMenubutton( this, FALSE );
+ }
+ mnHighItemId = it->mnId;
+ ImplDrawItem( nTempPos, 2 );
+ ImplShowFocus();
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT );
+ }
+ }
+ if ( mnOutStyle & TOOLBOX_STYLE_HANDPOINTER )
+ eStyle = POINTER_REFHAND;
+ }
+ break;
+ }
+
+ ++it;
+ }
+ }
+
+ // only clear highlight when focus is not in toolbar
+ BOOL bMenuButtonHit = mpData->maMenubuttonItem.maRect.IsInside( aMousePos );
+ if ( bClearHigh || bMenuButtonHit )
+ {
+ if ( !bMenuButtonHit && mpData->mbMenubuttonSelected )
+ {
+ // remove highlight from menubutton
+ ImplDrawMenubutton( this, FALSE );
+ }
+
+ if( mnHighItemId )
+ {
+ USHORT nClearPos = GetItemPos( mnHighItemId );
+ if ( nClearPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplDrawItem( nClearPos, (nClearPos == mnCurPos) ? TRUE : FALSE );
+ if( nClearPos != mnCurPos )
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nClearPos ) );
+ }
+ ImplHideFocus();
+ mnHighItemId = 0;
+ }
+
+ if( bMenuButtonHit )
+ {
+ ImplDrawMenubutton( this, TRUE );
+ }
+ }
+ }
+
+ if ( meLastStyle != eStyle )
+ {
+ meLastStyle = eStyle;
+ Pointer aPtr( eStyle );
+ SetPointer( aPtr );
+ }
+
+ DockingWindow::MouseMove( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ // Nur bei linker Maustaste ToolBox ausloesen und wenn wir uns nicht
+ // noch in der normalen Bearbeitung befinden
+ if ( rMEvt.IsLeft() && !mbDrag && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
+ {
+ // Activate schon hier rufen, da gegebenenfalls noch Items
+ // ausgetauscht werden
+ Activate();
+
+ // ToolBox hier updaten, damit der Anwender weiss, was Sache ist
+ if ( mbFormat )
+ {
+ ImplFormat();
+ Update();
+ }
+
+ Point aMousePos = rMEvt.GetPosPixel();
+ USHORT i = 0;
+ USHORT nNewPos = TOOLBOX_ITEM_NOTFOUND;
+
+ // Item suchen, das geklickt wurde
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ // Ist es dieses Item
+ if ( it->maRect.IsInside( aMousePos ) )
+ {
+ // Ist es ein Separator oder ist das Item disabled,
+ // dann mache nichts
+ if ( (it->meType == TOOLBOXITEM_BUTTON) &&
+ (!it->mbShowWindow || mbCustomizeMode) )
+ nNewPos = i;
+
+ break;
+ }
+
+ i++;
+ ++it;
+ }
+
+ // Item gefunden
+ if ( nNewPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ if ( mbCustomize )
+ {
+ if ( rMEvt.IsMod2() || mbCustomizeMode )
+ {
+ Deactivate();
+
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ Rectangle aItemRect = GetItemRect( it->mnId );
+ mnConfigItem = it->mnId;
+
+ BOOL bResizeItem;
+ if ( mbCustomizeMode && it->mbShowWindow &&
+ (it->maRect.Right()-TB_RESIZE_OFFSET <= aMousePos.X()) )
+ bResizeItem = TRUE;
+ else
+ bResizeItem = FALSE;
+ pMgr->StartDragging( this, aMousePos, aItemRect, 0, bResizeItem );
+ return;
+ }
+ }
+
+ if ( !it->mbEnabled )
+ {
+ Deactivate();
+ return;
+ }
+
+
+ // Aktuelle Daten setzen
+ USHORT nTrackFlags = 0;
+ mnCurPos = i;
+ mnCurItemId = it->mnId;
+ mnDownItemId = mnCurItemId;
+ mnMouseClicks = rMEvt.GetClicks();
+ mnMouseModifier = rMEvt.GetModifier();
+ if ( it->mnBits & TIB_REPEAT )
+ nTrackFlags |= STARTTRACK_BUTTONREPEAT;
+
+
+ if ( mbSelection )
+ {
+ ImplDrawItem( mnCurPos, TRUE );
+ Highlight();
+ }
+ else
+ {
+ // Hier schon bDrag setzen, da in EndSelection ausgewertet wird
+ mbDrag = TRUE;
+
+ // Bei Doppelklick nur den Handler rufen, aber bevor der
+ // Button gehiltet wird, da evt. in diesem Handler der
+ // Drag-Vorgang abgebrochen wird
+ if ( rMEvt.GetClicks() == 2 )
+ DoubleClick();
+
+
+ if ( mbDrag )
+ {
+ ImplDrawItem( mnCurPos, TRUE );
+ Highlight();
+ }
+
+ // was dropdown arrow pressed
+ if( (it->mnBits & TIB_DROPDOWN) )
+ {
+ if( ( (it->mnBits & TIB_DROPDOWNONLY) == TIB_DROPDOWNONLY) || it->GetDropDownRect( mbHorz ).IsInside( aMousePos ))
+ {
+ // dropdownonly always triggers the dropdown handler, over the whole button area
+
+ // the drop down arrow should not trigger the item action
+ mpData->mbDropDownByKeyboard = FALSE;
+ GetDropdownClickHdl().Call( this );
+
+ // do not reset data if the dropdown handler opened a floating window
+ // see ImplFloatControl()
+ if( mpFloatWin == NULL )
+ {
+ // no floater was opened
+ Deactivate();
+ ImplDrawItem( mnCurPos, FALSE );
+
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ mnCurItemId = 0;
+ mnDownItemId = 0;
+ mnMouseClicks = 0;
+ mnMouseModifier = 0;
+ mnHighItemId = 0;
+ }
+ return;
+ }
+ else // activate long click timer
+ mpData->maDropdownTimer.Start();
+ }
+
+
+ // Click-Handler aufrufen
+ if ( rMEvt.GetClicks() != 2 )
+ Click();
+
+ // Bei Repeat auch den Select-Handler rufen
+ if ( nTrackFlags & STARTTRACK_BUTTONREPEAT )
+ Select();
+
+ // Wenn die Aktion nicht im Click-Handler abgebrochen wurde
+ if ( mbDrag )
+ StartTracking( nTrackFlags );
+ }
+
+ // Wenn Maus ueber einem Item gedrueckt wurde, koennen wir
+ // die Bearbeitung abbrechen
+ return;
+ }
+
+ Deactivate();
+
+ // menu button hit ?
+ if( mpData->maMenubuttonItem.maRect.IsInside( aMousePos ) )
+ {
+ ExecuteCustomMenu();
+ return;
+ }
+
+
+ // Gegebenenfalls noch Scroll- und Next-Buttons ueberpruefen
+ if ( maUpperRect.IsInside( aMousePos ) )
+ {
+ if ( mnCurLine > 1 )
+ {
+ StartTracking();
+ mbUpper = TRUE;
+ mbIn = TRUE;
+ ImplDrawSpin( TRUE, FALSE );
+ }
+ return;
+ }
+ if ( maLowerRect.IsInside( aMousePos ) )
+ {
+ if ( mnCurLine+mnVisLines-1 < mnCurLines )
+ {
+ StartTracking();
+ mbLower = TRUE;
+ mbIn = TRUE;
+ ImplDrawSpin( FALSE, TRUE );
+ }
+ return;
+ }
+ if ( maNextToolRect.IsInside( aMousePos ) )
+ {
+ StartTracking();
+ mbNextTool = TRUE;
+ mbIn = TRUE;
+ ImplDrawNext( TRUE );
+ return;
+ }
+
+ // Linesizing testen
+ if ( (mnWinStyle & TB_WBLINESIZING) == TB_WBLINESIZING )
+ {
+ USHORT nLineMode = ImplTestLineSize( this, aMousePos );
+ if ( nLineMode )
+ {
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+
+ // Handler rufen, damit die Dock-Rectangles gesetzt werden
+ // koenen
+ StartDocking();
+
+ Point aPos = GetParent()->OutputToScreenPixel( GetPosPixel() );
+ Size aSize = GetSizePixel();
+ aPos = ScreenToOutputPixel( aPos );
+
+ // Dragging starten
+ pMgr->StartDragging( this, aMousePos, Rectangle( aPos, aSize ),
+ nLineMode, FALSE );
+ return;
+ }
+ }
+
+ // Kein Item, dann nur Click oder DoubleClick
+ if ( rMEvt.GetClicks() == 2 )
+ DoubleClick();
+ else
+ Click();
+ }
+
+ if ( !mbDrag && !mbSelection && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
+ DockingWindow::MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ if ( ImplHandleMouseButtonUp( rMEvt ) )
+ return;
+
+ if ( mbDragging && (rMEvt.IsLeft() || mbCommandDrag) )
+ {
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ pMgr->EndDragging();
+ return;
+ }
+ mbCommandDrag = FALSE;
+
+ DockingWindow::MouseButtonUp( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Tracking( const TrackingEvent& rTEvt )
+{
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+ if ( rTEvt.IsTrackingEnded() )
+ ImplHandleMouseButtonUp( rTEvt.GetMouseEvent(), rTEvt.IsTrackingCanceled() );
+ else
+ ImplHandleMouseMove( rTEvt.GetMouseEvent(), rTEvt.IsTrackingRepeat() );
+
+ if ( aDelData.IsDelete() )
+ // toolbox was deleted
+ return;
+ ImplRemoveDel( &aDelData );
+ DockingWindow::Tracking( rTEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Paint( const Rectangle& rPaintRect )
+{
+ if( mpData->mbIsPaintLocked )
+ return;
+ if ( rPaintRect == Rectangle( 0, 0, mnDX-1, mnDY-1 ) )
+ mbFullPaint = TRUE;
+ ImplFormat();
+ mbFullPaint = FALSE;
+
+
+ ImplDrawBackground( this, rPaintRect );
+
+ if ( (mnWinStyle & WB_BORDER) && !ImplIsFloatingMode() )
+ ImplDrawBorder( this );
+
+ if( !ImplIsFloatingMode() )
+ ImplDrawGrip( this );
+
+ ImplDrawMenubutton( this, mpData->mbMenubuttonSelected );
+
+ // SpinButtons zeichnen
+ if ( mnWinStyle & WB_SCROLL )
+ {
+ if ( mnCurLines > mnLines )
+ ImplDrawSpin( FALSE, FALSE );
+ }
+
+ // NextButton zeichnen
+ ImplDrawNext( FALSE );
+
+ // Buttons zeichnen
+ USHORT nHighPos;
+ if ( mnHighItemId )
+ nHighPos = GetItemPos( mnHighItemId );
+ else
+ nHighPos = TOOLBOX_ITEM_NOTFOUND;
+
+ USHORT nCount = (USHORT)mpData->m_aItems.size();
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[i];
+
+ // Nur malen, wenn Rechteck im PaintRectangle liegt
+ if ( !pItem->maRect.IsEmpty() && rPaintRect.IsOver( pItem->maRect ) )
+ {
+ BOOL bHighlight = FALSE;
+ if ( i == mnCurPos )
+ bHighlight = 1;
+ else if ( i == nHighPos )
+ bHighlight = 2;
+ ImplDrawItem( i, bHighlight );
+ }
+ }
+ ImplShowFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Move()
+{
+ DockingWindow::Move();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Resize()
+{
+ Size aSize = GetOutputSizePixel();
+ // #i31422# some WindowManagers send (0,0) sizes when
+ // switching virtual desktops - ignore this and avoid reformatting
+ if( !aSize.Width() && !aSize.Height() )
+ return;
+
+ long nOldDX = mnDX;
+ long nOldDY = mnDY;
+ mnDX = aSize.Width();
+ mnDY = aSize.Height();
+
+ mnLastResizeDY = 0;
+
+ // invalidate everything to have gradient backgrounds properly drawn
+ Invalidate();
+
+ // Evt. neu formatieren oder neu painten
+ if ( mbScroll )
+ {
+ if ( !mbFormat )
+ {
+ mbFormat = TRUE;
+ if( IsReallyVisible() )
+ ImplFormat( TRUE );
+ }
+ }
+
+ // Border muss neu ausgegeben werden
+ if ( mnWinStyle & WB_BORDER )
+ {
+ // Da wir sonst beim Paint denken, das alles neu gepaintet wird
+ if ( mbFormat && IsReallyVisible() )
+ Invalidate();
+ else
+ {
+ if ( mnRightBorder )
+ {
+ if ( nOldDX > mnDX )
+ Invalidate( Rectangle( mnDX-mnRightBorder-1, 0, mnDX, mnDY ) );
+ else
+ Invalidate( Rectangle( nOldDX-mnRightBorder-1, 0, nOldDX, nOldDY ) );
+ }
+
+ if ( mnBottomBorder )
+ {
+ if ( nOldDY > mnDY )
+ Invalidate( Rectangle( 0, mnDY-mnBottomBorder-1, mnDX, mnDY ) );
+ else
+ Invalidate( Rectangle( 0, nOldDY-mnBottomBorder-1, nOldDX, nOldDY ) );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+const XubString& ToolBox::ImplGetHelpText( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ {
+ if ( !pItem->maHelpText.Len() && ( pItem->mnHelpId || pItem->maCommandStr.Len() ))
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if ( pItem->maCommandStr.Len() )
+ pItem->maHelpText = pHelp->GetHelpText( pItem->maCommandStr, this );
+ if ( !pItem->maHelpText.Len() && pItem->mnHelpId )
+ pItem->maHelpText = pHelp->GetHelpText( pItem->mnHelpId, this );
+ }
+ }
+
+ return pItem->maHelpText;
+ }
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::RequestHelp( const HelpEvent& rHEvt )
+{
+ USHORT nItemId;
+ Point aHelpPos;
+
+ if( !rHEvt.KeyboardActivated() )
+ {
+ nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
+ aHelpPos = rHEvt.GetMousePosPixel();
+ }
+ else
+ {
+ if( !mnHighItemId )
+ return;
+ else
+ nItemId = mnHighItemId;
+ Rectangle aRect( GetItemRect( nItemId ) );
+ if( aRect.IsEmpty() )
+ return;
+ else
+ aHelpPos = OutputToScreenPixel( aRect.Center() );
+ }
+
+ if ( nItemId )
+ {
+ if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) )
+ {
+ // Rechteck ermitteln
+ Rectangle aTempRect = GetItemRect( nItemId );
+ Point aPt = OutputToScreenPixel( aTempRect.TopLeft() );
+ aTempRect.Left() = aPt.X();
+ aTempRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aTempRect.BottomRight() );
+ aTempRect.Right() = aPt.X();
+ aTempRect.Bottom() = aPt.Y();
+
+ // Text ermitteln und anzeigen
+ XubString aStr = GetQuickHelpText( nItemId );
+ const XubString& rHelpStr = GetHelpText( nItemId );
+ if ( !aStr.Len() )
+ aStr = MnemonicGenerator::EraseAllMnemonicChars( GetItemText( nItemId ) );
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ {
+ if ( rHelpStr.Len() )
+ aStr = rHelpStr;
+ Help::ShowBalloon( this, aHelpPos, aTempRect, aStr );
+ }
+ else
+ Help::ShowQuickHelp( this, aTempRect, aStr, rHelpStr, QUICKHELP_CTRLTEXT );
+ return;
+ }
+ else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
+ {
+ String aCommand = GetItemCommand( nItemId );
+ ULONG nHelpId = GetHelpId( nItemId );
+
+ if ( aCommand.Len() || nHelpId )
+ {
+ // Wenn eine Hilfe existiert, dann ausloesen
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if ( aCommand.Len() )
+ pHelp->Start( aCommand, this );
+ else if ( nHelpId )
+ pHelp->Start( nHelpId, this );
+ }
+ return;
+ }
+ }
+ }
+ else if ( maNextToolRect.IsInside( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ) )
+ {
+ if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) )
+ {
+ // Rechteck ermitteln
+ Rectangle aTempRect = maNextToolRect;
+ Point aPt = OutputToScreenPixel( aTempRect.TopLeft() );
+ aTempRect.Left() = aPt.X();
+ aTempRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aTempRect.BottomRight() );
+ aTempRect.Right() = aPt.X();
+ aTempRect.Bottom() = aPt.Y();
+
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ Help::ShowBalloon( this, aTempRect.Center(), aTempRect, maNextToolBoxStr );
+ else
+ Help::ShowQuickHelp( this, aTempRect, maNextToolBoxStr );
+ return;
+ }
+ }
+
+ DockingWindow::RequestHelp( rHEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long ToolBox::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ KeyEvent aKEvt = *rNEvt.GetKeyEvent();
+ KeyCode aKeyCode = aKEvt.GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+ switch( nKeyCode )
+ {
+ case KEY_TAB:
+ {
+ // internal TAB cycling only if parent is not a dialog or if we are the ony child
+ // otherwise the dialog control will take over
+ BOOL bNoTabCycling = ( ( ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL) ) == WB_DIALOGCONTROL &&
+ ImplGetParent()->GetChildCount() != 1 );
+
+ if( bNoTabCycling && ! (GetStyle() & WB_FORCETABCYCLE) )
+ return DockingWindow::Notify( rNEvt );
+ else if( ImplChangeHighlightUpDn( aKeyCode.IsShift() ? TRUE : FALSE , bNoTabCycling ) )
+ return FALSE;
+ else
+ return DockingWindow::Notify( rNEvt );
+ }
+ default:
+ break;
+ };
+ }
+ else if( rNEvt.GetType() == EVENT_GETFOCUS )
+ {
+ if( rNEvt.GetWindow() == this )
+ {
+ // the toolbar itself got the focus
+ if( mnLastFocusItemId != 0 )
+ {
+ // restore last item
+ ImplChangeHighlight( ImplGetItem( mnLastFocusItemId ) );
+ mnLastFocusItemId = 0;
+ }
+ else if( (GetGetFocusFlags() & (GETFOCUS_BACKWARD|GETFOCUS_TAB) ) == (GETFOCUS_BACKWARD|GETFOCUS_TAB))
+ // Shift-TAB was pressed in the parent
+ ImplChangeHighlightUpDn( FALSE );
+ else
+ ImplChangeHighlightUpDn( TRUE );
+
+ mnLastFocusItemId = 0;
+
+ return true;
+ }
+ else
+ {
+ // a child window got the focus so update current item to
+ // allow for proper lose focus handling in keyboard navigation
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ if ( it->mbVisible )
+ {
+ if ( it->mpWindow && it->mpWindow->ImplIsWindowOrChild( rNEvt.GetWindow() ) )
+ {
+ mnHighItemId = it->mnId;
+ break;
+ }
+ }
+
+ ++it;
+ }
+ return DockingWindow::Notify( rNEvt );
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ // deselect
+ ImplHideFocus();
+ mnHighItemId = 0;
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ }
+
+ return DockingWindow::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Command( const CommandEvent& rCEvt )
+{
+ // StartDrag auf MouseButton/Left/Alt abbilden
+ if ( (rCEvt.GetCommand() == COMMAND_STARTDRAG) && rCEvt.IsMouseEvent() &&
+ mbCustomize && !mbDragging && !mbDrag && !mbSelection &&
+ (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
+ {
+ // Wir erlauben nur das Draggen von Items. Deshalb muessen wir
+ // testen, ob auch ein Item angeklickt wurde, ansonsten wuerden
+ // wir evt. das Fenster verschieben, was nicht gewollt waere.
+ // Wir machen dieses jedoch nur im Customize-Mode, da ansonsten
+ // Items zuhaeufig ausversehen verschoben werden.
+ if ( mbCustomizeMode )
+ {
+ Point aMousePos = rCEvt.GetMousePosPixel();
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ // Ist es dieses Item
+ if ( it->maRect.IsInside( aMousePos ) )
+ {
+ // Ist es ein Separator oder ist das Item disabled,
+ // dann mache nichts
+ if ( (it->meType == TOOLBOXITEM_BUTTON) &&
+ !it->mbShowWindow )
+ mbCommandDrag = TRUE;
+ break;
+ }
+
+ ++it;
+ }
+
+ if ( mbCommandDrag )
+ {
+ MouseEvent aMEvt( aMousePos, 1, MOUSE_SIMPLECLICK,
+ MOUSE_LEFT, KEY_MOD2 );
+ ToolBox::MouseButtonDown( aMEvt );
+ return;
+ }
+ }
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ if ( (mnCurLine > 1) || (mnCurLine+mnVisLines-1 < mnCurLines) )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
+ {
+ if ( (mnCurLine > 1) && (pData->GetDelta() > 0) )
+ ShowLine( FALSE );
+ else if ( (mnCurLine+mnVisLines-1 < mnCurLines) && (pData->GetDelta() < 0) )
+ ShowLine( TRUE );
+ ImplDrawSpin( FALSE, FALSE );
+ return;
+ }
+ }
+ }
+
+ DockingWindow::Command( rCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::StateChanged( StateChangedType nType )
+{
+ DockingWindow::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ ImplFormat();
+ else if ( nType == STATE_CHANGE_ENABLE )
+ ImplUpdateItem();
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ mbCalc = TRUE;
+ mbFormat = TRUE;
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE ); // font, foreground, background
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ DockingWindow::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_DISPLAY) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ mbCalc = TRUE;
+ mbFormat = TRUE;
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::PrepareToggleFloatingMode()
+{
+ return DockingWindow::PrepareToggleFloatingMode();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ToggleFloatingMode()
+{
+ DockingWindow::ToggleFloatingMode();
+
+ BOOL mbOldHorz = mbHorz;
+
+ if ( ImplIsFloatingMode() )
+ {
+ mbHorz = TRUE;
+ meAlign = WINDOWALIGN_TOP;
+ mbScroll = TRUE;
+
+ if( mbOldHorz != mbHorz )
+ mbCalc = TRUE; // orientation was changed !
+
+ ImplSetMinMaxFloatSize( this );
+ SetOutputSizePixel( ImplCalcFloatSize( this, mnFloatLines ) );
+ }
+ else
+ {
+ mbScroll = (mnWinStyle & WB_SCROLL) ? TRUE : FALSE;
+ if ( (meAlign == WINDOWALIGN_TOP) || (meAlign == WINDOWALIGN_BOTTOM) )
+ mbHorz = TRUE;
+ else
+ mbHorz = FALSE;
+
+ // set focus back to document
+ ImplGetFrameWindow()->GetWindow( WINDOW_CLIENT )->GrabFocus();
+ }
+
+ if( mbOldHorz != mbHorz )
+ {
+ // if orientation changes, the toolbox has to be initialized again
+ // to update the direction of the gradient
+ mbCalc = TRUE;
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ }
+
+ mbFormat = TRUE;
+ ImplFormat();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::StartDocking()
+{
+ meDockAlign = meAlign;
+ mnDockLines = mnLines;
+ mbLastFloatMode = ImplIsFloatingMode();
+ DockingWindow::StartDocking();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::Docking( const Point& rPos, Rectangle& rRect )
+{
+ // Wenn Dragging, dann nicht machen, da vorher schon berechnet
+ if ( mbDragging )
+ return FALSE;
+
+ BOOL bFloatMode = FALSE;
+
+ DockingWindow::Docking( rPos, rRect );
+
+ // Befindet sich die Maus ausserhalb des Bereichs befindet, kann es nur ein
+ // FloatWindow werden
+ Rectangle aDockingRect( rRect );
+ if ( !ImplIsFloatingMode() )
+ {
+ // don't use tracking rectangle for alignment check, because it will be too large
+ // to get a floating mode as result - switch to floating size
+ // so the calculation only depends on the position of the rectangle, not the current
+ // docking state of the window
+ USHORT nTemp = 0;
+ aDockingRect.SetSize( ImplCalcFloatSize( this, nTemp ) );
+
+ // in this mode docking is never done by keyboard, so it's OK to use the mouse position
+ aDockingRect.SetPos( ImplGetFrameWindow()->GetPointerPosPixel() );
+ }
+
+ Rectangle aIntersection = maOutDockRect.GetIntersection( aDockingRect );
+ if ( !aIntersection.IsEmpty() && !IsDockingPrevented() )
+ {
+ Rectangle aInRect = maInDockRect;
+ Size aDockSize;
+ aDockSize.Width() = ImplCalcSize( this, mnLines, TB_CALCMODE_VERT ).Width();
+ aDockSize.Height() = ImplCalcSize( this, mnLines, TB_CALCMODE_HORZ ).Height();
+ aInRect.Left() += aDockSize.Width()/2;
+ aInRect.Top() += aDockSize.Height()/2;
+ aInRect.Right() -= aDockSize.Width()/2;
+ aInRect.Bottom() -= aDockSize.Height()/2;
+
+ // Wenn Fenster zu klein, wird das gesammte InDock-Rect genommen
+ if ( aInRect.Left() >= aInRect.Right() )
+ {
+ aInRect.Left() = maInDockRect.Left();
+ aInRect.Right() = maInDockRect.Right();
+ }
+ if ( aInRect.Top() >= aInRect.Bottom() )
+ {
+ aInRect.Top() = maInDockRect.Top();
+ aInRect.Bottom() = maInDockRect.Bottom();
+ }
+
+ // Wenn Maus nicht im Dock-Bereich, dann kann es nur zum
+ // FloatWindow werden
+ Rectangle aIntersect = aInRect.GetIntersection( aDockingRect );
+ if ( aIntersect == aDockingRect )
+ bFloatMode = TRUE;
+ else
+ {
+ // docking rectangle is in the "sensible area"
+ Point aPos = aDockingRect.TopLeft();
+ Point aInPosTL( aPos.X()-aInRect.Left(), aPos.Y()-aInRect.Top() );
+ Point aInPosBR( aPos.X()-aInRect.Left() + aDockingRect.GetWidth(), aPos.Y()-aInRect.Top() + aDockingRect.GetHeight() );
+ Size aInSize = aInRect.GetSize();
+
+ if ( aInPosTL.X() <= 0 )
+ meDockAlign = WINDOWALIGN_LEFT;
+ else if ( aInPosTL.Y() <= 0)
+ meDockAlign = WINDOWALIGN_TOP;
+ else if ( aInPosBR.X() >= aInSize.Width() )
+ meDockAlign = WINDOWALIGN_RIGHT;
+ else if ( aInPosBR.Y() >= aInSize.Height() )
+ meDockAlign = WINDOWALIGN_BOTTOM;
+
+ // Wenn sich Dock-Align geaendert hat, muessen wir die
+ // neue Dock-Groesse setzen
+ if ( (meDockAlign == WINDOWALIGN_TOP) || (meDockAlign == WINDOWALIGN_BOTTOM) )
+ aDockSize.Width() = maInDockRect.GetWidth();
+ else
+ aDockSize.Height() = maInDockRect.GetHeight();
+
+ aDockingRect.SetSize( aDockSize );
+
+ Point aPosTL( maInDockRect.TopLeft() );
+ switch ( meDockAlign )
+ {
+ case WINDOWALIGN_TOP :
+ aDockingRect.SetPos( aPosTL );
+ break;
+ case WINDOWALIGN_LEFT :
+ aDockingRect.SetPos( aPosTL );
+ break;
+ case WINDOWALIGN_BOTTOM :
+ {
+ Point aPosBL( maInDockRect.BottomLeft() );
+ aPosBL.Y() -= aDockingRect.GetHeight();
+ aDockingRect.SetPos( aPosBL );
+ break;
+ }
+ case WINDOWALIGN_RIGHT :
+ {
+ Point aPosTR( maInDockRect.TopRight() );
+ aPosTR.X() -= aDockingRect.GetWidth();
+ aDockingRect.SetPos( aPosTR );
+ break;
+ }
+ }
+ }
+ }
+ else
+ bFloatMode = TRUE;
+
+ if ( bFloatMode )
+ {
+ meDockAlign = meAlign;
+ if ( !mbLastFloatMode )
+ {
+ USHORT nTemp = 0;
+ aDockingRect.SetSize( ImplCalcFloatSize( this, nTemp ) );
+ }
+ }
+
+ rRect = aDockingRect;
+ mbLastFloatMode = bFloatMode;
+
+ return bFloatMode;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::EndDocking( const Rectangle& rRect, BOOL bFloatMode )
+{
+ if ( !IsDockingCanceled() )
+ {
+ if ( mnLines != mnDockLines )
+ SetLineCount( mnDockLines );
+ if ( meAlign != meDockAlign )
+ SetAlign( meDockAlign );
+ }
+ if ( bFloatMode || (bFloatMode != ImplIsFloatingMode()) )
+ DockingWindow::EndDocking( rRect, bFloatMode );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Resizing( Size& rSize )
+{
+ USHORT nCalcLines;
+ USHORT nTemp;
+
+ // Alle Floatinggroessen berechnen
+ ImplCalcFloatSizes( this );
+
+ if ( !mnLastResizeDY )
+ mnLastResizeDY = mnDY;
+
+ // Ist vertikales Resizing angesagt
+ if ( (mnLastResizeDY != rSize.Height()) && (mnDY != rSize.Height()) )
+ {
+ nCalcLines = ImplCalcLines( this, rSize.Height() );
+ if ( nCalcLines < 1 )
+ nCalcLines = 1;
+ rSize = ImplCalcFloatSize( this, nCalcLines );
+ }
+ else
+ {
+ nCalcLines = 1;
+ nTemp = nCalcLines;
+ Size aTempSize = ImplCalcFloatSize( this, nTemp );
+ while ( (aTempSize.Width() > rSize.Width()) &&
+ (nCalcLines <= mpFloatSizeAry->mpSize[0].mnLines) )
+ {
+ nCalcLines++;
+ nTemp = nCalcLines;
+ aTempSize = ImplCalcFloatSize( this, nTemp );
+ }
+ rSize = aTempSize;
+ }
+
+ mnLastResizeDY = rSize.Height();
+}
+
+// -----------------------------------------------------------------------
+
+Size ToolBox::CalcWindowSizePixel( USHORT nCalcLines ) const
+{
+ return ImplCalcSize( this, nCalcLines );
+}
+
+Size ToolBox::CalcWindowSizePixel( USHORT nCalcLines, WindowAlign eAlign ) const
+{
+ return ImplCalcSize( this, nCalcLines,
+ (eAlign == WINDOWALIGN_TOP || eAlign == WINDOWALIGN_BOTTOM) ? TB_CALCMODE_HORZ : TB_CALCMODE_VERT );
+}
+
+USHORT ToolBox::ImplCountLineBreaks( const ToolBox *pThis )
+{
+ USHORT nLines = 0;
+
+ std::vector< ImplToolItem >::const_iterator it = ((ToolBox*)pThis)->mpData->m_aItems.begin();
+ while ( it != ((ToolBox*)pThis)->mpData->m_aItems.end() )
+ {
+ if( it->meType == TOOLBOXITEM_BREAK )
+ nLines++;
+ it++;
+ }
+ return nLines;
+}
+
+Size ToolBox::CalcPopupWindowSizePixel() const
+{
+ // count number of breaks and calc corresponding floating window size
+ USHORT nLines = ImplCountLineBreaks( this );
+
+ if( nLines )
+ nLines++; // add the first line
+ else
+ {
+ // no breaks found: use quadratic layout
+ nLines = (USHORT) ceil( sqrt( (double) GetItemCount() ) );
+ }
+
+ BOOL bPopup = mpData->mbAssumePopupMode;
+ ToolBox *pThis = (ToolBox*) this;
+ pThis->mpData->mbAssumePopupMode = TRUE;
+
+ Size aSize = CalcFloatingWindowSizePixel( nLines );
+
+ pThis->mpData->mbAssumePopupMode = bPopup;
+ return aSize;
+}
+
+Size ToolBox::CalcFloatingWindowSizePixel() const
+{
+ USHORT nLines = ImplCountLineBreaks( this );
+ nLines++; // add the first line
+ return CalcFloatingWindowSizePixel( nLines );
+}
+
+Size ToolBox::CalcFloatingWindowSizePixel( USHORT nCalcLines ) const
+{
+ BOOL bFloat = mpData->mbAssumeFloating;
+ BOOL bDocking = mpData->mbAssumeDocked;
+
+ // simulate floating mode and force reformat before calculating
+ ToolBox *pThis = (ToolBox*) this;
+ pThis->mpData->mbAssumeFloating = TRUE;
+ pThis->mpData->mbAssumeDocked = FALSE;
+
+ Size aSize = ImplCalcFloatSize( (ToolBox*) this, nCalcLines );
+
+ pThis->mbFormat = TRUE;
+ pThis->mpData->mbAssumeFloating = bFloat;
+ pThis->mpData->mbAssumeDocked = bDocking;
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+Size ToolBox::CalcMinimumWindowSizePixel() const
+{
+ if( ImplIsFloatingMode() )
+ return ImplCalcSize( this, mnFloatLines );
+ else
+ {
+ // create dummy toolbox for measurements
+ ToolBox *pToolBox = new ToolBox( GetParent(), GetStyle() );
+
+ // copy until first useful item
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ pToolBox->CopyItem( *this, it->mnId );
+ if( (it->meType != TOOLBOXITEM_BUTTON) ||
+ !it->mbVisible || ImplIsFixedControl( &(*it) ) )
+ it++;
+ else
+ break;
+ }
+
+ // add to docking manager if required to obtain a drag area
+ // (which is accounted for in calcwindowsizepixel)
+ if( ImplGetDockingManager()->GetDockingWindowWrapper( this ) )
+ ImplGetDockingManager()->AddWindow( pToolBox );
+
+ // account for menu
+ if( IsMenuEnabled() )
+ pToolBox->SetMenuType( GetMenuType() );
+
+ pToolBox->SetAlign( GetAlign() );
+ Size aSize = pToolBox->CalcWindowSizePixel( 1 );
+
+ ImplGetDockingManager()->RemoveWindow( pToolBox );
+ pToolBox->Clear();
+ delete pToolBox;
+
+ return aSize;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::EnableCustomize( BOOL bEnable )
+{
+ if ( bEnable != mbCustomize )
+ {
+ mbCustomize = bEnable;
+
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ if ( bEnable )
+ pMgr->Insert( this );
+ else
+ pMgr->Remove( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::StartCustomize( const Rectangle& rRect, void* pData )
+{
+ DBG_ASSERT( mbCustomize,
+ "ToolBox::StartCustomize(): ToolBox must be customized" );
+
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ Point aMousePos = GetPointerPosPixel();
+ Point aPos = ScreenToOutputPixel( rRect.TopLeft() );
+ Rectangle aRect( aPos.X(), aPos.Y(),
+ aPos.X()+rRect.GetWidth()+SMALLBUTTON_HSIZE,
+ aPos.Y()+rRect.GetHeight()+SMALLBUTTON_VSIZE );
+ aMousePos = ScreenToOutputPixel( aPos );
+ Pointer aPtr;
+ SetPointer( aPtr );
+ pMgr->StartDragging( this, aMousePos, aRect, 0, FALSE, pData );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::StartCustomizeMode()
+{
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ pMgr->StartCustomizeMode();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::EndCustomizeMode()
+{
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ pMgr->EndCustomizeMode();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::IsCustomizeMode()
+{
+ ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
+ return pMgr->IsCustomizeMode();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::GetFocus()
+{
+ DockingWindow::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::LoseFocus()
+{
+ ImplChangeHighlight( NULL, TRUE );
+
+ DockingWindow::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+// performs the action associated with an item, ie simulates clicking the item
+void ToolBox::TriggerItem( USHORT nItemId, BOOL bShift, BOOL bCtrl )
+{
+ mnHighItemId = nItemId;
+ USHORT nModifier = 0;
+ if( bShift )
+ nModifier |= KEY_SHIFT;
+ if( bCtrl )
+ nModifier |= KEY_MOD1;
+ KeyCode aKeyCode( 0, nModifier );
+ ImplActivateItem( aKeyCode );
+}
+
+// -----------------------------------------------------------------------
+
+// calls the button's action handler
+// returns TRUE if action was called
+BOOL ToolBox::ImplActivateItem( KeyCode aKeyCode )
+{
+ BOOL bRet = TRUE;
+ if( mnHighItemId )
+ {
+ ImplToolItem *pToolItem = ImplGetItem( mnHighItemId );
+
+ // #107712#, activate can also be called for disabled entries
+ if( pToolItem && !pToolItem->mbEnabled )
+ return TRUE;
+
+ if( pToolItem && pToolItem->mpWindow && HasFocus() )
+ {
+ ImplHideFocus();
+ mbChangingHighlight = TRUE; // avoid focus change due to loose focus
+ pToolItem->mpWindow->ImplControlFocus( GETFOCUS_TAB );
+ mbChangingHighlight = FALSE;
+ }
+ else
+ {
+ mnDownItemId = mnCurItemId = mnHighItemId;
+ ImplToolItem* pItem = ImplGetItem( mnHighItemId );
+ if ( pItem->mnBits & TIB_AUTOCHECK )
+ {
+ if ( pItem->mnBits & TIB_RADIOCHECK )
+ {
+ if ( pItem->meState != STATE_CHECK )
+ SetItemState( pItem->mnId, STATE_CHECK );
+ }
+ else
+ {
+ if ( pItem->meState != STATE_CHECK )
+ pItem->meState = STATE_CHECK;
+ else
+ pItem->meState = STATE_NOCHECK;
+ }
+ }
+ mnMouseModifier = aKeyCode.GetModifier();
+ mbIsKeyEvent = TRUE;
+ Activate();
+ Click();
+
+ // #107776# we might be destroyed in the selecthandler
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ Select();
+ if ( aDelData.IsDelete() )
+ return bRet;
+ ImplRemoveDel( &aDelData );
+
+ Deactivate();
+ mbIsKeyEvent = FALSE;
+ mnMouseModifier = 0;
+ }
+ }
+ else
+ bRet = FALSE;
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplCloseLastPopup( Window *pParent )
+{
+ // close last popup toolbox (see also:
+ // ImplHandleMouseFloatMode(...) in winproc.cxx )
+
+ if( ImplGetSVData()->maWinData.mpFirstFloat )
+ {
+ FloatingWindow* pLastLevelFloat = ImplGetSVData()->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ // only close the floater if it is not our direct parent, which would kill ourself
+ if( pLastLevelFloat && pLastLevelFloat != pParent )
+ {
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// opens a drop down toolbox item
+// returns TRUE if item was opened
+BOOL ToolBox::ImplOpenItem( KeyCode aKeyCode )
+{
+ USHORT nCode = aKeyCode.GetCode();
+ BOOL bRet = TRUE;
+
+ // arrow keys should work only in the opposite direction of alignment (to not break cursor travelling)
+ if ( ((nCode == KEY_LEFT || nCode == KEY_RIGHT) && IsHorizontal())
+ || ((nCode == KEY_UP || nCode == KEY_DOWN) && !IsHorizontal()) )
+ return FALSE;
+
+ if( IsMenuEnabled() && mpData->mbMenubuttonSelected )
+ {
+ if( ImplCloseLastPopup( GetParent() ) )
+ return bRet;
+
+ ImplUpdateCustomMenu();
+ Application::PostUserEvent( mpData->mnEventId, LINK( this, ToolBox, ImplCallExecuteCustomMenu ) );
+ }
+ else if( mnHighItemId && ImplGetItem( mnHighItemId ) &&
+ (ImplGetItem( mnHighItemId )->mnBits & TIB_DROPDOWN) )
+ {
+ if( ImplCloseLastPopup( GetParent() ) )
+ return bRet;
+
+ mnDownItemId = mnCurItemId = mnHighItemId;
+ mnCurPos = GetItemPos( mnCurItemId );
+ mnLastFocusItemId = mnCurItemId; // save item id for possible later focus restore
+ mnMouseModifier = aKeyCode.GetModifier();
+ mbIsShift = TRUE;
+ mbIsKeyEvent = TRUE;
+ Activate();
+
+ mpData->mbDropDownByKeyboard = TRUE;
+ GetDropdownClickHdl().Call( this );
+
+ mbIsKeyEvent = FALSE;
+ mbIsShift = FALSE;
+ mnMouseModifier = 0;
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+ mnKeyModifier = aKeyCode.GetModifier();
+ USHORT nCode = aKeyCode.GetCode();
+ BOOL bParentIsDialog = ( ( ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL) ) == WB_DIALOGCONTROL );
+ BOOL bForwardKey = FALSE;
+ BOOL bGrabFocusToDocument = FALSE;
+
+ // #107776# we might be destroyed in the keyhandler
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+ switch ( nCode )
+ {
+ case KEY_UP:
+ {
+ // Ctrl-Cursor activates next toolbox, indicated by a blue arrow pointing to the left/up
+ if( aKeyCode.GetModifier() ) // allow only pure cursor keys
+ break;
+ if( !IsHorizontal() )
+ ImplChangeHighlightUpDn( TRUE );
+ else
+ ImplOpenItem( aKeyCode );
+ }
+ break;
+ case KEY_LEFT:
+ {
+ if( aKeyCode.GetModifier() ) // allow only pure cursor keys
+ break;
+ if( IsHorizontal() )
+ ImplChangeHighlightUpDn( TRUE );
+ else
+ ImplOpenItem( aKeyCode );
+ }
+ break;
+ case KEY_DOWN:
+ {
+ if( aKeyCode.GetModifier() ) // allow only pure cursor keys
+ break;
+ if( !IsHorizontal() )
+ ImplChangeHighlightUpDn( FALSE );
+ else
+ ImplOpenItem( aKeyCode );
+ }
+ break;
+ case KEY_RIGHT:
+ {
+ if( aKeyCode.GetModifier() ) // allow only pure cursor keys
+ break;
+ if( IsHorizontal() )
+ ImplChangeHighlightUpDn( FALSE );
+ else
+ ImplOpenItem( aKeyCode );
+ }
+ break;
+ case KEY_PAGEUP:
+ if ( mnCurLine > 1 )
+ {
+ if( mnCurLine > mnVisLines )
+ mnCurLine = mnCurLine - mnVisLines;
+ else
+ mnCurLine = 1;
+ mbFormat = TRUE;
+ ImplFormat();
+ ImplDrawSpin( FALSE, FALSE );
+ ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) );
+ }
+ break;
+ case KEY_PAGEDOWN:
+ if ( mnCurLine+mnVisLines-1 < mnCurLines )
+ {
+ if( mnCurLine + 2*mnVisLines-1 < mnCurLines )
+ mnCurLine = mnCurLine + mnVisLines;
+ else
+ mnCurLine = mnCurLines;
+ mbFormat = TRUE;
+ ImplFormat();
+ ImplDrawSpin( FALSE, FALSE );
+ ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) );
+ }
+ break;
+ case KEY_END:
+ {
+ ImplChangeHighlight( NULL );
+ ImplChangeHighlightUpDn( FALSE );
+ }
+ break;
+ case KEY_HOME:
+ {
+ ImplChangeHighlight( NULL );
+ ImplChangeHighlightUpDn( TRUE );
+ }
+ break;
+ case KEY_ESCAPE:
+ {
+ if( !ImplIsFloatingMode() && bParentIsDialog )
+ DockingWindow::KeyInput( rKEvt );
+ else
+ {
+ // send focus to document pane
+ Window *pWin = this;
+ while( pWin )
+ {
+ if( !pWin->GetParent() )
+ {
+ pWin->ImplGetFrameWindow()->GetWindow( WINDOW_CLIENT )->GrabFocus();
+ break;
+ }
+ pWin = pWin->GetParent();
+ }
+ }
+ }
+ break;
+ case KEY_RETURN:
+ {
+ // #107712#, disabled entries are selectable now
+ // leave toolbox and move focus to document
+ if( mnHighItemId )
+ {
+ ImplToolItem *pItem = ImplGetItem( mnHighItemId );
+ if( !pItem->mbEnabled )
+ {
+ Sound::Beep( SOUND_DISABLE, this );
+ bGrabFocusToDocument = TRUE;
+ }
+ }
+ if( !bGrabFocusToDocument )
+ bForwardKey = !ImplActivateItem( aKeyCode );
+ }
+ break;
+ default:
+ {
+ USHORT aKeyGroup = aKeyCode.GetGroup();
+ ImplToolItem *pItem = NULL;
+ if( mnHighItemId )
+ pItem = ImplGetItem( mnHighItemId );
+ // #i13931# forward alphanum keyinput into embedded control
+ if( (aKeyGroup == KEYGROUP_NUM || aKeyGroup == KEYGROUP_ALPHA ) && pItem && pItem->mpWindow && pItem->mbEnabled )
+ {
+ Window *pFocusWindow = Application::GetFocusWindow();
+ ImplHideFocus();
+ mbChangingHighlight = TRUE; // avoid focus change due to loose focus
+ pItem->mpWindow->ImplControlFocus( GETFOCUS_TAB );
+ mbChangingHighlight = FALSE;
+ if( pFocusWindow != Application::GetFocusWindow() )
+ Application::GetFocusWindow()->KeyInput( rKEvt );
+ }
+ else
+ {
+ // do nothing to avoid key presses going into the document
+ // while the toolbox has the focus
+ // just forward function and special keys and combinations with Alt-key
+ if( aKeyGroup == KEYGROUP_FKEYS || aKeyGroup == KEYGROUP_MISC || aKeyCode.IsMod2() )
+ bForwardKey = TRUE;
+ }
+ }
+ }
+
+ if ( aDelData.IsDelete() )
+ return;
+ ImplRemoveDel( &aDelData );
+
+ // #107251# move focus away if this toolbox was disabled during keyinput
+ if( HasFocus() && mpData->mbKeyInputDisabled && (ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL) ) == WB_DIALOGCONTROL)
+ {
+ USHORT n = 0;
+ Window *pFocusControl = ImplGetParent()->ImplGetDlgWindow( n, DLGWINDOW_FIRST );
+ if ( pFocusControl && pFocusControl != this )
+ pFocusControl->ImplControlFocus( GETFOCUS_INIT );
+ }
+
+ mnKeyModifier = 0;
+
+ // #107712#, leave toolbox
+ if( bGrabFocusToDocument )
+ {
+ GrabFocusToDocument();
+ return;
+ }
+
+ if( bForwardKey )
+ DockingWindow::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+// returns the current toolbox line of the item
+USHORT ToolBox::ImplGetItemLine( ImplToolItem* pCurrentItem )
+{
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ USHORT nLine = 1;
+ while( it != mpData->m_aItems.end() )
+ {
+ if ( it->mbBreak )
+ nLine++;
+ if( &(*it) == pCurrentItem)
+ break;
+ ++it;
+ }
+ return nLine;
+}
+
+// returns the first displayable item in the given line
+ImplToolItem* ToolBox::ImplGetFirstValidItem( USHORT nLine )
+{
+ if( !nLine || nLine > mnCurLines )
+ return NULL;
+
+ nLine--;
+
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ // find correct line
+ if ( it->mbBreak )
+ nLine--;
+ if( !nLine )
+ {
+ // find first useful item
+ while( it != mpData->m_aItems.end() && ((it->meType != TOOLBOXITEM_BUTTON) ||
+ /*!it->mbEnabled ||*/ !it->mbVisible || ImplIsFixedControl( &(*it) )) )
+ {
+ ++it;
+ if( it == mpData->m_aItems.end() || it->mbBreak )
+ return NULL; // no valid items in this line
+ }
+ return &(*it);
+ }
+ ++it;
+ }
+
+ return (it == mpData->m_aItems.end()) ? NULL : &(*it);
+}
+
+// returns the last displayable item in the given line
+ImplToolItem* ToolBox::ImplGetLastValidItem( USHORT nLine )
+{
+ if( !nLine || nLine > mnCurLines )
+ return NULL;
+
+ nLine--;
+ ImplToolItem *pFound = NULL;
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ // find correct line
+ if ( it->mbBreak )
+ nLine--;
+ if( !nLine )
+ {
+ // find last useful item
+ while( it != mpData->m_aItems.end() && ((it->meType == TOOLBOXITEM_BUTTON) &&
+ /*it->mbEnabled &&*/ it->mbVisible && !ImplIsFixedControl( &(*it) )) )
+ {
+ pFound = &(*it);
+ ++it;
+ if( it == mpData->m_aItems.end() || it->mbBreak )
+ return pFound; // end of line: return last useful item
+ }
+ return pFound;
+ }
+ ++it;
+ }
+
+ return pFound;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::ImplFindItemPos( const ImplToolItem* pItem, const std::vector< ImplToolItem >& rList )
+{
+ if( pItem )
+ {
+ USHORT nPos;
+ for( nPos = 0; nPos < rList.size(); nPos++ )
+ if( &rList[ nPos ] == pItem )
+ return nPos;
+ }
+ return TOOLBOX_ITEM_NOTFOUND;
+}
+
+void ToolBox::ChangeHighlight( USHORT nPos )
+{
+ if ( nPos < GetItemCount() ) {
+ ImplGrabFocus( 0 );
+ ImplChangeHighlight ( ImplGetItem ( GetItemId ( (USHORT) nPos ) ), FALSE );
+ }
+}
+
+void ToolBox::ImplChangeHighlight( ImplToolItem* pItem, BOOL bNoGrabFocus )
+{
+ // avoid recursion due to focus change
+ if( mbChangingHighlight )
+ return;
+
+ mbChangingHighlight = TRUE;
+
+ ImplToolItem* pOldItem = NULL;
+
+ if ( mnHighItemId )
+ {
+ ImplHideFocus();
+ USHORT nPos = GetItemPos( mnHighItemId );
+ pOldItem = ImplGetItem( mnHighItemId );
+ // #i89962# ImplDrawItem can cause Invalidate/Update
+ // which will in turn ImplShowFocus again
+ // set mnHighItemId to 0 already to prevent this hen/egg problem
+ mnHighItemId = 0;
+ ImplDrawItem( nPos, FALSE );
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nPos ) );
+ }
+
+ if( !bNoGrabFocus && pItem != pOldItem && pOldItem && pOldItem->mpWindow )
+ {
+ // move focus into toolbox
+ GrabFocus();
+ }
+
+ if( pItem )
+ {
+ USHORT aPos = ToolBox::ImplFindItemPos( pItem, mpData->m_aItems );
+ if( aPos != TOOLBOX_ITEM_NOTFOUND)
+ {
+ // check for line breaks
+ USHORT nLine = ImplGetItemLine( pItem );
+
+ if( nLine >= mnCurLine + mnVisLines )
+ {
+ mnCurLine = nLine - mnVisLines + 1;
+ mbFormat = TRUE;
+ }
+ else if ( nLine < mnCurLine )
+ {
+ mnCurLine = nLine;
+ mbFormat = TRUE;
+ }
+
+ if( mbFormat )
+ {
+ ImplFormat();
+ }
+
+ mnHighItemId = pItem->mnId;
+ ImplDrawItem( aPos, 2 ); // always use shadow effect (2)
+
+ if( mbSelection )
+ mnCurPos = aPos;
+ ImplShowFocus();
+
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT );
+ }
+ }
+ else
+ {
+ ImplHideFocus();
+ mnHighItemId = 0;
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ }
+
+ mbChangingHighlight = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+// check for keyboard accessible items
+static BOOL ImplIsValidItem( const ImplToolItem* pItem, BOOL bNotClipped )
+{
+ BOOL bValid = (pItem && pItem->meType == TOOLBOXITEM_BUTTON && pItem->mbVisible && !ImplIsFixedControl( pItem ));
+ if( bValid && bNotClipped && pItem->IsClipped() )
+ bValid = FALSE;
+ return bValid;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::ImplChangeHighlightUpDn( BOOL bUp, BOOL bNoCycle )
+{
+ ImplToolItem* pToolItem = ImplGetItem( mnHighItemId );
+
+ if( !pToolItem || !mnHighItemId )
+ {
+ // menubutton highlighted ?
+ if( mpData->mbMenubuttonSelected )
+ {
+ if( bUp )
+ {
+ // select last valid non-clipped item
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.end();
+ ImplToolItem* pItem = NULL;
+ while( it != mpData->m_aItems.begin() )
+ {
+ --it;
+ if ( ImplIsValidItem( &(*it), TRUE ) )
+ {
+ pItem = &(*it);
+ break;
+ }
+ }
+ ImplDrawMenubutton( this, FALSE );
+ ImplChangeHighlight( pItem );
+ }
+ else
+ {
+ // select first valid non-clipped item
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ if ( ImplIsValidItem( &(*it), TRUE ) )
+ break;
+ ++it;
+ }
+ if( it != mpData->m_aItems.end() )
+ {
+ ImplDrawMenubutton( this, FALSE );
+ ImplChangeHighlight( &(*it) );
+ }
+ }
+ return TRUE;
+ }
+
+ if( bUp )
+ {
+ // Select first valid item
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ if ( ImplIsValidItem( &(*it), FALSE ) )
+ break;
+ ++it;
+ }
+
+ // select the menu button if a clipped item would be selected
+ if( (it != mpData->m_aItems.end() && &(*it) == ImplGetFirstClippedItem( this )) && IsMenuEnabled() )
+ {
+ ImplChangeHighlight( NULL );
+ ImplDrawMenubutton( this, TRUE );
+ }
+ else
+ ImplChangeHighlight( (it != mpData->m_aItems.end()) ? &(*it) : NULL );
+ return TRUE;
+ }
+ else
+ {
+ // Select last valid item
+
+ // docked toolbars have the menubutton as last item - if this button is enabled
+ if( IsMenuEnabled() && !ImplIsFloatingMode() )
+ {
+ ImplChangeHighlight( NULL );
+ ImplDrawMenubutton( this, TRUE );
+ }
+ else
+ {
+ std::vector< ImplToolItem >::iterator it = mpData->m_aItems.end();
+ ImplToolItem* pItem = NULL;
+ while( it != mpData->m_aItems.begin() )
+ {
+ --it;
+ if ( ImplIsValidItem( &(*it), FALSE ) )
+ {
+ pItem = &(*it);
+ break;
+ }
+ }
+ ImplChangeHighlight( pItem );
+ }
+ return TRUE;
+ }
+ }
+
+ if( pToolItem )
+ {
+ ULONG pos = ToolBox::ImplFindItemPos( pToolItem, mpData->m_aItems );
+ ULONG nCount = mpData->m_aItems.size();
+
+ ULONG i=0;
+ do
+ {
+ if( bUp )
+ {
+ if( !pos-- )
+ {
+ if( bNoCycle )
+ return FALSE;
+
+ // highlight the menu button if it is the last item
+ if( IsMenuEnabled() && !ImplIsFloatingMode() )
+ {
+ ImplChangeHighlight( NULL );
+ ImplDrawMenubutton( this, TRUE );
+ return TRUE;
+ }
+ else
+ pos = nCount-1;
+ }
+ }
+ else
+ {
+ if( ++pos >= nCount )
+ {
+ if( bNoCycle )
+ return FALSE;
+
+ // highlight the menu button if it is the last item
+ if( IsMenuEnabled() && !ImplIsFloatingMode() )
+ {
+ ImplChangeHighlight( NULL );
+ ImplDrawMenubutton( this, TRUE );
+ return TRUE;
+ }
+ else
+ pos = 0;
+ }
+ }
+
+ pToolItem = &mpData->m_aItems[pos];
+
+ if ( ImplIsValidItem( pToolItem, FALSE ) )
+ break;
+
+ } while( ++i < nCount);
+
+ if( pToolItem->IsClipped() && IsMenuEnabled() )
+ {
+ // select the menu button if a clipped item would be selected
+ ImplChangeHighlight( NULL );
+ ImplDrawMenubutton( this, TRUE );
+ }
+ else if( i != nCount )
+ ImplChangeHighlight( pToolItem );
+ else
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplShowFocus()
+{
+ if( mnHighItemId && HasFocus() )
+ {
+ ImplToolItem* pItem = ImplGetItem( mnHighItemId );
+ if( pItem->mpWindow )
+ {
+ Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow : pItem->mpWindow;
+ pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = TRUE;
+ pWin->Invalidate( 0 );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplHideFocus()
+{
+ if( mnHighItemId )
+ {
+ ImplToolItem* pItem = ImplGetItem( mnHighItemId );
+ if( pItem->mpWindow )
+ {
+ Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow : pItem->mpWindow;
+ pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = FALSE;
+ pWin->Invalidate( 0 );
+ }
+ }
+
+ if ( mpData->mbMenubuttonSelected )
+ {
+ // remove highlight from menubutton
+ ImplDrawMenubutton( this, FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplDisableFlatButtons()
+{
+#ifdef WNT // Check in the Windows registry if an AT tool wants no flat toolboxes
+ static bool bInit = false, bValue = false;
+ if( ! bInit )
+ {
+ bInit = true;
+ HKEY hkey;
+
+ if( ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER,
+ "Software\\OpenOffice.org\\Accessibility\\AtToolSupport",
+ &hkey) )
+ {
+ DWORD dwType = 0;
+ WIN_BYTE Data[6]; // possible values: "true", "false", "1", "0", DWORD
+ DWORD cbData = sizeof(Data);
+
+ if( ERROR_SUCCESS == RegQueryValueEx(hkey, "DisableFlatToolboxButtons",
+ NULL, &dwType, Data, &cbData) )
+ {
+ switch (dwType)
+ {
+ case REG_SZ:
+ bValue = ((0 == stricmp((const char *) Data, "1")) || (0 == stricmp((const char *) Data, "true")));
+ break;
+ case REG_DWORD:
+ bValue = (bool)(((DWORD *) Data)[0]);
+ break;
+ }
+ }
+ RegCloseKey(hkey);
+ }
+ }
+ if( bValue )
+ mnOutStyle &= ~TOOLBOX_STYLE_FLAT;
+#endif
+}
diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx
new file mode 100644
index 000000000000..334cdd2d0a64
--- /dev/null
+++ b/vcl/source/window/toolbox2.cxx
@@ -0,0 +1,2437 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/list.hxx>
+#include <tools/debug.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/help.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/toolbox.h>
+#include <vcl/mnemonic.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/brdwin.hxx>
+
+#include <vcl/unohelp.hxx>
+#include <unotools/confignode.hxx>
+
+#include <vcl/ImageListProvider.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace vcl;
+using namespace rtl;
+
+// =======================================================================
+
+#define TB_SEP_SIZE 8
+
+// -----------------------------------------------------------------------
+
+ImplToolBoxPrivateData::ImplToolBoxPrivateData() :
+ m_pLayoutData( NULL ),
+ mpImageListProvider( NULL ),
+ meImageListType( vcl::IMAGELISTTYPE_UNKNOWN )
+{
+ meButtonSize = TOOLBOX_BUTTONSIZE_DONTCARE;
+ mpMenu = new PopupMenu();
+ mnEventId = 0;
+
+ maMenuType = TOOLBOX_MENUTYPE_NONE;
+ maMenubuttonItem.maItemSize = Size( TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET, TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET );
+ maMenubuttonItem.meState = STATE_NOCHECK;
+ mnMenuButtonWidth = TB_MENUBUTTON_SIZE;
+
+
+ mbIsLocked = FALSE;
+ mbNativeButtons = FALSE;
+ mbIsPaintLocked = FALSE;
+ mbAssumeDocked = FALSE;
+ mbAssumePopupMode = FALSE;
+ mbAssumeFloating = FALSE;
+ mbKeyInputDisabled = FALSE;
+ mbMenubuttonSelected = FALSE;
+ mbPageScroll = FALSE;
+ mbWillUsePopupMode = FALSE;
+ mbDropDownByKeyboard = FALSE;
+}
+
+ImplToolBoxPrivateData::~ImplToolBoxPrivateData()
+{
+ if( m_pLayoutData )
+ delete m_pLayoutData;
+ delete mpMenu;
+}
+
+// -----------------------------------------------------------------------
+ImplToolItem::ImplToolItem()
+{
+ mnId = 0;
+ mpWindow = NULL;
+ mpUserData = NULL;
+ mnHelpId = 0;
+ meType = TOOLBOXITEM_BUTTON;
+ mnBits = 0;
+ meState = STATE_NOCHECK;
+ mbEnabled = TRUE;
+ mbVisible = TRUE;
+ mbEmptyBtn = TRUE;
+ mbShowWindow = FALSE;
+ mbBreak = FALSE;
+ mnSepSize = TB_SEP_SIZE;
+ mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
+ mnImageAngle = 0;
+ mbMirrorMode = FALSE;
+ mbVisibleText = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplToolItem::ImplToolItem( USHORT nItemId, const Image& rImage,
+ ToolBoxItemBits nItemBits ) :
+ maImage( rImage )
+{
+ mnId = nItemId;
+ mpWindow = NULL;
+ mpUserData = NULL;
+ mnHelpId = 0;
+ meType = TOOLBOXITEM_BUTTON;
+ mnBits = nItemBits;
+ meState = STATE_NOCHECK;
+ mbEnabled = TRUE;
+ mbVisible = TRUE;
+ mbEmptyBtn = FALSE;
+ mbShowWindow = FALSE;
+ mbBreak = FALSE;
+ mnSepSize = TB_SEP_SIZE;
+ mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
+ mnImageAngle = 0;
+ mbMirrorMode = false;
+ mbVisibleText = false;
+}
+
+// -----------------------------------------------------------------------
+
+ImplToolItem::ImplToolItem( USHORT nItemId, const XubString& rText,
+ ToolBoxItemBits nItemBits ) :
+ maText( rText )
+{
+ mnId = nItemId;
+ mpWindow = NULL;
+ mpUserData = NULL;
+ mnHelpId = 0;
+ meType = TOOLBOXITEM_BUTTON;
+ mnBits = nItemBits;
+ meState = STATE_NOCHECK;
+ mbEnabled = TRUE;
+ mbVisible = TRUE;
+ mbEmptyBtn = FALSE;
+ mbShowWindow = FALSE;
+ mbBreak = FALSE;
+ mnSepSize = TB_SEP_SIZE;
+ mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
+ mnImageAngle = 0;
+ mbMirrorMode = false;
+ mbVisibleText = false;
+}
+
+// -----------------------------------------------------------------------
+
+ImplToolItem::ImplToolItem( USHORT nItemId, const Image& rImage,
+ const XubString& rText, ToolBoxItemBits nItemBits ) :
+ maImage( rImage ),
+ maText( rText )
+{
+ mnId = nItemId;
+ mpWindow = NULL;
+ mpUserData = NULL;
+ mnHelpId = 0;
+ meType = TOOLBOXITEM_BUTTON;
+ mnBits = nItemBits;
+ meState = STATE_NOCHECK;
+ mbEnabled = TRUE;
+ mbVisible = TRUE;
+ mbEmptyBtn = FALSE;
+ mbShowWindow = FALSE;
+ mbBreak = FALSE;
+ mnSepSize = TB_SEP_SIZE;
+ mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
+ mnImageAngle = 0;
+ mbMirrorMode = false;
+ mbVisibleText = false;
+}
+
+// -----------------------------------------------------------------------
+
+ImplToolItem::ImplToolItem( const ImplToolItem& rItem ) :
+ mpWindow ( rItem.mpWindow ),
+ mpUserData ( rItem.mpUserData ),
+ maImage ( rItem.maImage ),
+ maHighImage ( rItem.maHighImage ),
+ mnImageAngle ( rItem.mnImageAngle ),
+ mbMirrorMode ( rItem.mbMirrorMode ),
+ maText ( rItem.maText ),
+ maQuickHelpText ( rItem.maQuickHelpText ),
+ maHelpText ( rItem.maHelpText ),
+ maCommandStr ( rItem.maCommandStr ),
+ mnHelpId ( rItem.mnHelpId ),
+ maRect ( rItem.maRect ),
+ maCalcRect ( rItem.maCalcRect ),
+ maItemSize ( rItem.maItemSize ),
+ mnSepSize ( rItem.mnSepSize ),
+ mnDropDownArrowWidth ( rItem.mnDropDownArrowWidth ),
+ meType ( rItem.meType ),
+ mnBits ( rItem.mnBits ),
+ meState ( rItem.meState ),
+ mnId ( rItem.mnId ),
+ mbEnabled ( rItem.mbEnabled ),
+ mbVisible ( rItem.mbVisible ),
+ mbEmptyBtn ( rItem.mbEmptyBtn ),
+ mbShowWindow ( rItem.mbShowWindow ),
+ mbBreak ( rItem.mbBreak ),
+ mbVisibleText ( rItem.mbVisibleText )
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImplToolItem::~ImplToolItem()
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImplToolItem& ImplToolItem::operator=( const ImplToolItem& rItem )
+{
+ mpWindow = rItem.mpWindow;
+ mpUserData = rItem.mpUserData;
+ maImage = rItem.maImage;
+ maHighImage = rItem.maHighImage;
+ mnImageAngle = rItem.mnImageAngle;
+ mbMirrorMode = rItem.mbMirrorMode;
+ maText = rItem.maText;
+ maQuickHelpText = rItem.maQuickHelpText;
+ maHelpText = rItem.maHelpText;
+ maCommandStr = rItem.maCommandStr;
+ mnHelpId = rItem.mnHelpId;
+ maRect = rItem.maRect;
+ maCalcRect = rItem.maCalcRect;
+ mnSepSize = rItem.mnSepSize;
+ mnDropDownArrowWidth = rItem.mnDropDownArrowWidth;
+ maItemSize = rItem.maItemSize;
+ mbVisibleText = rItem.mbVisibleText;
+ meType = rItem.meType;
+ mnBits = rItem.mnBits;
+ meState = rItem.meState;
+ mnId = rItem.mnId;
+ mbEnabled = rItem.mbEnabled;
+ mbVisible = rItem.mbVisible;
+ mbEmptyBtn = rItem.mbEmptyBtn;
+ mbShowWindow = rItem.mbShowWindow;
+ mbBreak = rItem.mbBreak;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+Size ImplToolItem::GetSize( BOOL bHorz, BOOL bCheckMaxWidth, long maxWidth, const Size& rDefaultSize )
+{
+ Size aSize( rDefaultSize ); // the size of 'standard' toolbox items
+ // non-standard items are eg windows or buttons with text
+
+ if ( (meType == TOOLBOXITEM_BUTTON) || (meType == TOOLBOXITEM_SPACE) )
+ {
+ aSize = maItemSize;
+
+ if ( mpWindow && bHorz )
+ {
+ // get size of item window and check if it fits
+ // no windows in vertical toolbars (the default is mbShowWindow=FALSE)
+ Size aWinSize = mpWindow->GetSizePixel();
+ if ( !bCheckMaxWidth || (aWinSize.Width() <= maxWidth) )
+ {
+ aSize.Width() = aWinSize.Width();
+ aSize.Height() = aWinSize.Height();
+ mbShowWindow = TRUE;
+ }
+ else
+ {
+ if ( mbEmptyBtn )
+ {
+ aSize.Width() = 0;
+ aSize.Height() = 0;
+ }
+ }
+ }
+ }
+ else if ( meType == TOOLBOXITEM_SEPARATOR )
+ {
+ if ( bHorz )
+ {
+ aSize.Width() = mnSepSize;
+ aSize.Height() = rDefaultSize.Height();
+ }
+ else
+ {
+ aSize.Width() = rDefaultSize.Width();
+ aSize.Height() = mnSepSize;
+ }
+ }
+ else if ( meType == TOOLBOXITEM_BREAK )
+ {
+ aSize.Width() = 0;
+ aSize.Height() = 0;
+ }
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplToolItem::DetermineButtonDrawStyle( ButtonType eButtonType, BOOL& rbImage, BOOL& rbText ) const
+{
+ if ( meType != TOOLBOXITEM_BUTTON )
+ {
+ // no button -> draw nothing
+ rbImage = rbText = FALSE;
+ return;
+ }
+
+ BOOL bHasImage;
+ BOOL bHasText;
+
+ // check for image and/or text
+ if ( !(maImage) )
+ bHasImage = FALSE;
+ else
+ bHasImage = TRUE;
+ if ( !maText.Len() )
+ bHasText = FALSE;
+ else
+ bHasText = TRUE;
+
+ // prefer images if symbolonly buttons are drawn
+ // prefer texts if textonly buttons are dreawn
+
+ if ( eButtonType == BUTTON_SYMBOL ) // drawing icons only
+ {
+ if( bHasImage || !bHasText )
+ {
+ rbImage = TRUE;
+ rbText = FALSE;
+ }
+ else
+ {
+ rbImage = FALSE;
+ rbText = TRUE;
+ }
+ }
+ else if ( eButtonType == BUTTON_TEXT ) // drawing text only
+ {
+ if( bHasText || !bHasImage )
+ {
+ rbImage = FALSE;
+ rbText = TRUE;
+ }
+ else
+ {
+ rbImage = TRUE;
+ rbText = FALSE;
+ }
+ }
+ else // drawing icons and text both
+ {
+ rbImage = TRUE;
+ rbText = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ImplToolItem::GetDropDownRect( BOOL bHorz ) const
+{
+ Rectangle aRect;
+ if( (mnBits & TIB_DROPDOWN) && !maRect.IsEmpty() )
+ {
+ aRect = maRect;
+ if( mbVisibleText && !bHorz )
+ // item will be rotated -> place dropdown to the bottom
+ aRect.Top() = aRect.Bottom() - mnDropDownArrowWidth;
+ else
+ // place dropdown to the right
+ aRect.Left() = aRect.Right() - mnDropDownArrowWidth;
+ }
+ return aRect;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplToolItem::IsClipped() const
+{
+ return ( meType == TOOLBOXITEM_BUTTON && mbVisible && maRect.IsEmpty() );
+}
+
+// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+
+const XubString& ToolBox::ImplConvertMenuString( const XubString& rStr )
+{
+ maCvtStr = rStr;
+ if ( mbMenuStrings )
+ maCvtStr.EraseTrailingChars( '.' );
+ maCvtStr = MnemonicGenerator::EraseAllMnemonicChars( maCvtStr );
+ return maCvtStr;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplInvalidate( BOOL bNewCalc, BOOL bFullPaint )
+{
+ ImplUpdateInputEnable();
+
+ if ( bNewCalc )
+ mbCalc = TRUE;
+
+ if ( bFullPaint )
+ {
+ mbFormat = TRUE;
+
+ // Muss ueberhaupt eine neue Ausgabe erfolgen
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ Invalidate( Rectangle( mnLeftBorder, mnTopBorder,
+ mnDX-mnRightBorder-1, mnDY-mnBottomBorder-1 ) );
+ maTimer.Stop();
+ }
+ }
+ else
+ {
+ if ( !mbFormat )
+ {
+ mbFormat = TRUE;
+
+ // Muss ueberhaupt eine neue Ausgabe erfolgen
+ if ( IsReallyVisible() && IsUpdateMode() )
+ maTimer.Start();
+ }
+ }
+
+ // request new layout by layoutmanager
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_FORMATCHANGED );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplUpdateItem( USHORT nIndex )
+{
+ // Muss ueberhaupt eine neue Ausgabe erfolgen
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ if ( nIndex == 0xFFFF )
+ {
+ // #i52217# no immediate draw as this might lead to paint problems
+ Invalidate( Rectangle( mnLeftBorder, mnTopBorder,
+ mnDX-mnRightBorder-1, mnDY-mnBottomBorder-1 ) );
+ }
+ else
+ {
+ if ( !mbFormat )
+ {
+ // #i52217# no immediate draw as this might lead to paint problems
+ Invalidate( mpData->m_aItems[nIndex].maRect );
+ }
+ else
+ maPaintRect.Union( mpData->m_aItems[nIndex].maRect );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Click()
+{
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_CLICK );
+ maClickHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::DoubleClick()
+{
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_DOUBLECLICK );
+ maDoubleClickHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Activate()
+{
+ mnActivateCount++;
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ACTIVATE );
+ maActivateHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Deactivate()
+{
+ mnActivateCount--;
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_DEACTIVATE );
+ maDeactivateHdl.Call( this );
+
+ if ( mbHideStatusText )
+ {
+ GetpApp()->HideHelpStatusText();
+ mbHideStatusText = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Highlight()
+{
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT );
+ maHighlightHdl.Call( this );
+
+ XubString aStr = GetHelpText( mnCurItemId );
+ if ( aStr.Len() || mbHideStatusText )
+ {
+ GetpApp()->ShowHelpStatusText( aStr );
+ mbHideStatusText = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Select()
+{
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_SELECT );
+ maSelectHdl.Call( this );
+
+ if ( aDelData.IsDelete() )
+ return;
+ ImplRemoveDel( &aDelData );
+
+ // TODO: GetFloatingWindow in DockingWindow is currently inline, change it to check dockingwrapper
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper && pWrapper->GetFloatingWindow() && pWrapper->GetFloatingWindow()->IsInPopupMode() )
+ pWrapper->GetFloatingWindow()->EndPopupMode();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::NextToolBox()
+{
+ maNextToolBoxHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Customize( const ToolBoxCustomizeEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::UserDraw( const UserDrawEvent& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertItem( const ResId& rResId, USHORT nPos )
+{
+ ULONG nObjMask;
+ BOOL bImage = FALSE; // Wurde Image gesetzt
+
+ // Item anlegen
+ ImplToolItem aItem;
+
+ GetRes( rResId.SetRT( RSC_TOOLBOXITEM ) );
+ nObjMask = ReadLongRes();
+
+ if ( nObjMask & RSC_TOOLBOXITEM_ID )
+ aItem.mnId = sal::static_int_cast<USHORT>(ReadLongRes());
+ else
+ aItem.mnId = 1;
+
+ if ( nObjMask & RSC_TOOLBOXITEM_TYPE )
+ aItem.meType = (ToolBoxItemType)ReadLongRes();
+
+ if ( nObjMask & RSC_TOOLBOXITEM_STATUS )
+ aItem.mnBits = (ToolBoxItemBits)ReadLongRes();
+
+ if( nObjMask & RSC_TOOLBOXITEM_HELPID )
+ aItem.mnHelpId = ReadLongRes();
+
+ if ( nObjMask & RSC_TOOLBOXITEM_TEXT )
+ {
+ aItem.maText = ReadStringRes();
+ aItem.maText = ImplConvertMenuString( aItem.maText );
+ }
+ if ( nObjMask & RSC_TOOLBOXITEM_HELPTEXT )
+ aItem.maHelpText = ReadStringRes();
+
+ if ( nObjMask & RSC_TOOLBOXITEM_BITMAP )
+ {
+ Bitmap aBmp = Bitmap( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ aItem.maImage = Image( aBmp, IMAGE_STDBTN_COLOR );
+ bImage = TRUE;
+ }
+ if ( nObjMask & RSC_TOOLBOXITEM_IMAGE )
+ {
+ aItem.maImage = Image( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) );
+ bImage = TRUE;
+ }
+ if ( nObjMask & RSC_TOOLBOXITEM_DISABLE )
+ aItem.mbEnabled = !(BOOL)ReadShortRes();
+
+ if ( nObjMask & RSC_TOOLBOXITEM_STATE )
+ aItem.meState = (TriState)ReadLongRes();
+
+ if ( nObjMask & RSC_TOOLBOXITEM_HIDE )
+ aItem.mbVisible = !((BOOL)ReadShortRes());
+
+ if ( nObjMask & RSC_TOOLBOXITEM_COMMAND )
+ aItem.maCommandStr = ReadStringRes();
+
+ // Wenn kein Image geladen wurde, versuchen wir das Image aus der
+ // Image-Liste zu holen
+ if ( !bImage && aItem.mnId )
+ aItem.maImage = maImageList.GetImage( aItem.mnId );
+
+ // Wenn es sich um ein ButtonItem handelt, die ID ueberpruefen
+ BOOL bNewCalc;
+ if ( aItem.meType != TOOLBOXITEM_BUTTON )
+ {
+ bNewCalc = FALSE;
+ aItem.mnId = 0;
+ }
+ else
+ {
+ bNewCalc = TRUE;
+
+ DBG_ASSERT( aItem.mnId, "ToolBox::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( aItem.mnId ) == TOOLBOX_ITEM_NOTFOUND,
+ "ToolBox::InsertItem(): ItemId already exists" );
+ }
+
+ // Item anlegen und in die Liste einfuegen
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
+ mpData->ImplClearLayoutData();
+
+ // ToolBox neu brechnen und neu ausgeben
+ ImplInvalidate( bNewCalc );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertItem( USHORT nItemId, const Image& rImage,
+ ToolBoxItemBits nBits, USHORT nPos )
+{
+ DBG_ASSERT( nItemId, "ToolBox::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND,
+ "ToolBox::InsertItem(): ItemId already exists" );
+
+ // Item anlegen und in die Liste einfuegen
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), ImplToolItem( nItemId, rImage, nBits ) );
+ mpData->ImplClearLayoutData();
+
+ ImplInvalidate( TRUE );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >(nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertItem( USHORT nItemId, const Image& rImage,
+ const XubString& rText,
+ ToolBoxItemBits nBits, USHORT nPos )
+{
+ DBG_ASSERT( nItemId, "ToolBox::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND,
+ "ToolBox::InsertItem(): ItemId already exists" );
+
+ // Item anlegen und in die Liste einfuegen
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), ImplToolItem( nItemId, rImage, ImplConvertMenuString( rText ), nBits ) );
+ mpData->ImplClearLayoutData();
+
+ ImplInvalidate( TRUE );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertItem( USHORT nItemId, const XubString& rText,
+ ToolBoxItemBits nBits, USHORT nPos )
+{
+ DBG_ASSERT( nItemId, "ToolBox::InsertItem(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND,
+ "ToolBox::InsertItem(): ItemId already exists" );
+
+ // Item anlegen und in die Liste einfuegen
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), ImplToolItem( nItemId, ImplConvertMenuString( rText ), nBits ) );
+ mpData->ImplClearLayoutData();
+
+ ImplInvalidate( TRUE );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertWindow( USHORT nItemId, Window* pWindow,
+ ToolBoxItemBits nBits, USHORT nPos )
+{
+ DBG_ASSERT( nItemId, "ToolBox::InsertWindow(): ItemId == 0" );
+ DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND,
+ "ToolBox::InsertWindow(): ItemId already exists" );
+
+ // Item anlegen und in die Liste einfuegen
+ ImplToolItem aItem;
+ aItem.mnId = nItemId;
+ aItem.meType = TOOLBOXITEM_BUTTON;
+ aItem.mnBits = nBits;
+ aItem.mpWindow = pWindow;
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
+ mpData->ImplClearLayoutData();
+
+ if ( pWindow )
+ pWindow->Hide();
+
+ ImplInvalidate( TRUE );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertSpace( USHORT nPos )
+{
+ // Item anlegen und in die Liste einfuegen
+ ImplToolItem aItem;
+ aItem.meType = TOOLBOXITEM_SPACE;
+ aItem.mbEnabled = FALSE;
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
+ mpData->ImplClearLayoutData();
+
+ ImplInvalidate( FALSE );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertSeparator( USHORT nPos, USHORT nPixSize )
+{
+ // Item anlegen und in die Liste einfuegen
+ ImplToolItem aItem;
+ aItem.meType = TOOLBOXITEM_SEPARATOR;
+ aItem.mbEnabled = FALSE;
+ if ( nPixSize )
+ aItem.mnSepSize = nPixSize;
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
+ mpData->ImplClearLayoutData();
+
+ ImplInvalidate( FALSE );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::InsertBreak( USHORT nPos )
+{
+ // Item anlegen und in die Liste einfuegen
+ ImplToolItem aItem;
+ aItem.meType = TOOLBOXITEM_BREAK;
+ aItem.mbEnabled = FALSE;
+ mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem );
+ mpData->ImplClearLayoutData();
+
+ ImplInvalidate( FALSE );
+
+ // Notify
+ USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::RemoveItem( USHORT nPos )
+{
+ if( nPos < mpData->m_aItems.size() )
+ {
+ BOOL bMustCalc;
+ if ( mpData->m_aItems[nPos].meType == TOOLBOXITEM_BUTTON )
+ bMustCalc = TRUE;
+ else
+ bMustCalc = FALSE;
+
+ if ( mpData->m_aItems[nPos].mpWindow )
+ mpData->m_aItems[nPos].mpWindow->Hide();
+
+ // PaintRect um das removete Item erweitern
+ maPaintRect.Union( mpData->m_aItems[nPos].maRect );
+
+ // Absichern gegen das Loeschen im Select-Handler
+ if ( mpData->m_aItems[nPos].mnId == mnCurItemId )
+ mnCurItemId = 0;
+ if ( mpData->m_aItems[nPos].mnId == mnHighItemId )
+ mnHighItemId = 0;
+
+ ImplInvalidate( bMustCalc );
+
+ mpData->m_aItems.erase( mpData->m_aItems.begin()+nPos );
+ mpData->ImplClearLayoutData();
+
+ // Notify
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMREMOVED, reinterpret_cast< void* >( nPos ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::MoveItem( USHORT nItemId, USHORT nNewPos )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos == nNewPos )
+ return;
+
+ if ( nPos < nNewPos )
+ nNewPos--;
+
+ // Existiert Item
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ // ToolBox-Item in der Liste verschieben
+ ImplToolItem aItem = mpData->m_aItems[nPos];
+ mpData->m_aItems.erase( mpData->m_aItems.begin()+nPos );
+ mpData->m_aItems.insert( (nNewPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nNewPos : mpData->m_aItems.end(), aItem );
+ mpData->ImplClearLayoutData();
+
+ // ToolBox neu ausgeben
+ ImplInvalidate( FALSE );
+
+ // Notify
+ if( nPos < nNewPos ) // only send one event, all indices above this item are invalid anyway
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMREMOVED, reinterpret_cast< void* >( nPos ) );
+ else
+ {
+ USHORT nNewPos2 = sal::static_int_cast<USHORT>(( nNewPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nNewPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos2 ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::CopyItem( const ToolBox& rToolBox, USHORT nItemId,
+ USHORT nNewPos )
+{
+ DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND,
+ "ToolBox::CopyItem(): ItemId already exists" );
+
+ USHORT nPos = rToolBox.GetItemPos( nItemId );
+
+ // Existiert Item
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ // ToolBox-Item in der Liste verschieben
+ ImplToolItem aNewItem = rToolBox.mpData->m_aItems[nPos];
+ // Bestimme Daten zuruecksetzen
+ aNewItem.mpWindow = NULL;
+ aNewItem.mbShowWindow = FALSE;
+
+ mpData->m_aItems.insert( (nNewPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nNewPos : mpData->m_aItems.end(), aNewItem );
+ mpData->ImplClearLayoutData();
+ // ToolBox neu ausgeben
+ ImplInvalidate( FALSE );
+
+ // Notify
+ USHORT nNewPos2 = sal::static_int_cast<USHORT>(( nNewPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nNewPos);
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos2 ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::CopyItems( const ToolBox& rToolBox )
+{
+ mpData->ImplClearLayoutData();
+ mpData->m_aItems = rToolBox.mpData->m_aItems;
+ // Absichern gegen das Loeschen im Select-Handler
+ mnCurItemId = 0;
+ mnHighItemId = 0;
+
+ for( std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
+ it != mpData->m_aItems.end(); ++it )
+ {
+ it->mpWindow = NULL;
+ it->mbShowWindow = FALSE;
+ }
+
+ ImplInvalidate( TRUE, TRUE );
+
+ // Notify
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ALLITEMSCHANGED );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Clear()
+{
+ mpData->m_aItems.clear();
+ mpData->ImplClearLayoutData();
+
+ // Absichern gegen das Loeschen im Select-Handler
+ mnCurItemId = 0;
+ mnHighItemId = 0;
+
+ ImplInvalidate( TRUE, TRUE );
+
+ // Notify
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ALLITEMSCHANGED );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetButtonType( ButtonType eNewType )
+{
+ if ( meButtonType != eNewType )
+ {
+ meButtonType = eNewType;
+
+ // Hier besser alles neu ausgeben, da es ansonsten zu Problemen
+ // mit den per CopyBits kopierten Bereichen geben kann
+ ImplInvalidate( TRUE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetToolboxButtonSize( ToolBoxButtonSize eSize )
+{
+ if( mpData->meButtonSize != eSize )
+ {
+ mpData->meButtonSize = eSize;
+ mbCalc = TRUE;
+ mbFormat = TRUE;
+ }
+}
+
+ToolBoxButtonSize ToolBox::GetToolboxButtonSize() const
+{
+ return mpData->meButtonSize;
+}
+
+// -----------------------------------------------------------------------
+
+const Size& ToolBox::GetDefaultImageSize() const
+{
+ static Size aSmallButtonSize( TB_SMALLIMAGESIZE, TB_SMALLIMAGESIZE );
+
+ static ULONG s_nSymbolsStyle = STYLE_SYMBOLS_DEFAULT;
+ static Size aLargeButtonSize( TB_LARGEIMAGESIZE, TB_LARGEIMAGESIZE );
+
+ ULONG nSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyle();
+ if ( s_nSymbolsStyle != nSymbolsStyle )
+ {
+ s_nSymbolsStyle = nSymbolsStyle;
+ switch ( nSymbolsStyle )
+ {
+ case STYLE_SYMBOLS_INDUSTRIAL:
+ aLargeButtonSize = Size( TB_LARGEIMAGESIZE_INDUSTRIAL, TB_LARGEIMAGESIZE_INDUSTRIAL );
+ break;
+ case STYLE_SYMBOLS_CRYSTAL:
+ aLargeButtonSize = Size( TB_LARGEIMAGESIZE_CRYSTAL, TB_LARGEIMAGESIZE_CRYSTAL );
+ break;
+ case STYLE_SYMBOLS_OXYGEN:
+ aLargeButtonSize = Size( TB_LARGEIMAGESIZE_OXYGEN, TB_LARGEIMAGESIZE_OXYGEN );
+ break;
+ default:
+ aLargeButtonSize = Size( TB_LARGEIMAGESIZE, TB_LARGEIMAGESIZE );
+ }
+ }
+
+ return GetToolboxButtonSize() == TOOLBOX_BUTTONSIZE_LARGE ? aLargeButtonSize : aSmallButtonSize;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetAlign( WindowAlign eNewAlign )
+{
+ if ( meAlign != eNewAlign )
+ {
+ meAlign = eNewAlign;
+
+ if ( !ImplIsFloatingMode() )
+ {
+ // Setzen, ob Items horizontal oder vertikal angeordnet werden sollen
+ if ( (eNewAlign == WINDOWALIGN_LEFT) || (eNewAlign == WINDOWALIGN_RIGHT) )
+ mbHorz = FALSE;
+ else
+ mbHorz = TRUE;
+
+ // Hier alles neu ausgeben, da sich Border auch aendert
+ mbCalc = TRUE;
+ mbFormat = TRUE;
+ if ( IsReallyVisible() && IsUpdateMode() )
+ Invalidate();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetLineCount( USHORT nNewLines )
+{
+ if ( !nNewLines )
+ nNewLines = 1;
+
+ if ( mnLines != nNewLines )
+ {
+ mnLines = nNewLines;
+
+ // Hier besser alles neu ausgeben, da es ansonsten zu Problemen
+ // mit den per CopyBits kopierten Bereichen geben kann
+ ImplInvalidate( FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetPageScroll( BOOL b )
+{
+ mpData->mbPageScroll = b;
+}
+
+BOOL ToolBox::GetPageScroll()
+{
+ return mpData->mbPageScroll;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetNextToolBox( const XubString& rStr )
+{
+ BOOL bCalcNew = (!maNextToolBoxStr.Len() != !rStr.Len());
+ maNextToolBoxStr = rStr;
+ if ( bCalcNew )
+ ImplInvalidate( TRUE, FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::GetItemCount() const
+{
+ return (USHORT)mpData->m_aItems.size();
+}
+
+// -----------------------------------------------------------------------
+
+ToolBoxItemType ToolBox::GetItemType( USHORT nPos ) const
+{
+ return (nPos < mpData->m_aItems.size()) ? mpData->m_aItems[nPos].meType : TOOLBOXITEM_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::GetItemPos( USHORT nItemId ) const
+{
+ int nCount = mpData->m_aItems.size();
+ for( int nPos = 0; nPos < nCount; nPos++ )
+ if( mpData->m_aItems[nPos].mnId == nItemId )
+ return (USHORT)nPos;
+
+ return TOOLBOX_ITEM_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::GetItemPos( const Point& rPos ) const
+{
+ // search the item position on the given point
+ USHORT nRet = TOOLBOX_ITEM_NOTFOUND;
+ USHORT nPos = 0;
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ if ( it->maRect.IsInside( rPos ) )
+ {
+ // item found -> save position and break
+ nRet = nPos;
+ break;
+ }
+
+ ++it;
+ ++nPos;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::GetItemId( USHORT nPos ) const
+{
+ return (nPos < mpData->m_aItems.size()) ? mpData->m_aItems[nPos].mnId : 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::GetItemId( const Point& rPos ) const
+{
+ // Item suchen, das geklickt wurde
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while( it != mpData->m_aItems.end() )
+ {
+ // Ist es dieses Item
+ if ( it->maRect.IsInside( rPos ) )
+ {
+ if ( it->meType == TOOLBOXITEM_BUTTON )
+ return it->mnId;
+ else
+ return 0;
+ }
+
+ ++it;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+Point ToolBox::ImplGetPopupPosition( const Rectangle& rRect, const Size& rSize ) const
+{
+ Point aPos;
+ if( !rRect.IsEmpty() )
+ {
+ Rectangle aScreen = GetDesktopRectPixel();
+
+ // the popup should be positioned so that it will not cover
+ // the item rect and that it fits the desktop
+ // the preferred direction is always towards the center of
+ // the application window
+
+ Point devPos; // the position in device coordinates for screen comparison
+ switch( meAlign )
+ {
+ case WINDOWALIGN_TOP:
+ aPos = rRect.BottomLeft();
+ aPos.Y()++;
+ devPos = OutputToAbsoluteScreenPixel( aPos );
+ if( devPos.Y() + rSize.Height() >= aScreen.Bottom() )
+ aPos.Y() = rRect.Top() - rSize.Height();
+ break;
+ case WINDOWALIGN_BOTTOM:
+ aPos = rRect.TopLeft();
+ aPos.Y()--;
+ devPos = OutputToAbsoluteScreenPixel( aPos );
+ if( devPos.Y() - rSize.Height() > aScreen.Top() )
+ aPos.Y() -= rSize.Height();
+ else
+ aPos.Y() = rRect.Bottom();
+ break;
+ case WINDOWALIGN_LEFT:
+ aPos = rRect.TopRight();
+ aPos.X()++;
+ devPos = OutputToAbsoluteScreenPixel( aPos );
+ if( devPos.X() + rSize.Width() >= aScreen.Right() )
+ aPos.X() = rRect.Left() - rSize.Width();
+ break;
+ case WINDOWALIGN_RIGHT:
+ aPos = rRect.TopLeft();
+ aPos.X()--;
+ devPos = OutputToAbsoluteScreenPixel( aPos );
+ if( devPos.X() - rSize.Width() > aScreen.Left() )
+ aPos.X() -= rSize.Width();
+ else
+ aPos.X() = rRect.Right();
+ break;
+ default:
+ break;
+ };
+ }
+ return aPos;
+}
+
+
+Point ToolBox::GetItemPopupPosition( USHORT nItemId, const Size& rSize ) const
+{
+ return ImplGetPopupPosition( GetItemRect( nItemId ), rSize );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ToolBox::GetItemRect( USHORT nItemId ) const
+{
+ if ( mbCalc || mbFormat )
+ ((ToolBox*)this)->ImplFormat();
+
+ USHORT nPos = GetItemPos( nItemId );
+ return GetItemPosRect( nPos );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ToolBox::GetItemPosRect( USHORT nPos ) const
+{
+ if ( mbCalc || mbFormat )
+ ((ToolBox*)this)->ImplFormat();
+
+ if ( nPos < mpData->m_aItems.size() )
+ return mpData->m_aItems[nPos].maRect;
+ else
+ return Rectangle();
+}
+
+// -----------------------------------------------------------------------
+Rectangle ToolBox::GetItemDropDownRect( USHORT nItemId ) const
+{
+ if ( mbCalc || mbFormat )
+ ((ToolBox*)this)->ImplFormat();
+
+ USHORT nPos = GetItemPos( nItemId );
+ return GetItemPosDropDownRect( nPos );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ToolBox::GetItemPosDropDownRect( USHORT nPos ) const
+{
+ if ( mbCalc || mbFormat )
+ ((ToolBox*)this)->ImplFormat();
+
+ if ( nPos < mpData->m_aItems.size() )
+ return mpData->m_aItems[nPos].GetDropDownRect( mbHorz );
+ else
+ return Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ToolBox::GetMenubuttonRect() const
+{
+ return mpData->maMenubuttonItem.maRect;
+}
+
+BOOL ToolBox::ImplHasExternalMenubutton()
+{
+ // check if the borderwindow (i.e. the decoration) provides the menu button
+ BOOL bRet = FALSE;
+ if( ImplIsFloatingMode() )
+ {
+ // custom menu is placed in the decoration
+ ImplBorderWindow *pBorderWin = dynamic_cast<ImplBorderWindow*>( GetWindow( WINDOW_BORDER ) );
+ if( pBorderWin && !pBorderWin->GetMenuRect().IsEmpty() )
+ bRet = TRUE;
+ }
+ return bRet;
+}
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemBits( USHORT nItemId, ToolBoxItemBits nBits )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos < mpData->m_aItems.size() )
+ {
+ ToolBoxItemBits nOldBits = mpData->m_aItems[nPos].mnBits;
+ mpData->m_aItems[nPos].mnBits = nBits;
+ nBits &= TIB_LEFT | TIB_AUTOSIZE | TIB_DROPDOWN;
+ nOldBits &= TIB_LEFT | TIB_AUTOSIZE | TIB_DROPDOWN;
+ // trigger reformat when the item width has changed (dropdown arrow)
+ BOOL bFormat = (nBits & TIB_DROPDOWN) != (nOldBits & TIB_DROPDOWN);
+ if ( nBits != nOldBits )
+ ImplInvalidate( TRUE, bFormat );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ToolBoxItemBits ToolBox::GetItemBits( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mnBits;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemData( USHORT nItemId, void* pNewData )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos < mpData->m_aItems.size() )
+ {
+ mpData->m_aItems[nPos].mpUserData = pNewData;
+ ImplUpdateItem( nPos );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void* ToolBox::GetItemData( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mpUserData;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemImage( USHORT nItemId, const Image& rImage )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+ // Nur wenn alles berechnet ist, mehr Aufwand treiben
+ if ( !mbCalc )
+ {
+ Size aOldSize = pItem->maImage.GetSizePixel();
+ pItem->maImage = rImage;
+ if ( aOldSize != pItem->maImage.GetSizePixel() )
+ ImplInvalidate( TRUE );
+ else
+ ImplUpdateItem( nPos );
+ }
+ else
+ pItem->maImage = rImage;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetImageList( const ImageList& rImageList )
+{
+ maImageList = rImageList;
+
+ USHORT nCount = (USHORT)mpData->m_aItems.size();
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ Image aImage;
+ if ( mpData->m_aItems[i].mnId )
+ aImage = maImageList.GetImage( mpData->m_aItems[i].mnId );
+ if( !!aImage )
+ SetItemImage( mpData->m_aItems[i].mnId, aImage );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static Image ImplRotImage( const Image& rImage, long nAngle10 )
+{
+ Image aRet;
+ BitmapEx aRotBitmapEx( rImage.GetBitmapEx() );
+
+ aRotBitmapEx.Rotate( nAngle10, Color( COL_WHITE ) );
+
+ return Image( aRotBitmapEx );
+}
+
+void ToolBox::SetItemImageAngle( USHORT nItemId, long nAngle10 )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+ Size aOldSize = pItem->maImage.GetSizePixel();
+
+ long nDeltaAngle = (nAngle10 - pItem->mnImageAngle) % 3600;
+ while( nDeltaAngle < 0 )
+ nDeltaAngle += 3600;
+
+ pItem->mnImageAngle = nAngle10;
+ if( nDeltaAngle && !!pItem->maImage )
+ {
+ pItem->maImage = ImplRotImage( pItem->maImage, nDeltaAngle );
+ if( !!pItem->maHighImage )
+ pItem->maHighImage = ImplRotImage( pItem->maHighImage, nDeltaAngle );
+ }
+
+ if ( !mbCalc )
+ {
+ if ( aOldSize != pItem->maImage.GetSizePixel() )
+ ImplInvalidate( TRUE );
+ else
+ ImplUpdateItem( nPos );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static Image ImplMirrorImage( const Image& rImage )
+{
+ Image aRet;
+ BitmapEx aMirrBitmapEx( rImage.GetBitmapEx() );
+
+ aMirrBitmapEx.Mirror( BMP_MIRROR_HORZ );
+
+ return Image( aMirrBitmapEx );
+}
+
+void ToolBox::SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+
+ if( ( pItem->mbMirrorMode && ! bMirror ) ||
+ ( ! pItem->mbMirrorMode && bMirror )
+ )
+ {
+ pItem->mbMirrorMode = bMirror ? true : false;
+ if( !!pItem->maImage )
+ {
+ pItem->maImage = ImplMirrorImage( pItem->maImage );
+ if( !!pItem->maHighImage )
+ pItem->maHighImage = ImplMirrorImage( pItem->maHighImage );
+ }
+
+ if ( !mbCalc )
+ ImplUpdateItem( nPos );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Image ToolBox::GetItemImage( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->maImage;
+ else
+ return Image();
+}
+
+// -----------------------------------------------------------------------
+
+long ToolBox::GetItemImageAngle( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mnImageAngle;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::GetItemImageMirrorMode( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mbMirrorMode;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemHighImage( USHORT nItemId, const Image& rImage )
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+ if ( pItem )
+ {
+ DBG_ASSERT( (pItem->maImage.GetSizePixel() == rImage.GetSizePixel()) ||
+ ((!rImage) == TRUE), "ToolBox::SetItemHighImage() - ImageSize != HighImageSize" );
+ pItem->maHighImage = rImage;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Image ToolBox::GetItemHighImage( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->maHighImage;
+ else
+ return Image();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemText( USHORT nItemId, const XubString& rText )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+ // Nur wenn alles berechnet ist, mehr Aufwand treiben
+ if ( !mbCalc &&
+ ((meButtonType != BUTTON_SYMBOL) || !pItem->maImage) )
+ {
+ long nOldWidth = GetCtrlTextWidth( pItem->maText );
+ pItem->maText = ImplConvertMenuString( rText );
+ mpData->ImplClearLayoutData();
+ if ( nOldWidth != GetCtrlTextWidth( pItem->maText ) )
+ ImplInvalidate( TRUE );
+ else
+ ImplUpdateItem( nPos );
+ }
+ else
+ pItem->maText = ImplConvertMenuString( rText );
+
+ // Notify button changed event to prepare accessibility bridge
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED, reinterpret_cast< void* >( nPos ) );
+
+ // Notify
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMTEXTCHANGED, reinterpret_cast< void* >( nPos ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& ToolBox::GetItemText( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->maText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemWindow( USHORT nItemId, Window* pNewWindow )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+ pItem->mpWindow = pNewWindow;
+ if ( pNewWindow )
+ pNewWindow->Hide();
+ ImplInvalidate( TRUE );
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMWINDOWCHANGED, reinterpret_cast< void* >( nPos ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Window* ToolBox::GetItemWindow( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mpWindow;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::StartSelection()
+{
+ if ( mbDrag )
+ EndSelection();
+
+ if ( !mbSelection )
+ {
+ mbSelection = TRUE;
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ mnCurItemId = 0;
+ Activate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::EndSelection()
+{
+ mbCommandDrag = FALSE;
+
+ if ( mbDrag || mbSelection )
+ {
+ // Daten zuruecksetzen
+ mbDrag = FALSE;
+ mbSelection = FALSE;
+ if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
+ ImplDrawItem( mnCurPos );
+ EndTracking();
+ ReleaseMouse();
+ Deactivate();
+ }
+
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ mnCurItemId = 0;
+ mnDownItemId = 0;
+ mnMouseClicks = 0;
+ mnMouseModifier = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemDown( USHORT nItemId, BOOL bDown, BOOL bRelease )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ if ( bDown )
+ {
+ if ( nPos != mnCurPos )
+ {
+ mnCurPos = nPos;
+ ImplDrawItem( mnCurPos, TRUE );
+ Flush();
+ }
+ }
+ else
+ {
+ if ( nPos == mnCurPos )
+ {
+ ImplDrawItem( mnCurPos, FALSE );
+ Flush();
+ mnCurPos = TOOLBOX_ITEM_NOTFOUND;
+ }
+ }
+
+ if ( bRelease )
+ {
+ if ( mbDrag || mbSelection )
+ {
+ mbDrag = FALSE;
+ mbSelection = FALSE;
+ EndTracking();
+ ReleaseMouse();
+ Deactivate();
+ }
+
+ mnCurItemId = 0;
+ mnDownItemId = 0;
+ mnMouseClicks = 0;
+ mnMouseModifier = 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::IsItemDown( USHORT nItemId ) const
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ return (nPos == mnCurPos);
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemState( USHORT nItemId, TriState eState )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+
+ // Hat sich der Status geaendert
+ if ( pItem->meState != eState )
+ {
+ // Wenn RadioCheck, dann vorherigen unchecken
+ if ( (eState == STATE_CHECK) && (pItem->mnBits & TIB_AUTOCHECK) &&
+ (pItem->mnBits & TIB_RADIOCHECK) )
+ {
+ ImplToolItem* pGroupItem;
+ USHORT nGroupPos;
+ USHORT nItemCount = GetItemCount();
+
+ nGroupPos = nPos;
+ while ( nGroupPos )
+ {
+ pGroupItem = &mpData->m_aItems[nGroupPos-1];
+ if ( pGroupItem->mnBits & TIB_RADIOCHECK )
+ {
+ if ( pGroupItem->meState != STATE_NOCHECK )
+ SetItemState( pGroupItem->mnId, STATE_NOCHECK );
+ }
+ else
+ break;
+ nGroupPos--;
+ }
+
+ nGroupPos = nPos+1;
+ while ( nGroupPos < nItemCount )
+ {
+ pGroupItem = &mpData->m_aItems[nGroupPos];
+ if ( pGroupItem->mnBits & TIB_RADIOCHECK )
+ {
+ if ( pGroupItem->meState != STATE_NOCHECK )
+ SetItemState( pGroupItem->mnId, STATE_NOCHECK );
+ }
+ else
+ break;
+ nGroupPos++;
+ }
+ }
+
+ pItem->meState = eState;
+ ImplUpdateItem( nPos );
+
+ // Notify button changed event to prepare accessibility bridge
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED, reinterpret_cast< void* >( nPos ) );
+
+ // Notify
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_CLICK, reinterpret_cast< void* >( nPos ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TriState ToolBox::GetItemState( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->meState;
+ else
+ return STATE_NOCHECK;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::EnableItem( USHORT nItemId, BOOL bEnable )
+{
+ USHORT nPos = GetItemPos( nItemId );
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+ if ( bEnable )
+ bEnable = TRUE;
+ if ( pItem->mbEnabled != bEnable )
+ {
+ pItem->mbEnabled = bEnable;
+
+ // Gegebenenfalls das Fenster mit updaten
+ if ( pItem->mpWindow )
+ pItem->mpWindow->Enable( pItem->mbEnabled );
+
+ // Item updaten
+ ImplUpdateItem( nPos );
+
+ ImplUpdateInputEnable();
+
+ // Notify button changed event to prepare accessibility bridge
+ ImplCallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED, reinterpret_cast< void* >( nPos ) );
+
+ ImplCallEventListeners( bEnable ? VCLEVENT_TOOLBOX_ITEMENABLED : VCLEVENT_TOOLBOX_ITEMDISABLED, reinterpret_cast< void* >( nPos ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::IsItemEnabled( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mbEnabled;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ShowItem( USHORT nItemId, BOOL bVisible )
+{
+ USHORT nPos = GetItemPos( nItemId );
+ mpData->ImplClearLayoutData();
+
+ if ( nPos != TOOLBOX_ITEM_NOTFOUND )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[nPos];
+ if ( pItem->mbVisible != bVisible )
+ {
+ pItem->mbVisible = bVisible;
+ ImplInvalidate( FALSE );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::IsItemVisible( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mbVisible;
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::IsItemReallyVisible( USHORT nItemId ) const
+{
+ // is the item on the visible area of the toolbox?
+ BOOL bRet = FALSE;
+ Rectangle aRect( mnLeftBorder, mnTopBorder, mnDX-mnRightBorder, mnDY-mnBottomBorder );
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem && pItem->mbVisible &&
+ !pItem->maRect.IsEmpty() && aRect.IsOver( pItem->maRect ) )
+ {
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetItemCommand( USHORT nItemId, const XubString& rCommand )
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ pItem->maCommandStr = rCommand;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& ToolBox::GetItemCommand( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->maCommandStr;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetQuickHelpText( USHORT nItemId, const XubString& rText )
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ pItem->maQuickHelpText = rText;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& ToolBox::GetQuickHelpText( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->maQuickHelpText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetHelpText( USHORT nItemId, const XubString& rText )
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ pItem->maHelpText = rText;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& ToolBox::GetHelpText( USHORT nItemId ) const
+{
+ return ImplGetHelpText( nItemId );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetHelpId( USHORT nItemId, ULONG nHelpId )
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ pItem->mnHelpId = nHelpId;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG ToolBox::GetHelpId( USHORT nItemId ) const
+{
+ ImplToolItem* pItem = ImplGetItem( nItemId );
+
+ if ( pItem )
+ return pItem->mnHelpId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetBorder( long nX, long nY )
+{
+ mnBorderX = nX;
+ mnBorderY = nY;
+
+ ImplInvalidate( TRUE, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetOutStyle( USHORT nNewStyle )
+{
+ // always force flat looking toolbars since NWF
+ nNewStyle |= TOOLBOX_STYLE_FLAT;
+
+ if ( mnOutStyle != nNewStyle )
+ {
+ mnOutStyle = nNewStyle;
+ ImplDisableFlatButtons();
+
+ // Damit das ButtonDevice neu angelegt wird
+ if ( !(mnOutStyle & TOOLBOX_STYLE_FLAT) )
+ {
+ mnMaxItemWidth = 1;
+ mnMaxItemHeight = 1;
+ }
+
+ ImplInvalidate( TRUE, TRUE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::RecalcItems()
+{
+ ImplInvalidate( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+// disable key input if all items are disabled
+
+void ToolBox::ImplUpdateInputEnable()
+{
+ for( std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ it != mpData->m_aItems.end(); ++it )
+ {
+ if( it->mbEnabled )
+ {
+ // at least one useful entry
+ mpData->mbKeyInputDisabled = FALSE;
+ return;
+ }
+ }
+ mpData->mbKeyInputDisabled = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::ImplFillLayoutData() const
+{
+ mpData->m_pLayoutData = new ToolBoxLayoutData();
+
+ USHORT nCount = (USHORT)mpData->m_aItems.size();
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ ImplToolItem* pItem = &mpData->m_aItems[i];
+
+ // Nur malen, wenn Rechteck im PaintRectangle liegt
+ if ( !pItem->maRect.IsEmpty() )
+ const_cast<ToolBox*>(this)->ImplDrawItem( i, FALSE, FALSE, TRUE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+String ToolBox::GetDisplayText() const
+{
+ if( ! mpData->m_pLayoutData )
+ ImplFillLayoutData();
+ return mpData->m_pLayoutData ? mpData->m_pLayoutData->m_aDisplayText : String();
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ToolBox::GetCharacterBounds( USHORT nItemID, long nIndex ) const
+{
+ long nItemIndex = -1;
+ if( ! mpData->m_pLayoutData )
+ ImplFillLayoutData();
+ if( mpData->m_pLayoutData )
+ {
+ for( ULONG i = 0; i < mpData->m_pLayoutData->m_aLineItemIds.size(); i++ )
+ {
+ if( mpData->m_pLayoutData->m_aLineItemIds[i] == nItemID )
+ {
+ nItemIndex = mpData->m_pLayoutData->m_aLineIndices[i];
+ break;
+ }
+ }
+ }
+ return (mpData->m_pLayoutData && nItemIndex != -1) ? mpData->m_pLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+long ToolBox::GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const
+{
+ long nIndex = -1;
+ rItemID = 0;
+ if( ! mpData->m_pLayoutData )
+ ImplFillLayoutData();
+ if( mpData->m_pLayoutData )
+ {
+ nIndex = mpData->m_pLayoutData->GetIndexForPoint( rPoint );
+ for( ULONG i = 0; i < mpData->m_pLayoutData->m_aLineIndices.size(); i++ )
+ {
+ if( mpData->m_pLayoutData->m_aLineIndices[i] <= nIndex &&
+ (i == mpData->m_pLayoutData->m_aLineIndices.size()-1 || mpData->m_pLayoutData->m_aLineIndices[i+1] > nIndex) )
+ {
+ rItemID = mpData->m_pLayoutData->m_aLineItemIds[i];
+ break;
+ }
+ }
+ }
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+long ToolBox::GetTextCount() const
+{
+ if( ! mpData->m_pLayoutData )
+ ImplFillLayoutData();
+ return mpData->m_pLayoutData ? mpData->m_pLayoutData->GetLineCount() : 0;
+}
+
+// -----------------------------------------------------------------------
+
+Pair ToolBox::GetTextStartEnd( long nText ) const
+{
+ if( ! mpData->m_pLayoutData )
+ ImplFillLayoutData();
+ return mpData->m_pLayoutData ? mpData->m_pLayoutData->GetLineStartEnd( nText ) : Pair( -1, -1 );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ToolBox::GetDisplayItemId( long nText ) const
+{
+ USHORT nItemId = 0;
+ if( ! mpData->m_pLayoutData )
+ ImplFillLayoutData();
+ if( mpData->m_pLayoutData && nText >= 0 && (ULONG)nText < mpData->m_pLayoutData->m_aLineItemIds.size() )
+ nItemId = mpData->m_pLayoutData->m_aLineItemIds[nText];
+ return nItemId;
+}
+
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetDropdownClickHdl( const Link& rLink )
+{
+ mpData->maDropdownClickHdl = rLink;
+}
+
+const Link& ToolBox::GetDropdownClickHdl() const
+{
+ return mpData->maDropdownClickHdl;
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::SetMenuType( USHORT aType )
+{
+ if( aType != mpData->maMenuType )
+ {
+ mpData->maMenuType = aType;
+ if( IsFloatingMode() )
+ {
+ // the menu button may have to be moved into the decoration which changes the layout
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ pWrapper->ShowTitleButton( TITLE_BUTTON_MENU, ( aType & TOOLBOX_MENUTYPE_CUSTOMIZE) ? TRUE : FALSE );
+
+ mbFormat = TRUE;
+ ImplFormat();
+ ImplSetMinMaxFloatSize( this );
+ }
+ else
+ {
+ // trigger redraw of menu button
+ if( !mpData->maMenubuttonItem.maRect.IsEmpty() )
+ Invalidate(mpData->maMenubuttonItem.maRect);
+ }
+ }
+}
+
+USHORT ToolBox::GetMenuType() const
+{
+ return mpData->maMenuType;
+}
+
+BOOL ToolBox::IsMenuEnabled() const
+{
+ return mpData->maMenuType != TOOLBOX_MENUTYPE_NONE;
+}
+
+PopupMenu* ToolBox::GetMenu() const
+{
+ return mpData->mpMenu;
+}
+
+void ToolBox::SetMenuButtonHdl( const Link& rLink )
+{
+ mpData->maMenuButtonHdl = rLink;
+}
+
+const Link& ToolBox::GetMenuButtonHdl() const
+{
+ return mpData->maMenuButtonHdl;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::ImplHasClippedItems()
+{
+ // are any items currently clipped ?
+ ImplFormat();
+ std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
+ while ( it != mpData->m_aItems.end() )
+ {
+ if( it->IsClipped() )
+ return TRUE;
+ it++;
+ }
+ return FALSE;
+}
+
+void ToolBox::ImplUpdateCustomMenu()
+{
+ // fill clipped items into menu
+ if( !IsMenuEnabled() )
+ return;
+
+ PopupMenu *pMenu = GetMenu();
+
+ USHORT i = 0;
+ // remove old entries
+ while( i < pMenu->GetItemCount() )
+ {
+ if( pMenu->GetItemId( i ) >= TOOLBOX_MENUITEM_START )
+ {
+ pMenu->RemoveItem( i );
+ i = 0;
+ }
+ else
+ i++;
+ }
+
+ // add menu items, starting from the end and inserting at pos 0
+ if ( !mpData->m_aItems.empty() )
+ {
+ for ( std::vector< ImplToolItem >::reverse_iterator it(mpData->m_aItems.rbegin());
+ it != mpData->m_aItems.rend(); ++it)
+ {
+ if( it->IsClipped() )
+ {
+ USHORT id = it->mnId + TOOLBOX_MENUITEM_START;
+ pMenu->InsertItem( id, it->maText, it->maImage, 0, 0 );
+ pMenu->EnableItem( id, it->mbEnabled );
+ pMenu->CheckItem( id, it->meState == STATE_CHECK );
+ }
+ }
+ }
+}
+
+IMPL_LINK( ToolBox, ImplCustomMenuListener, VclMenuEvent*, pEvent )
+{
+ if( pEvent->GetMenu() == GetMenu() && pEvent->GetId() == VCLEVENT_MENU_SELECT )
+ {
+ USHORT id = GetMenu()->GetItemId( pEvent->GetItemPos() );
+ if( id >= TOOLBOX_MENUITEM_START )
+ TriggerItem( id - TOOLBOX_MENUITEM_START, FALSE, FALSE );
+ }
+ return 0;
+}
+
+IMPL_LINK( ToolBox, ImplCallExecuteCustomMenu, void*, EMPTYARG )
+{
+ mpData->mnEventId = 0;
+ ImplExecuteCustomMenu();
+ return 0;
+}
+
+void ToolBox::ImplExecuteCustomMenu()
+{
+ if( IsMenuEnabled() )
+ {
+ if( GetMenuType() & TOOLBOX_MENUTYPE_CUSTOMIZE )
+ // call button handler to allow for menu customization
+ mpData->maMenuButtonHdl.Call( this );
+
+ // register handler
+ GetMenu()->AddEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) );
+
+ // make sure all disabled entries will be shown
+ GetMenu()->SetMenuFlags(
+ GetMenu()->GetMenuFlags() | MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES );
+
+ // toolbox might be destroyed during execute
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+ ImplDelData aBorderDel;
+ bool bBorderDel = false;
+
+ Window *pWin = this;
+ Rectangle aMenuRect = mpData->maMenubuttonItem.maRect;
+ if( IsFloatingMode() )
+ {
+ // custom menu is placed in the decoration
+ ImplBorderWindow *pBorderWin = dynamic_cast<ImplBorderWindow*>( GetWindow( WINDOW_BORDER ) );
+ if( pBorderWin && !pBorderWin->GetMenuRect().IsEmpty() )
+ {
+ pWin = pBorderWin;
+ aMenuRect = pBorderWin->GetMenuRect();
+ pWin->ImplAddDel( &aBorderDel );
+ bBorderDel = true;
+ }
+ }
+
+ USHORT uId = GetMenu()->Execute( pWin, Rectangle( ImplGetPopupPosition( aMenuRect, Size() ), Size() ),
+ POPUPMENU_EXECUTE_DOWN | POPUPMENU_NOMOUSEUPCLOSE );
+
+ if ( aDelData.IsDelete() )
+ return;
+ ImplRemoveDel( &aDelData );
+
+ if( GetMenu() )
+ GetMenu()->RemoveEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) );
+ if( bBorderDel )
+ {
+ if( aBorderDel.IsDelete() )
+ return;
+ pWin->ImplRemoveDel( &aBorderDel );
+ }
+
+ pWin->Invalidate( aMenuRect );
+
+ if( uId )
+ GrabFocusToDocument();
+ }
+}
+
+void ToolBox::ExecuteCustomMenu()
+{
+ if( IsMenuEnabled() )
+ {
+ // handle custom menu asynchronously
+ // to avoid problems if the toolbox is closed during menu execute
+ ImplUpdateCustomMenu();
+ Application::PostUserEvent( mpData->mnEventId, LINK( this, ToolBox, ImplCallExecuteCustomMenu ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// checks override first, useful during calculation of sizes
+BOOL ToolBox::ImplIsFloatingMode() const
+{
+ DBG_ASSERT( !(mpData->mbAssumeDocked && mpData->mbAssumeFloating),
+ "ToolBox::ImplIsFloatingMode(): cannot assume docked and floating" );
+
+ if( mpData->mbAssumeDocked )
+ return FALSE;
+ else if( mpData->mbAssumeFloating )
+ return TRUE;
+ else
+ return IsFloatingMode();
+}
+
+// checks override first, useful during calculation of sizes
+BOOL ToolBox::ImplIsInPopupMode() const
+{
+ if( mpData->mbAssumePopupMode )
+ return TRUE;
+ else
+ {
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ return ( pWrapper && pWrapper->GetFloatingWindow() && pWrapper->GetFloatingWindow()->IsInPopupMode() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ToolBox::Lock( BOOL bLock )
+{
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( !pWrapper )
+ return;
+ if( mpData->mbIsLocked != bLock )
+ {
+ mpData->mbIsLocked = bLock;
+ if( !ImplIsFloatingMode() )
+ {
+ mbCalc = TRUE;
+ mbFormat = TRUE;
+ SetSizePixel( CalcWindowSizePixel(1) );
+ Invalidate();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ToolBox::AlwaysLocked()
+{
+ // read config item to determine toolbox behaviour, used for subtoolbars
+
+ static int nAlwaysLocked = -1;
+
+ if( nAlwaysLocked == -1 )
+ {
+ nAlwaysLocked = 0; // ask configuration only once
+
+ utl::OConfigurationNode aNode = utl::OConfigurationTreeRoot::tryCreateWithServiceFactory(
+ vcl::unohelper::GetMultiServiceFactory(),
+ OUString::createFromAscii( "/org.openoffice.Office.UI.GlobalSettings/Toolbars" ) ); // note: case sensisitive !
+ if ( aNode.isValid() )
+ {
+ // feature enabled ?
+ BOOL bStatesEnabled = BOOL();
+ ::com::sun::star::uno::Any aValue = aNode.getNodeValue( OUString::createFromAscii( "StatesEnabled" ) );
+ if( aValue >>= bStatesEnabled )
+ {
+ if( bStatesEnabled == TRUE )
+ {
+ // now read the locking state
+ utl::OConfigurationNode aNode2 = utl::OConfigurationTreeRoot::tryCreateWithServiceFactory(
+ vcl::unohelper::GetMultiServiceFactory(),
+ OUString::createFromAscii( "/org.openoffice.Office.UI.GlobalSettings/Toolbars/States" ) ); // note: case sensisitive !
+
+ BOOL bLocked = BOOL();
+ ::com::sun::star::uno::Any aValue2 = aNode2.getNodeValue( OUString::createFromAscii( "Locked" ) );
+ if( aValue2 >>= bLocked )
+ nAlwaysLocked = (bLocked == TRUE) ? 1 : 0;
+ }
+ }
+ }
+ }
+
+ return nAlwaysLocked == 1 ? TRUE : FALSE;
+}
+
+BOOL ToolBox::WillUsePopupMode() const
+{
+ return mpData->mbWillUsePopupMode;
+}
+
+void ToolBox::WillUsePopupMode( BOOL b )
+{
+ mpData->mbWillUsePopupMode = b;
+}
+
+void ToolBox::ImplUpdateImageList()
+{
+ if (mpData->mpImageListProvider != NULL)
+ {
+ BOOL bHC = GetSettings().GetStyleSettings().GetHighContrastMode();
+ try
+ {
+ ImageListType eType = bHC ? vcl::HIGHCONTRAST_YES : vcl::HIGHCONTRAST_NO;
+
+ if (eType != mpData->meImageListType)
+ {
+ vcl::IImageListProvider* pImageListProvider = mpData->mpImageListProvider;
+ SetImageList( pImageListProvider->getImageList(eType) );
+ mpData->meImageListType = eType;
+ }
+ }
+ catch (com::sun::star::lang::IllegalArgumentException &) {}
+ }
+}
+
+void ToolBox::SetImageListProvider(vcl::IImageListProvider* _pProvider)
+{
+ mpData->mpImageListProvider = _pProvider;
+ ImplUpdateImageList();
+}
+// -----------------------------------------------------------------------
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
new file mode 100644
index 000000000000..adedbde4c0f2
--- /dev/null
+++ b/vcl/source/window/window.cxx
@@ -0,0 +1,9972 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#ifndef _SV_SVSYS_HXX
+#include "svsys.h"
+#endif
+#include "vcl/salframe.hxx"
+#include "vcl/salobj.hxx"
+#include "vcl/salinst.hxx"
+#include "vcl/salgtype.hxx"
+#include "vcl/salgdi.hxx"
+#include "vcl/salctrlhandle.hxx"
+
+#include "vcl/unohelp.hxx"
+#include "tools/time.hxx"
+#include "tools/debug.hxx"
+#ifndef _SV_RC_H
+#include "tools/rc.h"
+#endif
+#include "vcl/svdata.hxx"
+#include "vcl/windata.hxx"
+#include "vcl/dbggui.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/outdev.h"
+#include "vcl/region.h"
+#include "vcl/event.hxx"
+#include "vcl/help.hxx"
+#include "vcl/cursor.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/window.h"
+#include "vcl/window.hxx"
+#include "vcl/syswin.hxx"
+#include "vcl/syschild.hxx"
+#include "vcl/brdwin.hxx"
+#include "vcl/helpwin.hxx"
+#include "vcl/dockwin.hxx"
+#include "vcl/menu.hxx"
+#include "vcl/wrkwin.hxx"
+#include "vcl/wall.hxx"
+#include "vcl/gradient.hxx"
+#include "vcl/toolbox.h"
+#include "unotools/fontcfg.hxx"
+#include "vcl/sysdata.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/button.hxx" // Button::GetStandardText
+#include "vcl/taskpanelist.hxx"
+#include "com/sun/star/awt/XWindowPeer.hpp"
+#include "com/sun/star/rendering/XCanvas.hpp"
+#include "com/sun/star/rendering/XSpriteCanvas.hpp"
+#include "com/sun/star/awt/XWindow.hpp"
+#include "comphelper/processfactory.hxx"
+#include "com/sun/star/datatransfer/dnd/XDragSource.hpp"
+#include "com/sun/star/datatransfer/dnd/XDropTarget.hpp"
+#include "com/sun/star/datatransfer/clipboard/XClipboard.hpp"
+#include "com/sun/star/awt/XTopWindow.hpp"
+#include "com/sun/star/awt/XDisplayConnection.hpp"
+#include "com/sun/star/lang/XInitialization.hpp"
+#include "com/sun/star/lang/XComponent.hpp"
+#include "com/sun/star/lang/XServiceName.hpp"
+#include "com/sun/star/accessibility/XAccessible.hpp"
+#include "com/sun/star/accessibility/AccessibleRole.hpp"
+
+#include "vcl/dialog.hxx"
+#include "vcl/unowrap.hxx"
+#include "vcl/dndlcon.hxx"
+#include "vcl/dndevdis.hxx"
+#include "vcl/impbmpconv.hxx"
+#include "unotools/confignode.hxx"
+#include "vcl/gdimtf.hxx"
+
+#include "vcl/pdfextoutdevdata.hxx"
+#include "vcl/lazydelete.hxx"
+
+#include <set>
+#include <typeinfo>
+
+using namespace rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::datatransfer::dnd;
+using namespace ::com::sun::star;
+using namespace com::sun;
+
+using ::com::sun::star::awt::XTopWindow;
+
+// =======================================================================
+
+DBG_NAME( Window )
+
+// =======================================================================
+
+#define IMPL_PAINT_PAINT ((USHORT)0x0001)
+#define IMPL_PAINT_PAINTALL ((USHORT)0x0002)
+#define IMPL_PAINT_PAINTALLCHILDS ((USHORT)0x0004)
+#define IMPL_PAINT_PAINTCHILDS ((USHORT)0x0008)
+#define IMPL_PAINT_ERASE ((USHORT)0x0010)
+#define IMPL_PAINT_CHECKRTL ((USHORT)0x0020)
+
+// -----------------------------------------------------------------------
+
+typedef Window* PWINDOW;
+
+// -----------------------------------------------------------------------
+
+struct ImplCalcToTopData
+{
+ ImplCalcToTopData* mpNext;
+ Window* mpWindow;
+ Region* mpInvalidateRegion;
+};
+
+struct ImplAccessibleInfos
+{
+ USHORT nAccessibleRole;
+ String* pAccessibleName;
+ String* pAccessibleDescription;
+
+ ImplAccessibleInfos()
+ {
+ nAccessibleRole = 0xFFFF;
+ pAccessibleName = NULL;
+ pAccessibleDescription = NULL;
+ }
+
+ ~ImplAccessibleInfos()
+ {
+ delete pAccessibleName;
+ delete pAccessibleDescription;
+ }
+};
+
+// -----------------------------------------------------------------------
+
+WindowImpl::WindowImpl()
+{
+}
+
+WindowImpl::~WindowImpl()
+{
+}
+
+
+// -----------------------------------------------------------------------
+
+// helper method to allow inline constructor even for pWindow!=NULL case
+void ImplDelData::AttachToWindow( const Window* pWindow )
+{
+ if( pWindow )
+ const_cast<Window*>(pWindow)->ImplAddDel( this );
+}
+
+// -----------------------------------------------------------------------
+
+// define dtor for ImplDelData
+ImplDelData::~ImplDelData()
+{
+ // #112873# auto remove of ImplDelData
+ // due to this code actively calling ImplRemoveDel() is not mandatory anymore
+ if( !mbDel && mpWindow )
+ {
+ // the window still exists but we were not removed
+ const_cast<Window*>(mpWindow)->ImplRemoveDel( this );
+ mpWindow = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+#ifdef DBG_UTIL
+const char* ImplDbgCheckWindow( const void* pObj )
+{
+ DBG_TESTSOLARMUTEX();
+
+ const Window* pWindow = (Window*)pObj;
+
+ if ( (pWindow->GetType() < WINDOW_FIRST) || (pWindow->GetType() > WINDOW_LAST) )
+ return "Window data overwrite";
+
+ // Fenster-Verkettung ueberpruefen
+ Window* pChild = pWindow->mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ if ( pChild->mpWindowImpl->mpParent != pWindow )
+ return "Child-Window-Parent wrong";
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+
+ return NULL;
+}
+#endif
+
+// =======================================================================
+
+void Window::ImplInitAppFontData( Window* pWindow )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ long nTextHeight = pWindow->GetTextHeight();
+ long nTextWidth = pWindow->GetTextWidth( XubString( RTL_CONSTASCII_USTRINGPARAM( "aemnnxEM" ) ) );
+ long nSymHeight = nTextHeight*4;
+ // Falls Font zu schmal ist, machen wir die Basis breiter,
+ // damit die Dialoge symetrisch aussehen und nicht zu schmal
+ // werden. Wenn der Dialog die gleiche breite hat, geben wir
+ // noch etwas Spielraum dazu, da etwas mehr Platz besser ist.
+ if ( nSymHeight > nTextWidth )
+ nTextWidth = nSymHeight;
+ else if ( nSymHeight+5 > nTextWidth )
+ nTextWidth = nSymHeight+5;
+ pSVData->maGDIData.mnAppFontX = nTextWidth * 10 / 8;
+ pSVData->maGDIData.mnAppFontY = nTextHeight * 10;
+
+ // FIXME: this is currently only on aqua, check with other
+ // platforms
+ if( pSVData->maNWFData.mbNoFocusRects )
+ {
+ // try to find out wether there is a large correction
+ // of control sizes, if yes, make app font scalings larger
+ // so dialog positioning is not completely off
+ ImplControlValue aControlValue;
+ Rectangle aCtrlRegion( Point(), Size( nTextWidth < 10 ? 10 : nTextWidth, nTextHeight < 10 ? 10 : nTextHeight ) );
+ Rectangle aBoundingRgn( aCtrlRegion );
+ Rectangle aContentRgn( aCtrlRegion );
+ if( pWindow->GetNativeControlRegion( CTRL_EDITBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ // comment: the magical +6 is for the extra border in bordered
+ // (which is the standard) edit fields
+ if( aContentRgn.GetHeight() - nTextHeight > (nTextHeight+4)/4 )
+ pSVData->maGDIData.mnAppFontY = (aContentRgn.GetHeight()-4) * 10;
+ }
+ }
+
+
+ pSVData->maGDIData.mnRealAppFontX = pSVData->maGDIData.mnAppFontX;
+ if ( pSVData->maAppData.mnDialogScaleX )
+ pSVData->maGDIData.mnAppFontX += (pSVData->maGDIData.mnAppFontX*pSVData->maAppData.mnDialogScaleX)/100;
+}
+
+// -----------------------------------------------------------------------
+
+bool Window::ImplCheckUIFont( const Font& rFont )
+{
+ if( ImplGetSVData()->maGDIData.mbNativeFontConfig )
+ return true;
+
+ String aTestText;
+ aTestText.Append( Button::GetStandardText( BUTTON_OK ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_CANCEL ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_YES ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_NO ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_RETRY ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_HELP ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_CLOSE ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_MORE ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_LESS ) );
+ aTestText.Append( Button::GetStandardText( BUTTON_ABORT ) );
+
+ return HasGlyphs( rFont, aTestText ) >= aTestText.Len();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateGlobalSettings( AllSettings& rSettings, BOOL bCallHdl )
+{
+ // reset high contrast to false, so the system can either update it
+ // or AutoDetectSystemHC can kick in (see below)
+ StyleSettings aTmpSt( rSettings.GetStyleSettings() );
+ aTmpSt.SetHighContrastMode( FALSE );
+ rSettings.SetStyleSettings( aTmpSt );
+ ImplGetFrame()->UpdateSettings( rSettings );
+
+ // Verify availability of the configured UI font, otherwise choose "Andale Sans UI"
+ String aUserInterfaceFont;
+ bool bUseSystemFont = rSettings.GetStyleSettings().GetUseSystemUIFonts();
+
+ // check whether system UI font can display a typical UI text
+ if( bUseSystemFont )
+ bUseSystemFont = ImplCheckUIFont( rSettings.GetStyleSettings().GetAppFont() );
+
+ if ( !bUseSystemFont )
+ {
+ ImplInitFontList();
+ String aConfigFont = utl::DefaultFontConfiguration::get()->getUserInterfaceFont( rSettings.GetUILocale() );
+ xub_StrLen nIndex = 0;
+ while( nIndex != STRING_NOTFOUND )
+ {
+ String aName( aConfigFont.GetToken( 0, ';', nIndex ) );
+ if ( aName.Len() && mpWindowImpl->mpFrameData->mpFontList->FindFontFamily( aName ) )
+ {
+ aUserInterfaceFont = aConfigFont;
+ break;
+ }
+ }
+
+ if ( ! aUserInterfaceFont.Len() )
+ {
+ String aFallbackFont (RTL_CONSTASCII_USTRINGPARAM( "Andale Sans UI" ));
+ if ( mpWindowImpl->mpFrameData->mpFontList->FindFontFamily( aFallbackFont ) )
+ aUserInterfaceFont = aFallbackFont;
+ }
+ }
+
+ if ( !bUseSystemFont && aUserInterfaceFont.Len() )
+ {
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ Font aFont = aStyleSettings.GetAppFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetAppFont( aFont );
+ aFont = aStyleSettings.GetHelpFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetHelpFont( aFont );
+ aFont = aStyleSettings.GetTitleFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetTitleFont( aFont );
+ aFont = aStyleSettings.GetFloatTitleFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetFloatTitleFont( aFont );
+ aFont = aStyleSettings.GetMenuFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetMenuFont( aFont );
+ aFont = aStyleSettings.GetToolFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetToolFont( aFont );
+ aFont = aStyleSettings.GetLabelFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetLabelFont( aFont );
+ aFont = aStyleSettings.GetInfoFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetInfoFont( aFont );
+ aFont = aStyleSettings.GetRadioCheckFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetRadioCheckFont( aFont );
+ aFont = aStyleSettings.GetPushButtonFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetPushButtonFont( aFont );
+ aFont = aStyleSettings.GetFieldFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetFieldFont( aFont );
+ aFont = aStyleSettings.GetIconFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetIconFont( aFont );
+ aFont = aStyleSettings.GetGroupFont();
+ aFont.SetName( aUserInterfaceFont );
+ aStyleSettings.SetGroupFont( aFont );
+ rSettings.SetStyleSettings( aStyleSettings );
+ }
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ // #97047: Force all fonts except Menu and Help to a fixed height
+ // to avoid UI scaling due to large fonts
+ // - but allow bigger fonts on bigger screens (i16682, i21238)
+ // dialogs were designed to fit 800x600 with an 8pt font, so scale accordingly
+ int maxFontheight = 9; // #107886#: 9 is default for some asian systems, so always allow if requested
+ if( GetDesktopRectPixel().getHeight() > 600 )
+ maxFontheight = (int) ((( 8.0 * (double) GetDesktopRectPixel().getHeight()) / 600.0) + 1.5);
+
+ Font aFont = aStyleSettings.GetMenuFont();
+ int defFontheight = aFont.GetHeight();
+ if( defFontheight > maxFontheight )
+ defFontheight = maxFontheight;
+
+ // if the UI is korean, chinese or another locale
+ // where the system font size is kown to be often too small to
+ // generate readable fonts enforce a minimum font size of 9 points
+ bool bBrokenLangFontHeight = false;
+ static const LanguageType eBrokenSystemFontSizeLanguages[] =
+ { LANGUAGE_KOREAN, LANGUAGE_KOREAN_JOHAB,
+ LANGUAGE_CHINESE_HONGKONG, LANGUAGE_CHINESE_MACAU, LANGUAGE_CHINESE_SIMPLIFIED, LANGUAGE_CHINESE_SINGAPORE, LANGUAGE_CHINESE_TRADITIONAL
+ };
+ static std::set< LanguageType > aBrokenSystemFontSizeLanguagesSet(
+ eBrokenSystemFontSizeLanguages,
+ eBrokenSystemFontSizeLanguages +
+ (sizeof(eBrokenSystemFontSizeLanguages)/sizeof(eBrokenSystemFontSizeLanguages[0]))
+ );
+ LanguageType aLang = Application::GetSettings().GetUILanguage();
+ if( aBrokenSystemFontSizeLanguagesSet.find( aLang ) != aBrokenSystemFontSizeLanguagesSet.end() )
+ {
+ defFontheight = Max(9, defFontheight);
+ bBrokenLangFontHeight = true;
+ }
+
+ // i22098, toolfont will be scaled differently to avoid bloated rulers and status bars for big fonts
+ int toolfontheight = defFontheight;
+ if( toolfontheight > 9 )
+ toolfontheight = (defFontheight+8) / 2;
+
+ aFont = aStyleSettings.GetAppFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetAppFont( aFont );
+ aFont = aStyleSettings.GetTitleFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetTitleFont( aFont );
+ aFont = aStyleSettings.GetFloatTitleFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetFloatTitleFont( aFont );
+ // keep menu and help font size from system unless in broken locale size
+ if( bBrokenLangFontHeight )
+ {
+ aFont = aStyleSettings.GetMenuFont();
+ if( aFont.GetHeight() < defFontheight )
+ {
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetMenuFont( aFont );
+ }
+ aFont = aStyleSettings.GetHelpFont();
+ if( aFont.GetHeight() < defFontheight )
+ {
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetHelpFont( aFont );
+ }
+ }
+
+ // use different height for toolfont
+ aFont = aStyleSettings.GetToolFont();
+ aFont.SetHeight( toolfontheight );
+ aStyleSettings.SetToolFont( aFont );
+
+ aFont = aStyleSettings.GetLabelFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetLabelFont( aFont );
+ aFont = aStyleSettings.GetInfoFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetInfoFont( aFont );
+ aFont = aStyleSettings.GetRadioCheckFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetRadioCheckFont( aFont );
+ aFont = aStyleSettings.GetPushButtonFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetPushButtonFont( aFont );
+ aFont = aStyleSettings.GetFieldFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetFieldFont( aFont );
+ aFont = aStyleSettings.GetIconFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetIconFont( aFont );
+ aFont = aStyleSettings.GetGroupFont();
+ aFont.SetHeight( defFontheight );
+ aStyleSettings.SetGroupFont( aFont );
+
+ // set workspace gradient to black in dark themes
+ if( aStyleSettings.GetWindowColor().IsDark() )
+ aStyleSettings.SetWorkspaceGradient( Wallpaper( Color( COL_BLACK ) ) );
+ else
+ {
+ Gradient aGrad( GRADIENT_LINEAR, DEFAULT_WORKSPACE_GRADIENT_START_COLOR, DEFAULT_WORKSPACE_GRADIENT_END_COLOR );
+ aStyleSettings.SetWorkspaceGradient( Wallpaper( aGrad ) );
+ }
+
+ rSettings.SetStyleSettings( aStyleSettings );
+
+
+ // auto detect HC mode; if the system already set it to "yes"
+ // (see above) then accept that
+ if( !rSettings.GetStyleSettings().GetHighContrastMode() )
+ {
+ sal_Bool bTmp = sal_False, bAutoHCMode = sal_True;
+ utl::OConfigurationNode aNode = utl::OConfigurationTreeRoot::tryCreateWithServiceFactory(
+ vcl::unohelper::GetMultiServiceFactory(),
+ OUString::createFromAscii( "org.openoffice.Office.Common/Accessibility" ) ); // note: case sensisitive !
+ if ( aNode.isValid() )
+ {
+ ::com::sun::star::uno::Any aValue = aNode.getNodeValue( OUString::createFromAscii( "AutoDetectSystemHC" ) );
+ if( aValue >>= bTmp )
+ bAutoHCMode = bTmp;
+ }
+ if( bAutoHCMode )
+ {
+ if( rSettings.GetStyleSettings().GetFaceColor().IsDark()
+ || rSettings.GetStyleSettings().GetWindowColor().IsDark() )
+ {
+ aStyleSettings = rSettings.GetStyleSettings();
+ aStyleSettings.SetHighContrastMode( TRUE );
+ rSettings.SetStyleSettings( aStyleSettings );
+ }
+ }
+ }
+
+ static const char* pEnvHC = getenv( "SAL_FORCE_HC" );
+ if( pEnvHC && *pEnvHC )
+ {
+ aStyleSettings.SetHighContrastMode( TRUE );
+ rSettings.SetStyleSettings( aStyleSettings );
+ }
+
+#ifdef DBG_UTIL
+ // Evt. AppFont auf Fett schalten, damit man feststellen kann,
+ // ob fuer die Texte auf anderen Systemen genuegend Platz
+ // vorhanden ist
+ if ( DbgIsBoldAppFont() )
+ {
+ aStyleSettings = rSettings.GetStyleSettings();
+ aFont = aStyleSettings.GetAppFont();
+ aFont.SetWeight( WEIGHT_BOLD );
+ aStyleSettings.SetAppFont( aFont );
+ aFont = aStyleSettings.GetGroupFont();
+ aFont.SetWeight( WEIGHT_BOLD );
+ aStyleSettings.SetGroupFont( aFont );
+ aFont = aStyleSettings.GetLabelFont();
+ aFont.SetWeight( WEIGHT_BOLD );
+ aStyleSettings.SetLabelFont( aFont );
+ aFont = aStyleSettings.GetRadioCheckFont();
+ aFont.SetWeight( WEIGHT_BOLD );
+ aStyleSettings.SetRadioCheckFont( aFont );
+ aFont = aStyleSettings.GetPushButtonFont();
+ aFont.SetWeight( WEIGHT_BOLD );
+ aStyleSettings.SetPushButtonFont( aFont );
+ aFont = aStyleSettings.GetFieldFont();
+ aFont.SetWeight( WEIGHT_BOLD );
+ aStyleSettings.SetFieldFont( aFont );
+ aFont = aStyleSettings.GetIconFont();
+ aFont.SetWeight( WEIGHT_BOLD );
+ aStyleSettings.SetIconFont( aFont );
+ rSettings.SetStyleSettings( aStyleSettings );
+ }
+#endif
+
+ if ( bCallHdl )
+ GetpApp()->SystemSettingsChanging( rSettings, this );
+}
+
+// -----------------------------------------------------------------------
+
+MouseEvent ImplTranslateMouseEvent( const MouseEvent& rE, Window* pSource, Window* pDest )
+{
+ Point aPos = pSource->OutputToScreenPixel( rE.GetPosPixel() );
+ aPos = pDest->ScreenToOutputPixel( aPos );
+ return MouseEvent( aPos, rE.GetClicks(), rE.GetMode(), rE.GetButtons(), rE.GetModifier() );
+}
+
+// -----------------------------------------------------------------------
+
+CommandEvent ImplTranslateCommandEvent( const CommandEvent& rCEvt, Window* pSource, Window* pDest )
+{
+ if ( !rCEvt.IsMouseEvent() )
+ return rCEvt;
+
+ Point aPos = pSource->OutputToScreenPixel( rCEvt.GetMousePosPixel() );
+ aPos = pDest->ScreenToOutputPixel( aPos );
+ return CommandEvent( aPos, rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetData() );
+}
+
+// =======================================================================
+
+void Window::ImplInitWindowData( WindowType nType )
+{
+ mpWindowImpl = new WindowImpl;
+
+ meOutDevType = OUTDEV_WINDOW;
+
+ mpWindowImpl->maZoom = Fraction( 1, 1 );
+ mpWindowImpl->maWinRegion = Region( REGION_NULL );
+ mpWindowImpl->maWinClipRegion = Region( REGION_NULL );
+ mpWindowImpl->mpWinData = NULL; // Extra Window Data, that we dont need for all windows
+ mpWindowImpl->mpOverlapData = NULL; // Overlap Data
+ mpWindowImpl->mpFrameData = NULL; // Frame Data
+ mpWindowImpl->mpFrame = NULL; // Pointer to frame window
+ mpWindowImpl->mpSysObj = NULL;
+ mpWindowImpl->mpFrameWindow = NULL; // window to top level parent (same as frame window)
+ mpWindowImpl->mpOverlapWindow = NULL; // first overlap parent
+ mpWindowImpl->mpBorderWindow = NULL; // Border-Window
+ mpWindowImpl->mpClientWindow = NULL; // Client-Window of a FrameWindow
+ mpWindowImpl->mpParent = NULL; // parent (inkl. BorderWindow)
+ mpWindowImpl->mpRealParent = NULL; // real parent (exkl. BorderWindow)
+ mpWindowImpl->mpFirstChild = NULL; // first child window
+ mpWindowImpl->mpLastChild = NULL; // last child window
+ mpWindowImpl->mpFirstOverlap = NULL; // first overlap window (only set in overlap windows)
+ mpWindowImpl->mpLastOverlap = NULL; // last overlap window (only set in overlap windows)
+ mpWindowImpl->mpPrev = NULL; // prev window
+ mpWindowImpl->mpNext = NULL; // next window
+ mpWindowImpl->mpNextOverlap = NULL; // next overlap window of frame
+ mpWindowImpl->mpLastFocusWindow = NULL; // window for focus restore
+ mpWindowImpl->mpDlgCtrlDownWindow = NULL; // window for dialog control
+ mpWindowImpl->mpFirstDel = NULL; // Dtor notification list
+ mpWindowImpl->mpUserData = NULL; // user data
+ mpWindowImpl->mpCursor = NULL; // cursor
+ mpWindowImpl->mpControlFont = NULL; // font propertie
+ mpWindowImpl->mpVCLXWindow = NULL;
+ mpWindowImpl->mpAccessibleInfos = NULL;
+ mpWindowImpl->maControlForeground = Color( COL_TRANSPARENT ); // kein Foreground gesetzt
+ mpWindowImpl->maControlBackground = Color( COL_TRANSPARENT ); // kein Background gesetzt
+ mpWindowImpl->mnLeftBorder = 0; // left border
+ mpWindowImpl->mnTopBorder = 0; // top border
+ mpWindowImpl->mnRightBorder = 0; // right border
+ mpWindowImpl->mnBottomBorder = 0; // bottom border
+ mpWindowImpl->mnX = 0; // X-Position to Parent
+ mpWindowImpl->mnY = 0; // Y-Position to Parent
+ mpWindowImpl->mnAbsScreenX = 0; // absolute X-position on screen, used for RTL window positioning
+ mpWindowImpl->mnHelpId = 0; // help id
+ mpWindowImpl->mnUniqId = 0; // unique id
+ mpWindowImpl->mpChildClipRegion = NULL; // Child-Clip-Region when ClipChildren
+ mpWindowImpl->mpPaintRegion = NULL; // Paint-ClipRegion
+ mpWindowImpl->mnStyle = 0; // style (init in ImplInitWindow)
+ mpWindowImpl->mnPrevStyle = 0; // prevstyle (set in SetStyle)
+ mpWindowImpl->mnExtendedStyle = 0; // extended style (init in ImplInitWindow)
+ mpWindowImpl->mnPrevExtendedStyle = 0; // prevstyle (set in SetExtendedStyle)
+ mpWindowImpl->mnType = nType; // type
+ mpWindowImpl->mnGetFocusFlags = 0; // Flags fuer GetFocus()-Aufruf
+ mpWindowImpl->mnWaitCount = 0; // Wait-Count (>1 == Warte-MousePointer)
+ mpWindowImpl->mnPaintFlags = 0; // Flags for ImplCallPaint
+ mpWindowImpl->mnParentClipMode = 0; // Flags for Parent-ClipChildren-Mode
+ mpWindowImpl->mnActivateMode = 0; // Wird bei System/Overlap-Windows umgesetzt
+ mpWindowImpl->mnDlgCtrlFlags = 0; // DialogControl-Flags
+ mpWindowImpl->mnLockCount = 0; // LockCount
+ mpWindowImpl->meAlwaysInputMode = AlwaysInputNone; // neither AlwaysEnableInput nor AlwaysDisableInput called
+ mpWindowImpl->mbFrame = FALSE; // TRUE: Window is a frame window
+ mpWindowImpl->mbBorderWin = FALSE; // TRUE: Window is a border window
+ mpWindowImpl->mbOverlapWin = FALSE; // TRUE: Window is a overlap window
+ mpWindowImpl->mbSysWin = FALSE; // TRUE: SystemWindow is the base class
+ mpWindowImpl->mbDialog = FALSE; // TRUE: Dialog is the base class
+ mpWindowImpl->mbDockWin = FALSE; // TRUE: DockingWindow is the base class
+ mpWindowImpl->mbFloatWin = FALSE; // TRUE: FloatingWindow is the base class
+ mpWindowImpl->mbPushButton = FALSE; // TRUE: PushButton is the base class
+ mpWindowImpl->mbToolBox = FALSE; // TRUE: ToolBox is the base class
+ mpWindowImpl->mbMenuFloatingWindow= FALSE; // TRUE: MenuFloatingWindow is the base class
+ mpWindowImpl->mbToolbarFloatingWindow= FALSE; // TRUE: ImplPopupFloatWin is the base class, used for subtoolbars
+ mpWindowImpl->mbSplitter = FALSE; // TRUE: Splitter is the base class
+ mpWindowImpl->mbVisible = FALSE; // TRUE: Show( TRUE ) called
+ mpWindowImpl->mbOverlapVisible = FALSE; // TRUE: Hide called for visible window from ImplHideAllOverlapWindow()
+ mpWindowImpl->mbDisabled = FALSE; // TRUE: Enable( FALSE ) called
+ mpWindowImpl->mbInputDisabled = FALSE; // TRUE: EnableInput( FALSE ) called
+ mpWindowImpl->mbDropDisabled = FALSE; // TRUE: Drop is enabled
+ mpWindowImpl->mbNoUpdate = FALSE; // TRUE: SetUpdateMode( FALSE ) called
+ mpWindowImpl->mbNoParentUpdate = FALSE; // TRUE: SetParentUpdateMode( FALSE ) called
+ mpWindowImpl->mbActive = FALSE; // TRUE: Window Active
+ mpWindowImpl->mbParentActive = FALSE; // TRUE: OverlapActive from Parent
+ mpWindowImpl->mbReallyVisible = FALSE; // TRUE: this and all parents to an overlaped window are visible
+ mpWindowImpl->mbReallyShown = FALSE; // TRUE: this and all parents to an overlaped window are shown
+ mpWindowImpl->mbInInitShow = FALSE; // TRUE: we are in InitShow
+ mpWindowImpl->mbChildNotify = FALSE; // TRUE: ChildNotify
+ mpWindowImpl->mbChildPtrOverwrite = FALSE; // TRUE: PointerStyle overwrites Child-Pointer
+ mpWindowImpl->mbNoPtrVisible = FALSE; // TRUE: ShowPointer( FALSE ) called
+ mpWindowImpl->mbMouseMove = FALSE; // TRUE: BaseMouseMove called
+ mpWindowImpl->mbPaintFrame = FALSE; // TRUE: Paint is visible, but not painted
+ mpWindowImpl->mbInPaint = FALSE; // TRUE: Inside PaintHdl
+ mpWindowImpl->mbMouseButtonDown = FALSE; // TRUE: BaseMouseButtonDown called
+ mpWindowImpl->mbMouseButtonUp = FALSE; // TRUE: BaseMouseButtonUp called
+ mpWindowImpl->mbKeyInput = FALSE; // TRUE: BaseKeyInput called
+ mpWindowImpl->mbKeyUp = FALSE; // TRUE: BaseKeyUp called
+ mpWindowImpl->mbCommand = FALSE; // TRUE: BaseCommand called
+ mpWindowImpl->mbDefPos = TRUE; // TRUE: Position is not Set
+ mpWindowImpl->mbDefSize = TRUE; // TRUE: Size is not Set
+ mpWindowImpl->mbCallMove = TRUE; // TRUE: Move must be called by Show
+ mpWindowImpl->mbCallResize = TRUE; // TRUE: Resize must be called by Show
+ mpWindowImpl->mbWaitSystemResize = TRUE; // TRUE: Wait for System-Resize
+ mpWindowImpl->mbInitWinClipRegion = TRUE; // TRUE: Calc Window Clip Region
+ mpWindowImpl->mbInitChildRegion = FALSE; // TRUE: InitChildClipRegion
+ mpWindowImpl->mbWinRegion = FALSE; // TRUE: Window Region
+ mpWindowImpl->mbClipChildren = FALSE; // TRUE: Child-Fenster muessen evt. geclippt werden
+ mpWindowImpl->mbClipSiblings = FALSE; // TRUE: Nebeneinanderliegende Child-Fenster muessen evt. geclippt werden
+ mpWindowImpl->mbChildTransparent = FALSE; // TRUE: Child-Fenster duerfen transparent einschalten (inkl. Parent-CLIPCHILDREN)
+ mpWindowImpl->mbPaintTransparent = FALSE; // TRUE: Paints muessen auf Parent ausgeloest werden
+ mpWindowImpl->mbMouseTransparent = FALSE; // TRUE: Window is transparent for Mouse
+ mpWindowImpl->mbDlgCtrlStart = FALSE; // TRUE: Ab hier eigenes Dialog-Control
+ mpWindowImpl->mbFocusVisible = FALSE; // TRUE: Focus Visible
+ mpWindowImpl->mbUseNativeFocus = FALSE;
+ mpWindowImpl->mbNativeFocusVisible= FALSE; // TRUE: native Focus Visible
+ mpWindowImpl->mbInShowFocus = FALSE; // prevent recursion
+ mpWindowImpl->mbInHideFocus = FALSE; // prevent recursion
+ mpWindowImpl->mbTrackVisible = FALSE; // TRUE: Tracking Visible
+ mpWindowImpl->mbControlForeground = FALSE; // TRUE: Foreground-Property set
+ mpWindowImpl->mbControlBackground = FALSE; // TRUE: Background-Property set
+ mpWindowImpl->mbAlwaysOnTop = FALSE; // TRUE: immer vor allen anderen normalen Fenstern sichtbar
+ mpWindowImpl->mbCompoundControl = FALSE; // TRUE: Zusammengesetztes Control => Listener...
+ mpWindowImpl->mbCompoundControlHasFocus = FALSE; // TRUE: Zusammengesetztes Control hat irgendwo den Focus
+ mpWindowImpl->mbPaintDisabled = FALSE; // TRUE: Paint soll nicht ausgefuehrt werden
+ mpWindowImpl->mbAllResize = FALSE; // TRUE: Auch ResizeEvents mit 0,0 schicken
+ mpWindowImpl->mbInDtor = FALSE; // TRUE: Wir befinden uns im Window-Dtor
+ mpWindowImpl->mbExtTextInput = FALSE; // TRUE: ExtTextInput-Mode is active
+ mpWindowImpl->mbInFocusHdl = FALSE; // TRUE: Innerhalb vom GetFocus-Handler
+ mpWindowImpl->mbCreatedWithToolkit = FALSE;
+ mpWindowImpl->mbSuppressAccessibilityEvents = FALSE; // TRUE: do not send any accessibility events
+ mpWindowImpl->mbDrawSelectionBackground = FALSE; // TRUE: draws transparent window background to indicate (toolbox) selection
+ mpWindowImpl->mbIsInTaskPaneList = FALSE; // TRUE: window was added to the taskpanelist in the topmost system window
+ mpWindowImpl->mnNativeBackground = 0; // initialize later, depends on type
+ mpWindowImpl->mbCallHandlersDuringInputDisabled = FALSE; // TRUE: call event handlers even if input is disabled
+ mpWindowImpl->mbDisableAccessibleLabelForRelation = FALSE; // TRUE: do not set LabelFor relation on accessible objects
+ mpWindowImpl->mbDisableAccessibleLabeledByRelation = FALSE; // TRUE: do not set LabeledBy relation on accessible objects
+ mpWindowImpl->mbHelpTextDynamic = FALSE; // TRUE: append help id in HELP_DEBUG case
+ mpWindowImpl->mbFakeFocusSet = FALSE; // TRUE: pretend as if the window has focus.
+
+ mbEnableRTL = Application::GetSettings().GetLayoutRTL(); // TRUE: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInit( Window* pParent, WinBits nStyle, const ::com::sun::star::uno::Any& /*aSystemWorkWindowToken*/ )
+{
+ ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData )
+{
+ DBG_ASSERT( mpWindowImpl->mbFrame || pParent, "Window::Window(): pParent == NULL" );
+
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pRealParent = pParent;
+
+ // 3D-Look vererben
+ if ( !mpWindowImpl->mbOverlapWin && pParent && (pParent->GetStyle() & WB_3DLOOK) )
+ nStyle |= WB_3DLOOK;
+
+ // create border window if necessary
+ if ( !mpWindowImpl->mbFrame && !mpWindowImpl->mbBorderWin && !mpWindowImpl->mpBorderWindow
+ && (nStyle & (WB_BORDER | WB_SYSTEMCHILDWINDOW) ) )
+ {
+ USHORT nBorderTypeStyle = 0;
+ if( (nStyle & WB_SYSTEMCHILDWINDOW) )
+ {
+ // handle WB_SYSTEMCHILDWINDOW
+ // these should be analogous to a top level frame; meaning they
+ // should have a border window with style BORDERWINDOW_STYLE_FRAME
+ // which controls their size
+ nBorderTypeStyle |= BORDERWINDOW_STYLE_FRAME;
+ nStyle |= WB_BORDER;
+ }
+ ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle & (WB_BORDER | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_NEEDSFOCUS), nBorderTypeStyle );
+ ((Window*)pBorderWin)->mpWindowImpl->mpClientWindow = this;
+ pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ mpWindowImpl->mpBorderWindow = pBorderWin;
+ pParent = mpWindowImpl->mpBorderWindow;
+ }
+ else if( !mpWindowImpl->mbFrame && ! pParent )
+ {
+ mpWindowImpl->mbOverlapWin = TRUE;
+ mpWindowImpl->mbFrame = TRUE;
+ }
+
+ // insert window in list
+ ImplInsertWindow( pParent );
+ mpWindowImpl->mnStyle = nStyle;
+
+ // Overlap-Window-Daten
+ if ( mpWindowImpl->mbOverlapWin )
+ {
+ mpWindowImpl->mpOverlapData = new ImplOverlapData;
+ mpWindowImpl->mpOverlapData->mpSaveBackDev = NULL;
+ mpWindowImpl->mpOverlapData->mpSaveBackRgn = NULL;
+ mpWindowImpl->mpOverlapData->mpNextBackWin = NULL;
+ mpWindowImpl->mpOverlapData->mnSaveBackSize = 0;
+ mpWindowImpl->mpOverlapData->mbSaveBack = FALSE;
+ mpWindowImpl->mpOverlapData->mnTopLevel = 1;
+ }
+
+ if( pParent && ! mpWindowImpl->mbFrame )
+ mbEnableRTL = pParent->mbEnableRTL;
+
+ // test for frame creation
+ if ( mpWindowImpl->mbFrame )
+ {
+ // create frame
+ ULONG nFrameStyle = 0;
+
+ if ( nStyle & WB_MOVEABLE )
+ nFrameStyle |= SAL_FRAME_STYLE_MOVEABLE;
+ if ( nStyle & WB_SIZEABLE )
+ nFrameStyle |= SAL_FRAME_STYLE_SIZEABLE;
+ if ( nStyle & WB_CLOSEABLE )
+ nFrameStyle |= SAL_FRAME_STYLE_CLOSEABLE;
+ if ( nStyle & WB_APP )
+ nFrameStyle |= SAL_FRAME_STYLE_DEFAULT;
+ // check for undecorated floating window
+ if( // 1. floating windows that are not moveable/sizeable (only closeable allowed)
+ ( !(nFrameStyle & ~SAL_FRAME_STYLE_CLOSEABLE) &&
+ ( mpWindowImpl->mbFloatWin || ((GetType() == WINDOW_BORDERWINDOW) && ((ImplBorderWindow*)this)->mbFloatWindow) || (nStyle & WB_SYSTEMFLOATWIN) ) ) ||
+ // 2. borderwindows of floaters with ownerdraw decoration
+ ( ((GetType() == WINDOW_BORDERWINDOW) && ((ImplBorderWindow*)this)->mbFloatWindow && (nStyle & WB_OWNERDRAWDECORATION) ) ) )
+ {
+ nFrameStyle = SAL_FRAME_STYLE_FLOAT;
+ if( nStyle & WB_OWNERDRAWDECORATION )
+ nFrameStyle |= (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_NOSHADOW);
+ if( nStyle & WB_NEEDSFOCUS )
+ nFrameStyle |= SAL_FRAME_STYLE_FLOAT_FOCUSABLE;
+ }
+ else if( mpWindowImpl->mbFloatWin )
+ nFrameStyle |= SAL_FRAME_STYLE_TOOLWINDOW;
+
+ if( nStyle & WB_INTROWIN )
+ nFrameStyle |= SAL_FRAME_STYLE_INTRO;
+ if( nStyle & WB_TOOLTIPWIN )
+ nFrameStyle |= SAL_FRAME_STYLE_TOOLTIP;
+
+ if( nStyle & WB_NOSHADOW )
+ nFrameStyle |= SAL_FRAME_STYLE_NOSHADOW;
+
+ if( nStyle & WB_SYSTEMCHILDWINDOW )
+ nFrameStyle |= SAL_FRAME_STYLE_SYSTEMCHILD;
+
+ switch (mpWindowImpl->mnType)
+ {
+ case WINDOW_DIALOG:
+ case WINDOW_TABDIALOG:
+ case WINDOW_MODALDIALOG:
+ case WINDOW_MODELESSDIALOG:
+ case WINDOW_MESSBOX:
+ case WINDOW_INFOBOX:
+ case WINDOW_WARNINGBOX:
+ case WINDOW_ERRORBOX:
+ case WINDOW_QUERYBOX:
+ nFrameStyle |= SAL_FRAME_STYLE_DIALOG;
+ default:
+ break;
+ }
+
+ SalFrame* pParentFrame = NULL;
+ if ( pParent )
+ pParentFrame = pParent->mpWindowImpl->mpFrame;
+ SalFrame* pFrame;
+ if ( pSystemParentData )
+ pFrame = pSVData->mpDefInst->CreateChildFrame( pSystemParentData, nFrameStyle | SAL_FRAME_STYLE_PLUG );
+ else
+ pFrame = pSVData->mpDefInst->CreateFrame( pParentFrame, nFrameStyle );
+ if ( !pFrame )
+ {
+ // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario)
+ throw ::com::sun::star::uno::RuntimeException(
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Could not create system window!" ) ),
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+ //GetpApp()->Exception( EXC_SYSOBJNOTCREATED );
+ }
+
+ pFrame->SetCallback( this, ImplWindowFrameProc );
+
+ // set window frame data
+ mpWindowImpl->mpFrameData = new ImplFrameData;
+ mpWindowImpl->mpFrame = pFrame;
+ mpWindowImpl->mpFrameWindow = this;
+ mpWindowImpl->mpOverlapWindow = this;
+
+ // set frame data
+ mpWindowImpl->mpFrameData->mpNextFrame = pSVData->maWinData.mpFirstFrame;
+ pSVData->maWinData.mpFirstFrame = this;
+ mpWindowImpl->mpFrameData->mpFirstOverlap = NULL;
+ mpWindowImpl->mpFrameData->mpFocusWin = NULL;
+ mpWindowImpl->mpFrameData->mpMouseMoveWin = NULL;
+ mpWindowImpl->mpFrameData->mpMouseDownWin = NULL;
+ mpWindowImpl->mpFrameData->mpFirstBackWin = NULL;
+ mpWindowImpl->mpFrameData->mpFontList = pSVData->maGDIData.mpScreenFontList;
+ mpWindowImpl->mpFrameData->mpFontCache = pSVData->maGDIData.mpScreenFontCache;
+ mpWindowImpl->mpFrameData->mnAllSaveBackSize = 0;
+ mpWindowImpl->mpFrameData->mnFocusId = 0;
+ mpWindowImpl->mpFrameData->mnMouseMoveId = 0;
+ mpWindowImpl->mpFrameData->mnLastMouseX = -1;
+ mpWindowImpl->mpFrameData->mnLastMouseY = -1;
+ mpWindowImpl->mpFrameData->mnBeforeLastMouseX = -1;
+ mpWindowImpl->mpFrameData->mnBeforeLastMouseY = -1;
+ mpWindowImpl->mpFrameData->mnFirstMouseX = -1;
+ mpWindowImpl->mpFrameData->mnFirstMouseY = -1;
+ mpWindowImpl->mpFrameData->mnLastMouseWinX = -1;
+ mpWindowImpl->mpFrameData->mnLastMouseWinY = -1;
+ mpWindowImpl->mpFrameData->mnModalMode = 0;
+ mpWindowImpl->mpFrameData->mnMouseDownTime = 0;
+ mpWindowImpl->mpFrameData->mnClickCount = 0;
+ mpWindowImpl->mpFrameData->mnFirstMouseCode = 0;
+ mpWindowImpl->mpFrameData->mnMouseCode = 0;
+ mpWindowImpl->mpFrameData->mnMouseMode = 0;
+ mpWindowImpl->mpFrameData->meMapUnit = MAP_PIXEL;
+ mpWindowImpl->mpFrameData->mbHasFocus = FALSE;
+ mpWindowImpl->mpFrameData->mbInMouseMove = FALSE;
+ mpWindowImpl->mpFrameData->mbMouseIn = FALSE;
+ mpWindowImpl->mpFrameData->mbStartDragCalled = FALSE;
+ mpWindowImpl->mpFrameData->mbNeedSysWindow = FALSE;
+ mpWindowImpl->mpFrameData->mbMinimized = FALSE;
+ mpWindowImpl->mpFrameData->mbStartFocusState = FALSE;
+ mpWindowImpl->mpFrameData->mbInSysObjFocusHdl = FALSE;
+ mpWindowImpl->mpFrameData->mbInSysObjToTopHdl = FALSE;
+ mpWindowImpl->mpFrameData->mbSysObjFocus = FALSE;
+ mpWindowImpl->mpFrameData->maPaintTimer.SetTimeout( 30 );
+ mpWindowImpl->mpFrameData->maPaintTimer.SetTimeoutHdl( LINK( this, Window, ImplHandlePaintHdl ) );
+ mpWindowImpl->mpFrameData->maResizeTimer.SetTimeout( 50 );
+ mpWindowImpl->mpFrameData->maResizeTimer.SetTimeoutHdl( LINK( this, Window, ImplHandleResizeTimerHdl ) );
+ mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = FALSE;
+
+ if ( pRealParent && IsTopWindow() )
+ {
+ ImplWinData* pParentWinData = pRealParent->ImplGetWinData();
+ pParentWinData->maTopWindowChildren.push_back( this );
+ }
+ }
+
+ // init data
+ mpWindowImpl->mpRealParent = pRealParent;
+
+ // #99318: make sure fontcache and list is available before call to SetSettings
+ mpFontList = mpWindowImpl->mpFrameData->mpFontList;
+ mpFontCache = mpWindowImpl->mpFrameData->mpFontCache;
+
+ if ( mpWindowImpl->mbFrame )
+ {
+ if ( pParent )
+ {
+ mpWindowImpl->mpFrameData->mnDPIX = pParent->mpWindowImpl->mpFrameData->mnDPIX;
+ mpWindowImpl->mpFrameData->mnDPIY = pParent->mpWindowImpl->mpFrameData->mnDPIY;
+ }
+ else
+ {
+ if ( ImplGetGraphics() )
+ {
+ mpGraphics->GetResolution( mpWindowImpl->mpFrameData->mnDPIX, mpWindowImpl->mpFrameData->mnDPIY );
+ }
+ }
+
+ // add ownerdraw decorated frame windows to list in the top-most frame window
+ // so they can be hidden on lose focus
+ if( nStyle & WB_OWNERDRAWDECORATION )
+ ImplGetOwnerDrawList().push_back( this );
+
+ // delay settings initialization until first "real" frame
+ // this relies on the IntroWindow not needing any system settings
+ if ( !pSVData->maAppData.mbSettingsInit &&
+ ! (nStyle & (WB_INTROWIN|WB_DEFAULTWIN))
+ )
+ {
+ // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
+ ImplUpdateGlobalSettings( *pSVData->maAppData.mpSettings );
+ OutputDevice::SetSettings( *pSVData->maAppData.mpSettings );
+ pSVData->maAppData.mbSettingsInit = TRUE;
+ }
+
+ // If we create a Window with default size, query this
+ // size directly, because we want resize all Controls to
+ // the correct size before we display the window
+ if ( nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_APP) )
+ mpWindowImpl->mpFrame->GetClientSize( mnOutWidth, mnOutHeight );
+ }
+ else
+ {
+ if ( pParent )
+ {
+ if ( !ImplIsOverlapWindow() )
+ {
+ mpWindowImpl->mbDisabled = pParent->mpWindowImpl->mbDisabled;
+ mpWindowImpl->mbInputDisabled = pParent->mpWindowImpl->mbInputDisabled;
+ mpWindowImpl->meAlwaysInputMode = pParent->mpWindowImpl->meAlwaysInputMode;
+ }
+
+ OutputDevice::SetSettings( pParent->GetSettings() );
+ }
+
+ }
+
+ const StyleSettings& rStyleSettings = maSettings.GetStyleSettings();
+ USHORT nScreenZoom = rStyleSettings.GetScreenZoom();
+ mnDPIX = (mpWindowImpl->mpFrameData->mnDPIX*nScreenZoom)/100;
+ mnDPIY = (mpWindowImpl->mpFrameData->mnDPIY*nScreenZoom)/100;
+ maFont = rStyleSettings.GetAppFont();
+ ImplPointToLogic( maFont );
+
+ if ( nStyle & WB_3DLOOK )
+ {
+ SetTextColor( rStyleSettings.GetButtonTextColor() );
+ SetBackground( Wallpaper( rStyleSettings.GetFaceColor() ) );
+ }
+ else
+ {
+ SetTextColor( rStyleSettings.GetWindowTextColor() );
+ SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) );
+ }
+
+ ImplUpdatePos();
+
+ // calculate app font res (except for the Intro Window or the default window)
+ if ( mpWindowImpl->mbFrame && !pSVData->maGDIData.mnAppFontX && ! (nStyle & (WB_INTROWIN|WB_DEFAULTWIN)) )
+ ImplInitAppFontData( this );
+
+ if ( GetAccessibleParentWindow() && GetParent() != Application::GetDefDialogParent() )
+ GetAccessibleParentWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_CHILDCREATED, this );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplSetFrameParent( const Window* pParent )
+{
+ Window* pFrameWindow = ImplGetSVData()->maWinData.mpFirstFrame;
+ while( pFrameWindow )
+ {
+ // search all frames that are children of this window
+ // and reparent them
+ if( ImplIsRealParentPath( pFrameWindow ) )
+ {
+ DBG_ASSERT( mpWindowImpl->mpFrame != pFrameWindow->mpWindowImpl->mpFrame, "SetFrameParent to own" );
+ DBG_ASSERT( mpWindowImpl->mpFrame, "no frame" );
+ SalFrame* pParentFrame = pParent ? pParent->mpWindowImpl->mpFrame : NULL;
+ pFrameWindow->mpWindowImpl->mpFrame->SetParent( pParentFrame );
+ }
+ pFrameWindow = pFrameWindow->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInsertWindow( Window* pParent )
+{
+ mpWindowImpl->mpParent = pParent;
+ mpWindowImpl->mpRealParent = pParent;
+
+ if ( pParent && !mpWindowImpl->mbFrame )
+ {
+ // search frame window and set window frame data
+ Window* pFrameParent = pParent->mpWindowImpl->mpFrameWindow;
+ mpWindowImpl->mpFrameData = pFrameParent->mpWindowImpl->mpFrameData;
+ mpWindowImpl->mpFrame = pFrameParent->mpWindowImpl->mpFrame;
+ mpWindowImpl->mpFrameWindow = pFrameParent;
+ mpWindowImpl->mbFrame = FALSE;
+
+ // search overlap window and insert window in list
+ if ( ImplIsOverlapWindow() )
+ {
+ Window* pFirstOverlapParent = pParent;
+ while ( !pFirstOverlapParent->ImplIsOverlapWindow() )
+ pFirstOverlapParent = pFirstOverlapParent->ImplGetParent();
+ mpWindowImpl->mpOverlapWindow = pFirstOverlapParent;
+
+ mpWindowImpl->mpNextOverlap = mpWindowImpl->mpFrameData->mpFirstOverlap;
+ mpWindowImpl->mpFrameData->mpFirstOverlap = this;
+
+ // Overlap-Windows sind per default die obersten
+ mpWindowImpl->mpNext = pFirstOverlapParent->mpWindowImpl->mpFirstOverlap;
+ pFirstOverlapParent->mpWindowImpl->mpFirstOverlap = this;
+ if ( !pFirstOverlapParent->mpWindowImpl->mpLastOverlap )
+ pFirstOverlapParent->mpWindowImpl->mpLastOverlap = this;
+ else
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
+ }
+ else
+ {
+ if ( pParent->ImplIsOverlapWindow() )
+ mpWindowImpl->mpOverlapWindow = pParent;
+ else
+ mpWindowImpl->mpOverlapWindow = pParent->mpWindowImpl->mpOverlapWindow;
+ mpWindowImpl->mpPrev = pParent->mpWindowImpl->mpLastChild;
+ pParent->mpWindowImpl->mpLastChild = this;
+ if ( !pParent->mpWindowImpl->mpFirstChild )
+ pParent->mpWindowImpl->mpFirstChild = this;
+ else
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplRemoveWindow( BOOL bRemoveFrameData )
+{
+ // Fenster aus den Listen austragen
+ if ( !mpWindowImpl->mbFrame )
+ {
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpFrameData->mpFirstOverlap == this )
+ mpWindowImpl->mpFrameData->mpFirstOverlap = mpWindowImpl->mpNextOverlap;
+ else
+ {
+ Window* pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pTempWin->mpWindowImpl->mpNextOverlap != this )
+ pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
+ pTempWin->mpWindowImpl->mpNextOverlap = mpWindowImpl->mpNextOverlap;
+ }
+
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+ }
+ else
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
+ }
+
+ mpWindowImpl->mpPrev = NULL;
+ mpWindowImpl->mpNext = NULL;
+ }
+
+ if ( bRemoveFrameData )
+ {
+ // Graphic freigeben
+ ImplReleaseGraphics();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallResize()
+{
+ mpWindowImpl->mbCallResize = FALSE;
+
+ if( GetBackground().IsGradient() )
+ Invalidate();
+
+ Resize();
+
+ // #88419# Most classes don't call the base class in Resize() and Move(),
+ // => Call ImpleResize/Move instead of Resize/Move directly...
+ ImplCallEventListeners( VCLEVENT_WINDOW_RESIZE );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallMove()
+{
+ mpWindowImpl->mbCallMove = FALSE;
+
+ if( mpWindowImpl->mbFrame )
+ {
+ // update frame position
+ SalFrame *pParentFrame = NULL;
+ Window *pParent = ImplGetParent();
+ while( pParent )
+ {
+ if( pParent->mpWindowImpl->mpFrame != mpWindowImpl->mpFrame )
+ {
+ pParentFrame = pParent->mpWindowImpl->mpFrame;
+ break;
+ }
+ pParent = pParent->GetParent();
+ }
+
+ SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
+ mpWindowImpl->maPos = Point( g.nX, g.nY );
+ if( pParentFrame )
+ {
+ g = pParentFrame->GetGeometry();
+ mpWindowImpl->maPos -= Point( g.nX, g.nY );
+ }
+ // the client window and and all its subclients have the same position as the borderframe
+ // this is important for floating toolbars where the borderwindow is a floating window
+ // which has another borderwindow (ie the system floating window)
+ Window *pClientWin = mpWindowImpl->mpClientWindow;
+ while( pClientWin )
+ {
+ pClientWin->mpWindowImpl->maPos = mpWindowImpl->maPos;
+ pClientWin = pClientWin->mpWindowImpl->mpClientWindow;
+ }
+ }
+
+ Move();
+
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOVE );
+}
+
+// -----------------------------------------------------------------------
+
+static ULONG ImplAutoHelpID( ResMgr* pResMgr )
+{
+ if ( !Application::IsAutoHelpIdEnabled() )
+ return 0;
+
+ ULONG nHID = 0;
+
+ DBG_ASSERT( pResMgr, "No res mgr for auto help id" );
+ if( ! pResMgr )
+ return 0;
+
+ nHID = pResMgr->GetAutoHelpId();
+
+ return nHID;
+}
+
+// -----------------------------------------------------------------------
+
+WinBits Window::ImplInitRes( const ResId& rResId )
+{
+ GetRes( rResId );
+
+ char* pRes = (char*)GetClassRes();
+ pRes += 8;
+ sal_uInt32 nStyle = (sal_uInt32)GetLongRes( (void*)pRes );
+ rResId.SetWinBits( nStyle );
+ return nStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplLoadRes( const ResId& rResId )
+{
+ // newer move this line after IncrementRes
+ char* pRes = (char*)GetClassRes();
+ pRes += 12;
+ sal_uInt32 nHelpId = (sal_uInt32)GetLongRes( (void*)pRes );
+ if ( !nHelpId )
+ nHelpId = ImplAutoHelpID( rResId.GetResMgr() );
+ SetHelpId( nHelpId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ // ResourceStyle
+ ULONG nRSStyle = ReadLongRes();
+ // WinBits
+ ReadLongRes();
+ // HelpId
+ ReadLongRes();
+
+ BOOL bPos = FALSE;
+ BOOL bSize = FALSE;
+ Point aPos;
+ Size aSize;
+
+ if ( nObjMask & (WINDOW_XYMAPMODE | WINDOW_X | WINDOW_Y) )
+ {
+ // Groessenangabe aus der Resource verwenden
+ MapUnit ePosMap = MAP_PIXEL;
+
+ bPos = TRUE;
+
+ if ( nObjMask & WINDOW_XYMAPMODE )
+ ePosMap = (MapUnit)ReadLongRes();
+ if ( nObjMask & WINDOW_X )
+ aPos.X() = ImplLogicUnitToPixelX( ReadLongRes(), ePosMap );
+ if ( nObjMask & WINDOW_Y )
+ aPos.Y() = ImplLogicUnitToPixelY( ReadLongRes(), ePosMap );
+ }
+
+ if ( nObjMask & (WINDOW_WHMAPMODE | WINDOW_WIDTH | WINDOW_HEIGHT) )
+ {
+ // Groessenangabe aus der Resource verwenden
+ MapUnit eSizeMap = MAP_PIXEL;
+
+ bSize = TRUE;
+
+ if ( nObjMask & WINDOW_WHMAPMODE )
+ eSizeMap = (MapUnit)ReadLongRes();
+ if ( nObjMask & WINDOW_WIDTH )
+ aSize.Width() = ImplLogicUnitToPixelX( ReadLongRes(), eSizeMap );
+ if ( nObjMask & WINDOW_HEIGHT )
+ aSize.Height() = ImplLogicUnitToPixelY( ReadLongRes(), eSizeMap );
+ }
+
+ // Wegen Optimierung so schlimm aussehend
+ if ( nRSStyle & RSWND_CLIENTSIZE )
+ {
+ if ( bPos )
+ SetPosPixel( aPos );
+ if ( bSize )
+ SetOutputSizePixel( aSize );
+ }
+ else if ( bPos && bSize )
+ SetPosSizePixel( aPos, aSize );
+ else if ( bPos )
+ SetPosPixel( aPos );
+ else if ( bSize )
+ SetSizePixel( aSize );
+
+ if ( nRSStyle & RSWND_DISABLED )
+ Enable( FALSE );
+
+ if ( nObjMask & WINDOW_TEXT )
+ SetText( ReadStringRes() );
+ if ( nObjMask & WINDOW_HELPTEXT )
+ {
+ SetHelpText( ReadStringRes() );
+ mpWindowImpl->mbHelpTextDynamic = TRUE;
+ }
+ if ( nObjMask & WINDOW_QUICKTEXT )
+ SetQuickHelpText( ReadStringRes() );
+ if ( nObjMask & WINDOW_EXTRALONG )
+ SetData( (void*)ReadLongRes() );
+ if ( nObjMask & WINDOW_UNIQUEID )
+ SetUniqueId( (ULONG)ReadLongRes() );
+
+ if ( nObjMask & WINDOW_BORDER_STYLE )
+ {
+ USHORT nBorderStyle = (USHORT)ReadLongRes();
+ SetBorderStyle( nBorderStyle );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplWinData* Window::ImplGetWinData() const
+{
+ if ( !mpWindowImpl->mpWinData )
+ {
+ static const char* pNoNWF = getenv( "SAL_NO_NWF" );
+
+ ((Window*)this)->mpWindowImpl->mpWinData = new ImplWinData;
+ mpWindowImpl->mpWinData->mpExtOldText = NULL;
+ mpWindowImpl->mpWinData->mpExtOldAttrAry = NULL;
+ mpWindowImpl->mpWinData->mpCursorRect = 0;
+ mpWindowImpl->mpWinData->mnCursorExtWidth = 0;
+ mpWindowImpl->mpWinData->mpFocusRect = NULL;
+ mpWindowImpl->mpWinData->mpTrackRect = NULL;
+ mpWindowImpl->mpWinData->mnTrackFlags = 0;
+ mpWindowImpl->mpWinData->mnIsTopWindow = (USHORT) ~0; // not initialized yet, 0/1 will indicate TopWindow (see IsTopWindow())
+ mpWindowImpl->mpWinData->mbMouseOver = FALSE;
+ mpWindowImpl->mpWinData->mbEnableNativeWidget = (pNoNWF && *pNoNWF) ? FALSE : TRUE; // TRUE: try to draw this control with native theme API
+ mpWindowImpl->mpWinData->mpSmartHelpId = NULL;
+ mpWindowImpl->mpWinData->mpSmartUniqueId = NULL;
+ }
+
+ return mpWindowImpl->mpWinData;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* Window::ImplGetFrameGraphics() const
+{
+ if ( mpWindowImpl->mpFrameWindow->mpGraphics )
+ mpWindowImpl->mpFrameWindow->mbInitClipRegion = TRUE;
+ else
+ mpWindowImpl->mpFrameWindow->ImplGetGraphics();
+ mpWindowImpl->mpFrameWindow->mpGraphics->ResetClipRegion();
+ return mpWindowImpl->mpFrameWindow->mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::ImplFindWindow( const Point& rFramePos )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Window* pTempWindow;
+ Window* pFindWindow;
+
+ // Zuerst alle ueberlappenden Fenster ueberpruefen
+ pTempWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pTempWindow )
+ {
+ pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
+ if ( pFindWindow )
+ return pFindWindow;
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+
+ // dann testen wir unser Fenster
+ if ( !mpWindowImpl->mbVisible )
+ return NULL;
+
+ USHORT nHitTest = ImplHitTest( rFramePos );
+ if ( nHitTest & WINDOW_HITTEST_INSIDE )
+ {
+ // und danach gehen wir noch alle Child-Fenster durch
+ pTempWindow = mpWindowImpl->mpFirstChild;
+ while ( pTempWindow )
+ {
+ pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
+ if ( pFindWindow )
+ return pFindWindow;
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+
+ if ( nHitTest & WINDOW_HITTEST_TRANSPARENT )
+ return NULL;
+ else
+ return this;
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Window::ImplHitTest( const Point& rFramePos )
+{
+ Point aFramePos( rFramePos );
+ if( ImplIsAntiparallel() )
+ {
+ // - RTL - re-mirror frame pos at this window
+ ImplReMirror( aFramePos );
+ }
+ Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ if ( !aRect.IsInside( aFramePos ) )
+ return 0;
+ if ( mpWindowImpl->mbWinRegion )
+ {
+ Point aTempPos = aFramePos;
+ aTempPos.X() -= mnOutOffX;
+ aTempPos.Y() -= mnOutOffY;
+ if ( !mpWindowImpl->maWinRegion.IsInside( aTempPos ) )
+ return 0;
+ }
+
+ USHORT nHitTest = WINDOW_HITTEST_INSIDE;
+ if ( mpWindowImpl->mbMouseTransparent )
+ nHitTest |= WINDOW_HITTEST_TRANSPARENT;
+ return nHitTest;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplIsRealParentPath( const Window* pWindow ) const
+{
+ pWindow = pWindow->GetParent();
+ while ( pWindow )
+ {
+ if ( pWindow == this )
+ return TRUE;
+ pWindow = pWindow->GetParent();
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplIsChild( const Window* pWindow, BOOL bSystemWindow ) const
+{
+ do
+ {
+ if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
+ break;
+
+ pWindow = pWindow->ImplGetParent();
+
+ if ( pWindow == this )
+ return TRUE;
+ }
+ while ( pWindow );
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplIsWindowOrChild( const Window* pWindow, BOOL bSystemWindow ) const
+{
+ if ( this == pWindow )
+ return TRUE;
+ return ImplIsChild( pWindow, bSystemWindow );
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::ImplGetSameParent( const Window* pWindow ) const
+{
+ if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow )
+ return NULL;
+ else
+ {
+ if ( pWindow->ImplIsChild( this ) )
+ return (Window*)pWindow;
+ else
+ {
+ Window* pTestWindow = (Window*)this;
+ while ( (pTestWindow == pWindow) || pTestWindow->ImplIsChild( pWindow ) )
+ pTestWindow = pTestWindow->ImplGetParent();
+ return pTestWindow;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int Window::ImplTestMousePointerSet()
+{
+ // Wenn Mouse gecaptured ist, dann soll MousePointer umgeschaltet werden
+ if ( IsMouseCaptured() )
+ return TRUE;
+
+ // Wenn sich Mouse ueber dem Fenster befindet, dann soll MousePointer
+ // umgeschaltet werden
+ Rectangle aClientRect( Point( 0, 0 ), GetOutputSizePixel() );
+ if ( aClientRect.IsInside( GetPointerPosPixel() ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+PointerStyle Window::ImplGetMousePointer() const
+{
+ PointerStyle ePointerStyle;
+ BOOL bWait = FALSE;
+
+ if ( IsEnabled() && IsInputEnabled() && ! IsInModalMode() )
+ ePointerStyle = GetPointer().GetStyle();
+ else
+ ePointerStyle = POINTER_ARROW;
+
+ const Window* pWindow = this;
+ do
+ {
+ // Wenn Pointer nicht sichtbar, dann wird suche abgebrochen, da
+ // dieser Status nicht ueberschrieben werden darf
+ if ( pWindow->mpWindowImpl->mbNoPtrVisible )
+ return POINTER_NULL;
+
+ if ( !bWait )
+ {
+ if ( pWindow->mpWindowImpl->mnWaitCount )
+ {
+ ePointerStyle = POINTER_WAIT;
+ bWait = TRUE;
+ }
+ else
+ {
+ if ( pWindow->mpWindowImpl->mbChildPtrOverwrite )
+ ePointerStyle = pWindow->GetPointer().GetStyle();
+ }
+ }
+
+ if ( pWindow->ImplIsOverlapWindow() )
+ break;
+
+ pWindow = pWindow->ImplGetParent();
+ }
+ while ( pWindow );
+
+ return ePointerStyle;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplResetReallyVisible()
+{
+ BOOL bBecameReallyInvisible = mpWindowImpl->mbReallyVisible;
+
+ mbDevOutput = FALSE;
+ mpWindowImpl->mbReallyVisible = FALSE;
+ mpWindowImpl->mbReallyShown = FALSE;
+
+ // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
+ // For this, the data member of the event must not be NULL.
+ // Previously, we did this in Window::Show, but there some events got lost in certain situations.
+ // #104887# - 2004-08-10 - fs@openoffice.org
+ if( bBecameReallyInvisible && ImplIsAccessibleCandidate() )
+ ImplCallEventListeners( VCLEVENT_WINDOW_HIDE, this );
+ // TODO. It's kind of a hack that we're re-using the VCLEVENT_WINDOW_HIDE. Normally, we should
+ // introduce another event which explicitly triggers the Accessibility implementations.
+
+ Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ pWindow->ImplResetReallyVisible();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ pWindow->ImplResetReallyVisible();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplSetReallyVisible()
+{
+ // #i43594# it is possible that INITSHOW was never send, because the visibility state changed between
+ // ImplCallInitShow() and ImplSetReallyVisible() when called from Show()
+ // mbReallyShown is a useful indicator
+ if( !mpWindowImpl->mbReallyShown )
+ ImplCallInitShow();
+
+ BOOL bBecameReallyVisible = !mpWindowImpl->mbReallyVisible;
+
+ mbDevOutput = TRUE;
+ mpWindowImpl->mbReallyVisible = TRUE;
+ mpWindowImpl->mbReallyShown = TRUE;
+
+ // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
+ // For this, the data member of the event must not be NULL.
+ // Previously, we did this in Window::Show, but there some events got lost in certain situations. Now
+ // we're doing it when the visibility really changes
+ // #104887# - 2004-08-10 - fs@openoffice.org
+ if( bBecameReallyVisible && ImplIsAccessibleCandidate() )
+ ImplCallEventListeners( VCLEVENT_WINDOW_SHOW, this );
+ // TODO. It's kind of a hack that we're re-using the VCLEVENT_WINDOW_SHOW. Normally, we should
+ // introduce another event which explicitly triggers the Accessibility implementations.
+
+ Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbVisible )
+ pWindow->ImplSetReallyVisible();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbVisible )
+ pWindow->ImplSetReallyVisible();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallInitShow()
+{
+ mpWindowImpl->mbReallyShown = TRUE;
+ mpWindowImpl->mbInInitShow = TRUE;
+ StateChanged( STATE_CHANGE_INITSHOW );
+ mpWindowImpl->mbInInitShow = FALSE;
+
+ Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbVisible )
+ pWindow->ImplCallInitShow();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbVisible )
+ pWindow->ImplCallInitShow();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplAddDel( ImplDelData* pDel ) // TODO: make "const" when incompatiblity ok
+{
+ DBG_ASSERT( !pDel->mpWindow, "Window::ImplAddDel(): cannot add ImplDelData twice !" );
+ if( !pDel->mpWindow )
+ {
+ pDel->mpWindow = this; // #112873# store ref to this window, so pDel can remove itself
+ pDel->mpNext = mpWindowImpl->mpFirstDel;
+ mpWindowImpl->mpFirstDel = pDel;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplRemoveDel( ImplDelData* pDel ) // TODO: make "const" when incompatiblity ok
+{
+ pDel->mpWindow = NULL; // #112873# pDel is not associated with a Window anymore
+ if ( mpWindowImpl->mpFirstDel == pDel )
+ mpWindowImpl->mpFirstDel = pDel->mpNext;
+ else
+ {
+ ImplDelData* pData = mpWindowImpl->mpFirstDel;
+ while ( pData->mpNext != pDel )
+ pData = pData->mpNext;
+ pData->mpNext = pDel->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInitResolutionSettings()
+{
+ // AppFont-Aufloesung und DPI-Aufloesung neu berechnen
+ if ( mpWindowImpl->mbFrame )
+ {
+ const StyleSettings& rStyleSettings = maSettings.GetStyleSettings();
+ USHORT nScreenZoom = rStyleSettings.GetScreenZoom();
+ mnDPIX = (mpWindowImpl->mpFrameData->mnDPIX*nScreenZoom)/100;
+ mnDPIY = (mpWindowImpl->mpFrameData->mnDPIY*nScreenZoom)/100;
+ SetPointFont( rStyleSettings.GetAppFont() );
+ }
+ else if ( mpWindowImpl->mpParent )
+ {
+ mnDPIX = mpWindowImpl->mpParent->mnDPIX;
+ mnDPIY = mpWindowImpl->mpParent->mnDPIY;
+ }
+
+ // Vorberechnete Werte fuer logische Einheiten updaten und auch
+ // die entsprechenden Tools dazu
+ if ( IsMapMode() )
+ {
+ MapMode aMapMode = GetMapMode();
+ SetMapMode();
+ SetMapMode( aMapMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplPointToLogic( Font& rFont ) const
+{
+ Size aSize = rFont.GetSize();
+ USHORT nScreenFontZoom = maSettings.GetStyleSettings().GetScreenFontZoom();
+
+ if ( aSize.Width() )
+ {
+ aSize.Width() *= mpWindowImpl->mpFrameData->mnDPIX;
+ aSize.Width() += 72/2;
+ aSize.Width() /= 72;
+ aSize.Width() *= nScreenFontZoom;
+ aSize.Width() /= 100;
+ }
+ aSize.Height() *= mpWindowImpl->mpFrameData->mnDPIY;
+ aSize.Height() += 72/2;
+ aSize.Height() /= 72;
+ aSize.Height() *= nScreenFontZoom;
+ aSize.Height() /= 100;
+
+ if ( IsMapModeEnabled() )
+ aSize = PixelToLogic( aSize );
+
+ rFont.SetSize( aSize );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplLogicToPoint( Font& rFont ) const
+{
+ Size aSize = rFont.GetSize();
+ USHORT nScreenFontZoom = maSettings.GetStyleSettings().GetScreenFontZoom();
+
+ if ( IsMapModeEnabled() )
+ aSize = LogicToPixel( aSize );
+
+ if ( aSize.Width() )
+ {
+ aSize.Width() *= 100;
+ aSize.Width() /= nScreenFontZoom;
+ aSize.Width() *= 72;
+ aSize.Width() += mpWindowImpl->mpFrameData->mnDPIX/2;
+ aSize.Width() /= mpWindowImpl->mpFrameData->mnDPIX;
+ }
+ aSize.Height() *= 100;
+ aSize.Height() /= nScreenFontZoom;
+ aSize.Height() *= 72;
+ aSize.Height() += mpWindowImpl->mpFrameData->mnDPIY/2;
+ aSize.Height() /= mpWindowImpl->mpFrameData->mnDPIY;
+
+ rFont.SetSize( aSize );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplSysObjClip( const Region* pOldRegion )
+{
+ BOOL bUpdate = TRUE;
+
+ if ( mpWindowImpl->mpSysObj )
+ {
+ BOOL bVisibleState = mpWindowImpl->mbReallyVisible;
+
+ if ( bVisibleState )
+ {
+ Region* pWinChildClipRegion = ImplGetWinChildClipRegion();
+
+ if ( !pWinChildClipRegion->IsEmpty() )
+ {
+ if ( pOldRegion )
+ {
+ Region aNewRegion = *pWinChildClipRegion;
+ pWinChildClipRegion->Intersect( *pOldRegion );
+ bUpdate = aNewRegion == *pWinChildClipRegion;
+ }
+
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+
+ Region aRegion = *pWinChildClipRegion;
+ Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ Region aWinRectRegion( aWinRect );
+ USHORT nClipFlags = mpWindowImpl->mpSysObj->GetClipRegionType();
+
+ if ( aRegion == aWinRectRegion )
+ mpWindowImpl->mpSysObj->ResetClipRegion();
+ else
+ {
+ if ( nClipFlags & SAL_OBJECT_CLIP_EXCLUDERECTS )
+ {
+ aWinRectRegion.Exclude( aRegion );
+ aRegion = aWinRectRegion;
+ }
+ if ( !(nClipFlags & SAL_OBJECT_CLIP_ABSOLUTE) )
+ aRegion.Move( -mnOutOffX, -mnOutOffY );
+
+ // ClipRegion setzen/updaten
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ULONG nRectCount;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+
+ nRectCount = aRegion.GetRectCount();
+ mpWindowImpl->mpSysObj->BeginSetClipRegion( nRectCount );
+ bRegionRect = aRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ while ( bRegionRect )
+ {
+ mpWindowImpl->mpSysObj->UnionClipRegion( nX, nY, nWidth, nHeight );
+ bRegionRect = aRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ mpWindowImpl->mpSysObj->EndSetClipRegion();
+ }
+ }
+ else
+ bVisibleState = FALSE;
+ }
+
+ // Visible-Status updaten
+ mpWindowImpl->mpSysObj->Show( bVisibleState );
+ }
+
+ return bUpdate;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateSysObjChildsClip()
+{
+ if ( mpWindowImpl->mpSysObj && mpWindowImpl->mbInitWinClipRegion )
+ ImplSysObjClip( NULL );
+
+ Window* pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ pWindow->ImplUpdateSysObjChildsClip();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateSysObjOverlapsClip()
+{
+ ImplUpdateSysObjChildsClip();
+
+ Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ pWindow->ImplUpdateSysObjOverlapsClip();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateSysObjClip()
+{
+ if ( !ImplIsOverlapWindow() )
+ {
+ ImplUpdateSysObjChildsClip();
+
+ // Schwestern muessen ihre ClipRegion auch neu berechnen
+ if ( mpWindowImpl->mbClipSiblings )
+ {
+ Window* pWindow = mpWindowImpl->mpNext;
+ while ( pWindow )
+ {
+ pWindow->ImplUpdateSysObjChildsClip();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ }
+ }
+ else
+ mpWindowImpl->mpFrameWindow->ImplUpdateSysObjOverlapsClip();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplSetClipFlagChilds( BOOL bSysObjOnlySmaller )
+{
+ BOOL bUpdate = TRUE;
+ if ( mpWindowImpl->mpSysObj )
+ {
+ Region* pOldRegion = NULL;
+ if ( bSysObjOnlySmaller && !mpWindowImpl->mbInitWinClipRegion )
+ pOldRegion = new Region( mpWindowImpl->maWinClipRegion );
+
+ mbInitClipRegion = TRUE;
+ mpWindowImpl->mbInitWinClipRegion = TRUE;
+
+ Window* pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( !pWindow->ImplSetClipFlagChilds( bSysObjOnlySmaller ) )
+ bUpdate = FALSE;
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ if ( !ImplSysObjClip( pOldRegion ) )
+ {
+ mbInitClipRegion = TRUE;
+ mpWindowImpl->mbInitWinClipRegion = TRUE;
+ bUpdate = FALSE;
+ }
+
+ if ( pOldRegion )
+ delete pOldRegion;
+ }
+ else
+ {
+ mbInitClipRegion = TRUE;
+ mpWindowImpl->mbInitWinClipRegion = TRUE;
+
+ Window* pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( !pWindow->ImplSetClipFlagChilds( bSysObjOnlySmaller ) )
+ bUpdate = FALSE;
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ }
+ return bUpdate;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplSetClipFlagOverlapWindows( BOOL bSysObjOnlySmaller )
+{
+ BOOL bUpdate = ImplSetClipFlagChilds( bSysObjOnlySmaller );
+
+ Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ if ( !pWindow->ImplSetClipFlagOverlapWindows( bSysObjOnlySmaller ) )
+ bUpdate = FALSE;
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ return bUpdate;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplSetClipFlag( BOOL bSysObjOnlySmaller )
+{
+ if ( !ImplIsOverlapWindow() )
+ {
+ BOOL bUpdate = ImplSetClipFlagChilds( bSysObjOnlySmaller );
+
+ Window* pParent = ImplGetParent();
+ if ( pParent &&
+ ((pParent->GetStyle() & WB_CLIPCHILDREN) || (mpWindowImpl->mnParentClipMode & PARENTCLIPMODE_CLIP)) )
+ {
+ pParent->mbInitClipRegion = TRUE;
+ pParent->mpWindowImpl->mbInitChildRegion = TRUE;
+ }
+
+ // Schwestern muessen ihre ClipRegion auch neu berechnen
+ if ( mpWindowImpl->mbClipSiblings )
+ {
+ Window* pWindow = mpWindowImpl->mpNext;
+ while ( pWindow )
+ {
+ if ( !pWindow->ImplSetClipFlagChilds( bSysObjOnlySmaller ) )
+ bUpdate = FALSE;
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ }
+
+ return bUpdate;
+ }
+ else
+ return mpWindowImpl->mpFrameWindow->ImplSetClipFlagOverlapWindows( bSysObjOnlySmaller );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplIntersectWindowClipRegion( Region& rRegion )
+{
+ if ( mpWindowImpl->mbInitWinClipRegion )
+ ImplInitWinClipRegion();
+
+ rRegion.Intersect( mpWindowImpl->maWinClipRegion );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplIntersectWindowRegion( Region& rRegion )
+{
+ rRegion.Intersect( Rectangle( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) ) );
+ if ( mpWindowImpl->mbWinRegion )
+ rRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplExcludeWindowRegion( Region& rRegion )
+{
+ if ( mpWindowImpl->mbWinRegion )
+ {
+ Point aPoint( mnOutOffX, mnOutOffY );
+ Region aRegion( Rectangle( aPoint,
+ Size( mnOutWidth, mnOutHeight ) ) );
+ aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+ rRegion.Exclude( aRegion );
+ }
+ else
+ {
+ Point aPoint( mnOutOffX, mnOutOffY );
+ rRegion.Exclude( Rectangle( aPoint,
+ Size( mnOutWidth, mnOutHeight ) ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplExcludeOverlapWindows( Region& rRegion )
+{
+ Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ {
+ pWindow->ImplExcludeWindowRegion( rRegion );
+ pWindow->ImplExcludeOverlapWindows( rRegion );
+ }
+
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplExcludeOverlapWindows2( Region& rRegion )
+{
+ if ( mpWindowImpl->mbReallyVisible )
+ ImplExcludeWindowRegion( rRegion );
+
+ ImplExcludeOverlapWindows( rRegion );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplClipBoundaries( Region& rRegion, BOOL bThis, BOOL bOverlaps )
+{
+ if ( bThis )
+ ImplIntersectWindowClipRegion( rRegion );
+ else if ( ImplIsOverlapWindow() )
+ {
+ // Evt. noch am Frame clippen
+ if ( !mpWindowImpl->mbFrame )
+ rRegion.Intersect( Rectangle( Point( 0, 0 ), Size( mpWindowImpl->mpFrameWindow->mnOutWidth, mpWindowImpl->mpFrameWindow->mnOutHeight ) ) );
+
+ if ( bOverlaps && !rRegion.IsEmpty() )
+ {
+ // Clip Overlap Siblings
+ Window* pStartOverlapWindow = this;
+ while ( !pStartOverlapWindow->mpWindowImpl->mbFrame )
+ {
+ Window* pOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow && (pOverlapWindow != pStartOverlapWindow) )
+ {
+ pOverlapWindow->ImplExcludeOverlapWindows2( rRegion );
+ pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ }
+ pStartOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow;
+ }
+
+ // Clip Child Overlap Windows
+ ImplExcludeOverlapWindows( rRegion );
+ }
+ }
+ else
+ ImplGetParent()->ImplIntersectWindowClipRegion( rRegion );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplClipChilds( Region& rRegion )
+{
+ BOOL bOtherClip = FALSE;
+ Window* pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ {
+ // ParentClipMode-Flags auswerten
+ USHORT nClipMode = pWindow->GetParentClipMode();
+ if ( !(nClipMode & PARENTCLIPMODE_NOCLIP) &&
+ ((nClipMode & PARENTCLIPMODE_CLIP) || (GetStyle() & WB_CLIPCHILDREN)) )
+ pWindow->ImplExcludeWindowRegion( rRegion );
+ else
+ bOtherClip = TRUE;
+ }
+
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ return bOtherClip;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplClipAllChilds( Region& rRegion )
+{
+ Window* pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ pWindow->ImplExcludeWindowRegion( rRegion );
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplClipSiblings( Region& rRegion )
+{
+ Window* pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow == this )
+ break;
+
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ pWindow->ImplExcludeWindowRegion( rRegion );
+
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInitWinClipRegion()
+{
+ // Build Window Region
+ mpWindowImpl->maWinClipRegion = Rectangle( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) );
+ if ( mpWindowImpl->mbWinRegion )
+ mpWindowImpl->maWinClipRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+
+ // ClipSiblings
+ if ( mpWindowImpl->mbClipSiblings && !ImplIsOverlapWindow() )
+ ImplClipSiblings( mpWindowImpl->maWinClipRegion );
+
+ // Clip Parent Boundaries
+ ImplClipBoundaries( mpWindowImpl->maWinClipRegion, FALSE, TRUE );
+
+ // Clip Children
+ if ( (GetStyle() & WB_CLIPCHILDREN) || mpWindowImpl->mbClipChildren )
+ mpWindowImpl->mbInitChildRegion = TRUE;
+
+ mpWindowImpl->mbInitWinClipRegion = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInitWinChildClipRegion()
+{
+ if ( !mpWindowImpl->mpFirstChild )
+ {
+ if ( mpWindowImpl->mpChildClipRegion )
+ {
+ delete mpWindowImpl->mpChildClipRegion;
+ mpWindowImpl->mpChildClipRegion = NULL;
+ }
+ }
+ else
+ {
+ if ( !mpWindowImpl->mpChildClipRegion )
+ mpWindowImpl->mpChildClipRegion = new Region( mpWindowImpl->maWinClipRegion );
+ else
+ *mpWindowImpl->mpChildClipRegion = mpWindowImpl->maWinClipRegion;
+
+ ImplClipChilds( *mpWindowImpl->mpChildClipRegion );
+ }
+
+ mpWindowImpl->mbInitChildRegion = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Region* Window::ImplGetWinChildClipRegion()
+{
+ if ( mpWindowImpl->mbInitWinClipRegion )
+ ImplInitWinClipRegion();
+ if ( mpWindowImpl->mbInitChildRegion )
+ ImplInitWinChildClipRegion();
+ if ( mpWindowImpl->mpChildClipRegion )
+ return mpWindowImpl->mpChildClipRegion;
+ else
+ return &mpWindowImpl->maWinClipRegion;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplIntersectAndUnionOverlapWindows( const Region& rInterRegion, Region& rRegion )
+{
+ Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ {
+ Region aTempRegion( rInterRegion );
+ pWindow->ImplIntersectWindowRegion( aTempRegion );
+ rRegion.Union( aTempRegion );
+ pWindow->ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion );
+ }
+
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplIntersectAndUnionOverlapWindows2( const Region& rInterRegion, Region& rRegion )
+{
+ if ( mpWindowImpl->mbReallyVisible )
+ {
+ Region aTempRegion( rInterRegion );
+ ImplIntersectWindowRegion( aTempRegion );
+ rRegion.Union( aTempRegion );
+ }
+
+ ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCalcOverlapRegionOverlaps( const Region& rInterRegion, Region& rRegion )
+{
+ // Clip Overlap Siblings
+ Window* pStartOverlapWindow;
+ if ( !ImplIsOverlapWindow() )
+ pStartOverlapWindow = mpWindowImpl->mpOverlapWindow;
+ else
+ pStartOverlapWindow = this;
+ while ( !pStartOverlapWindow->mpWindowImpl->mbFrame )
+ {
+ Window* pOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow && (pOverlapWindow != pStartOverlapWindow) )
+ {
+ pOverlapWindow->ImplIntersectAndUnionOverlapWindows2( rInterRegion, rRegion );
+ pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ }
+ pStartOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow;
+ }
+
+ // Clip Child Overlap Windows
+ if ( !ImplIsOverlapWindow() )
+ mpWindowImpl->mpOverlapWindow->ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion );
+ else
+ ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCalcOverlapRegion( const Rectangle& rSourceRect, Region& rRegion,
+ BOOL bChilds, BOOL bParent, BOOL bSiblings )
+{
+ Region aRegion( rSourceRect );
+ if ( mpWindowImpl->mbWinRegion )
+ rRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+ Region aTempRegion;
+ Window* pWindow;
+
+ ImplCalcOverlapRegionOverlaps( aRegion, rRegion );
+
+ // Parent-Boundaries
+ if ( bParent )
+ {
+ pWindow = this;
+ if ( !ImplIsOverlapWindow() )
+ {
+ pWindow = ImplGetParent();
+ do
+ {
+ aTempRegion = aRegion;
+ pWindow->ImplExcludeWindowRegion( aTempRegion );
+ rRegion.Union( aTempRegion );
+ if ( pWindow->ImplIsOverlapWindow() )
+ break;
+ pWindow = pWindow->ImplGetParent();
+ }
+ while ( pWindow );
+ }
+ if ( !pWindow->mpWindowImpl->mbFrame )
+ {
+ aTempRegion = aRegion;
+ aTempRegion.Exclude( Rectangle( Point( 0, 0 ), Size( mpWindowImpl->mpFrameWindow->mnOutWidth, mpWindowImpl->mpFrameWindow->mnOutHeight ) ) );
+ rRegion.Union( aTempRegion );
+ }
+ }
+
+ // Siblings
+ if ( bSiblings && !ImplIsOverlapWindow() )
+ {
+ pWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
+ do
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible && (pWindow != this) )
+ {
+ aTempRegion = aRegion;
+ pWindow->ImplIntersectWindowRegion( aTempRegion );
+ rRegion.Union( aTempRegion );
+ }
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ while ( pWindow );
+ }
+
+ // Childs
+ if ( bChilds )
+ {
+ pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ {
+ aTempRegion = aRegion;
+ pWindow->ImplIntersectWindowRegion( aTempRegion );
+ rRegion.Union( aTempRegion );
+ }
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallPaint( const Region* pRegion, USHORT nPaintFlags )
+{
+ // call PrePaint. PrePaint may add to the invalidate region as well as
+ // other parameters used below.
+ PrePaint();
+
+ mpWindowImpl->mbPaintFrame = FALSE;
+
+ if ( nPaintFlags & IMPL_PAINT_PAINTALLCHILDS )
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINT | IMPL_PAINT_PAINTALLCHILDS | (nPaintFlags & IMPL_PAINT_PAINTALL);
+ if ( nPaintFlags & IMPL_PAINT_PAINTCHILDS )
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTCHILDS;
+ if ( nPaintFlags & IMPL_PAINT_ERASE )
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_ERASE;
+ if ( nPaintFlags & IMPL_PAINT_CHECKRTL )
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_CHECKRTL;
+ if ( !mpWindowImpl->mpFirstChild )
+ mpWindowImpl->mnPaintFlags &= ~IMPL_PAINT_PAINTALLCHILDS;
+
+ if ( mpWindowImpl->mbPaintDisabled )
+ {
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
+ Invalidate( INVALIDATE_NOCHILDREN | INVALIDATE_NOERASE | INVALIDATE_NOTRANSPARENT | INVALIDATE_NOCLIPCHILDREN );
+ else if ( pRegion )
+ Invalidate( *pRegion, INVALIDATE_NOCHILDREN | INVALIDATE_NOERASE | INVALIDATE_NOTRANSPARENT | INVALIDATE_NOCLIPCHILDREN );
+ return;
+ }
+
+ nPaintFlags = mpWindowImpl->mnPaintFlags & ~(IMPL_PAINT_PAINT);
+
+ Region* pChildRegion = NULL;
+ Rectangle aSelectionRect;
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINT )
+ {
+ Region* pWinChildClipRegion = ImplGetWinChildClipRegion();
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
+ mpWindowImpl->maInvalidateRegion = *pWinChildClipRegion;
+ else
+ {
+ if ( pRegion )
+ mpWindowImpl->maInvalidateRegion.Union( *pRegion );
+
+ if( mpWindowImpl->mpWinData && mpWindowImpl->mbTrackVisible )
+ /* #98602# need to repaint all children within the
+ * tracking rectangle, so the following invert
+ * operation takes places without traces of the previous
+ * one.
+ */
+ mpWindowImpl->maInvalidateRegion.Union( *mpWindowImpl->mpWinData->mpTrackRect );
+
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS )
+ pChildRegion = new Region( mpWindowImpl->maInvalidateRegion );
+ mpWindowImpl->maInvalidateRegion.Intersect( *pWinChildClipRegion );
+ }
+ mpWindowImpl->mnPaintFlags = 0;
+ if ( !mpWindowImpl->maInvalidateRegion.IsEmpty() )
+ {
+ if ( mpWindowImpl->mpCursor )
+ mpWindowImpl->mpCursor->ImplHide();
+
+ mbInitClipRegion = TRUE;
+ mpWindowImpl->mbInPaint = TRUE;
+
+ // Paint-Region zuruecksetzen
+ Region aPaintRegion( mpWindowImpl->maInvalidateRegion );
+ Rectangle aPaintRect = aPaintRegion.GetBoundRect();
+
+ // - RTL - re-mirror paint rect and region at this window
+ if( ImplIsAntiparallel() )
+ {
+ ImplReMirror( aPaintRect );
+ ImplReMirror( aPaintRegion );
+ }
+ aPaintRect = ImplDevicePixelToLogic( aPaintRect);
+ mpWindowImpl->mpPaintRegion = &aPaintRegion;
+ mpWindowImpl->maInvalidateRegion.SetEmpty();
+
+ if ( (nPaintFlags & IMPL_PAINT_ERASE) && IsBackground() )
+ {
+ if ( IsClipRegion() )
+ {
+ Region aOldRegion = GetClipRegion();
+ SetClipRegion();
+ Erase();
+ SetClipRegion( aOldRegion );
+ }
+ else
+ Erase();
+ }
+
+ // #98943# trigger drawing of toolbox selection after all childern are painted
+ if( mpWindowImpl->mbDrawSelectionBackground )
+ aSelectionRect = aPaintRect;
+
+ Paint( aPaintRect );
+
+ if ( mpWindowImpl->mpWinData )
+ {
+ if ( mpWindowImpl->mbFocusVisible )
+ ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) );
+ }
+ mpWindowImpl->mbInPaint = FALSE;
+ mbInitClipRegion = TRUE;
+ mpWindowImpl->mpPaintRegion = NULL;
+ if ( mpWindowImpl->mpCursor )
+ mpWindowImpl->mpCursor->ImplShow( FALSE );
+ }
+ }
+ else
+ mpWindowImpl->mnPaintFlags = 0;
+
+ if ( nPaintFlags & (IMPL_PAINT_PAINTALLCHILDS | IMPL_PAINT_PAINTCHILDS) )
+ {
+ // die Childfenster ausgeben
+ Window* pTempWindow = mpWindowImpl->mpFirstChild;
+ while ( pTempWindow )
+ {
+ if ( pTempWindow->mpWindowImpl->mbVisible )
+ pTempWindow->ImplCallPaint( pChildRegion, nPaintFlags );
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+ }
+
+ if ( mpWindowImpl->mpWinData && mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & SHOWTRACK_WINDOW) )
+ /* #98602# need to invert the tracking rect AFTER
+ * the children have painted
+ */
+ InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags );
+
+ // #98943# draw toolbox selection
+ if( !aSelectionRect.IsEmpty() )
+ DrawSelectionBackground( aSelectionRect, 3, FALSE, TRUE, FALSE );
+
+ if ( pChildRegion )
+ delete pChildRegion;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallOverlapPaint()
+{
+ // Zuerst geben wir die ueberlappenden Fenster aus
+ Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pTempWindow )
+ {
+ if ( pTempWindow->mpWindowImpl->mbReallyVisible )
+ pTempWindow->ImplCallOverlapPaint();
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+
+ // und dann erst uns selber
+ if ( mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDS) )
+ {
+ // - RTL - notify ImplCallPaint to check for re-mirroring (CHECKRTL)
+ // because we were called from the Sal layer
+ ImplCallPaint( NULL, mpWindowImpl->mnPaintFlags /*| IMPL_PAINT_CHECKRTL */);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplPostPaint()
+{
+ if ( !mpWindowImpl->mpFrameData->maPaintTimer.IsActive() )
+ mpWindowImpl->mpFrameData->maPaintTimer.Start();
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Window, ImplHandlePaintHdl, void*, EMPTYARG )
+{
+ // save paint events until resizing is done
+ if( mpWindowImpl->mbFrame && mpWindowImpl->mpFrameData->maResizeTimer.IsActive() )
+ mpWindowImpl->mpFrameData->maPaintTimer.Start();
+ else if ( mpWindowImpl->mbReallyVisible )
+ ImplCallOverlapPaint();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Window, ImplHandleResizeTimerHdl, void*, EMPTYARG )
+{
+ if( mpWindowImpl->mbReallyVisible )
+ {
+ ImplCallResize();
+ if( mpWindowImpl->mpFrameData->maPaintTimer.IsActive() )
+ {
+ mpWindowImpl->mpFrameData->maPaintTimer.Stop();
+ mpWindowImpl->mpFrameData->maPaintTimer.GetTimeoutHdl().Call( NULL );
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInvalidateFrameRegion( const Region* pRegion, USHORT nFlags )
+{
+ // PAINTCHILDS bei allen Parent-Fenster bis zum ersten OverlapWindow
+ // setzen
+ if ( !ImplIsOverlapWindow() )
+ {
+ Window* pTempWindow = this;
+ USHORT nTranspPaint = IsPaintTransparent() ? IMPL_PAINT_PAINT : 0;
+ do
+ {
+ pTempWindow = pTempWindow->ImplGetParent();
+ if ( pTempWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTCHILDS )
+ break;
+ pTempWindow->mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTCHILDS | nTranspPaint;
+ if( ! pTempWindow->IsPaintTransparent() )
+ nTranspPaint = 0;
+ }
+ while ( !pTempWindow->ImplIsOverlapWindow() );
+ }
+
+ // Paint-Flags setzen
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINT;
+ if ( nFlags & INVALIDATE_CHILDREN )
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTALLCHILDS;
+ if ( !(nFlags & INVALIDATE_NOERASE) )
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_ERASE;
+ if ( !pRegion )
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTALL;
+
+ // Wenn nicht alles neu ausgegeben werden muss, dann die Region
+ // dazupacken
+ if ( !(mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL) )
+ mpWindowImpl->maInvalidateRegion.Union( *pRegion );
+
+ // Handle transparent windows correctly: invalidate must be done on the first opaque parent
+ if( ((IsPaintTransparent() && !(nFlags & INVALIDATE_NOTRANSPARENT)) || (nFlags & INVALIDATE_TRANSPARENT) )
+ && ImplGetParent() )
+ {
+ Window *pParent = ImplGetParent();
+ while( pParent && pParent->IsPaintTransparent() )
+ pParent = pParent->ImplGetParent();
+ if( pParent )
+ {
+ Region *pChildRegion;
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
+ // invalidate the whole child window region in the parent
+ pChildRegion = ImplGetWinChildClipRegion();
+ else
+ // invalidate the same region in the parent that has to be repainted in the child
+ pChildRegion = &mpWindowImpl->maInvalidateRegion;
+
+ nFlags |= INVALIDATE_CHILDREN; // paint should also be done on all children
+ nFlags &= ~INVALIDATE_NOERASE; // parent should paint and erase to create proper background
+ pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
+ }
+ }
+ ImplPostPaint();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInvalidateOverlapFrameRegion( const Region& rRegion )
+{
+ Region aRegion = rRegion;
+
+ ImplClipBoundaries( aRegion, TRUE, TRUE );
+ if ( !aRegion.IsEmpty() )
+ ImplInvalidateFrameRegion( &aRegion, INVALIDATE_CHILDREN );
+
+ // Dann invalidieren wir die ueberlappenden Fenster
+ Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pTempWindow )
+ {
+ if ( pTempWindow->IsVisible() )
+ pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
+
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInvalidateParentFrameRegion( Region& rRegion )
+{
+ if ( mpWindowImpl->mbOverlapWin )
+ mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion );
+ else
+ {
+ if( ImplGetParent() )
+ ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, INVALIDATE_CHILDREN );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInvalidate( const Region* pRegion, USHORT nFlags )
+{
+
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+
+ // Feststellen, was neu ausgegeben werden muss
+ BOOL bInvalidateAll = !pRegion;
+
+ // Transparent-Invalidate beruecksichtigen
+ Window* pOpaqueWindow = this;
+ if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & INVALIDATE_NOTRANSPARENT)) || (nFlags & INVALIDATE_TRANSPARENT) )
+ {
+ Window* pTempWindow = pOpaqueWindow->ImplGetParent();
+ while ( pTempWindow )
+ {
+ if ( !pTempWindow->IsPaintTransparent() )
+ {
+ pOpaqueWindow = pTempWindow;
+ nFlags |= INVALIDATE_CHILDREN;
+ bInvalidateAll = FALSE;
+ break;
+ }
+
+ if ( pTempWindow->ImplIsOverlapWindow() )
+ break;
+
+ pTempWindow = pTempWindow->ImplGetParent();
+ }
+ }
+
+ // Region zusammenbauen
+ USHORT nOrgFlags = nFlags;
+ if ( !(nFlags & (INVALIDATE_CHILDREN | INVALIDATE_NOCHILDREN)) )
+ {
+ if ( GetStyle() & WB_CLIPCHILDREN )
+ nFlags |= INVALIDATE_NOCHILDREN;
+ else
+ nFlags |= INVALIDATE_CHILDREN;
+ }
+ if ( (nFlags & INVALIDATE_NOCHILDREN) && mpWindowImpl->mpFirstChild )
+ bInvalidateAll = FALSE;
+ if ( bInvalidateAll )
+ ImplInvalidateFrameRegion( NULL, nFlags );
+ else
+ {
+ Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ Region aRegion( aRect );
+ if ( pRegion )
+ {
+ // --- RTL --- remirror region before intersecting it
+ if ( ImplIsAntiparallel() )
+ {
+ Region aRgn( *pRegion );
+ ImplReMirror( aRgn );
+ aRegion.Intersect( aRgn );
+ }
+ else
+ aRegion.Intersect( *pRegion );
+ }
+ ImplClipBoundaries( aRegion, TRUE, TRUE );
+ if ( nFlags & INVALIDATE_NOCHILDREN )
+ {
+ nFlags &= ~INVALIDATE_CHILDREN;
+ if ( !(nFlags & INVALIDATE_NOCLIPCHILDREN) )
+ {
+ if ( nOrgFlags & INVALIDATE_NOCHILDREN )
+ ImplClipAllChilds( aRegion );
+ else
+ {
+ if ( ImplClipChilds( aRegion ) )
+ nFlags |= INVALIDATE_CHILDREN;
+ }
+ }
+ }
+ if ( !aRegion.IsEmpty() )
+ ImplInvalidateFrameRegion( &aRegion, nFlags ); // transparency is handled here, pOpaqueWindow not required
+ }
+
+ if ( nFlags & INVALIDATE_UPDATE )
+ pOpaqueWindow->Update(); // start painting at the opaque parent
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplMoveInvalidateRegion( const Rectangle& rRect,
+ long nHorzScroll, long nVertScroll,
+ BOOL bChilds )
+{
+ if ( (mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTALL)) == IMPL_PAINT_PAINT )
+ {
+ Region aTempRegion = mpWindowImpl->maInvalidateRegion;
+ aTempRegion.Intersect( rRect );
+ aTempRegion.Move( nHorzScroll, nVertScroll );
+ mpWindowImpl->maInvalidateRegion.Union( aTempRegion );
+ }
+
+ if ( bChilds && (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTCHILDS) )
+ {
+ Window* pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, TRUE );
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplMoveAllInvalidateRegions( const Rectangle& rRect,
+ long nHorzScroll, long nVertScroll,
+ BOOL bChilds )
+{
+ // Paint-Region auch verschieben, wenn noch Paints anstehen
+ ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChilds );
+ // Paint-Region muss bei uns verschoben gesetzt werden, die durch
+ // die Parents gezeichnet werden
+ if ( !ImplIsOverlapWindow() )
+ {
+ Region aPaintAllRegion;
+ Window* pPaintAllWindow = this;
+ do
+ {
+ pPaintAllWindow = pPaintAllWindow->ImplGetParent();
+ if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS )
+ {
+ if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
+ {
+ aPaintAllRegion.SetEmpty();
+ break;
+ }
+ else
+ aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion );
+ }
+ }
+ while ( !pPaintAllWindow->ImplIsOverlapWindow() );
+ if ( !aPaintAllRegion.IsEmpty() )
+ {
+ aPaintAllRegion.Move( nHorzScroll, nVertScroll );
+ USHORT nPaintFlags = 0;
+ if ( bChilds )
+ mpWindowImpl->mnPaintFlags |= INVALIDATE_CHILDREN;
+ ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplValidateFrameRegion( const Region* pRegion, USHORT nFlags )
+{
+ if ( !pRegion )
+ mpWindowImpl->maInvalidateRegion.SetEmpty();
+ else
+ {
+ // Wenn alle Childfenster neu ausgegeben werden muessen,
+ // dann invalidieren wir diese vorher
+ if ( (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS) && mpWindowImpl->mpFirstChild )
+ {
+ Region aChildRegion = mpWindowImpl->maInvalidateRegion;
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
+ {
+ Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ aChildRegion = aRect;
+ }
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->Invalidate( aChildRegion, INVALIDATE_CHILDREN | INVALIDATE_NOTRANSPARENT );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
+ {
+ Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ mpWindowImpl->maInvalidateRegion = aRect;
+ }
+ mpWindowImpl->maInvalidateRegion.Exclude( *pRegion );
+ }
+ mpWindowImpl->mnPaintFlags &= ~IMPL_PAINT_PAINTALL;
+
+ if ( nFlags & VALIDATE_CHILDREN )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->ImplValidateFrameRegion( pRegion, nFlags );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplValidate( const Region* pRegion, USHORT nFlags )
+{
+ // Region zusammenbauen
+ BOOL bValidateAll = !pRegion;
+ USHORT nOrgFlags = nFlags;
+ if ( !(nFlags & (VALIDATE_CHILDREN | VALIDATE_NOCHILDREN)) )
+ {
+ if ( GetStyle() & WB_CLIPCHILDREN )
+ nFlags |= VALIDATE_NOCHILDREN;
+ else
+ nFlags |= VALIDATE_CHILDREN;
+ }
+ if ( (nFlags & VALIDATE_NOCHILDREN) && mpWindowImpl->mpFirstChild )
+ bValidateAll = FALSE;
+ if ( bValidateAll )
+ ImplValidateFrameRegion( NULL, nFlags );
+ else
+ {
+ Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ Region aRegion( aRect );
+ if ( pRegion )
+ aRegion.Intersect( *pRegion );
+ ImplClipBoundaries( aRegion, TRUE, TRUE );
+ if ( nFlags & VALIDATE_NOCHILDREN )
+ {
+ nFlags &= ~VALIDATE_CHILDREN;
+ if ( nOrgFlags & VALIDATE_NOCHILDREN )
+ ImplClipAllChilds( aRegion );
+ else
+ {
+ if ( ImplClipChilds( aRegion ) )
+ nFlags |= VALIDATE_CHILDREN;
+ }
+ }
+ if ( !aRegion.IsEmpty() )
+ ImplValidateFrameRegion( &aRegion, nFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplScroll( const Rectangle& rRect,
+ long nHorzScroll, long nVertScroll, USHORT nFlags )
+{
+ if ( !IsDeviceOutputNecessary() )
+ return;
+
+ nHorzScroll = ImplLogicWidthToDevicePixel( nHorzScroll );
+ nVertScroll = ImplLogicHeightToDevicePixel( nVertScroll );
+
+ if ( !nHorzScroll && !nVertScroll )
+ return;
+
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+
+ if ( mpWindowImpl->mpCursor )
+ mpWindowImpl->mpCursor->ImplHide();
+
+ USHORT nOrgFlags = nFlags;
+ if ( !(nFlags & (SCROLL_CHILDREN | SCROLL_NOCHILDREN)) )
+ {
+ if ( GetStyle() & WB_CLIPCHILDREN )
+ nFlags |= SCROLL_NOCHILDREN;
+ else
+ nFlags |= SCROLL_CHILDREN;
+ }
+
+ Region aInvalidateRegion;
+ BOOL bScrollChilds = (nFlags & SCROLL_CHILDREN) != 0;
+ BOOL bErase = (nFlags & SCROLL_NOERASE) == 0;
+
+ if ( !mpWindowImpl->mpFirstChild )
+ bScrollChilds = FALSE;
+
+ // --- RTL --- check if this window requires special action
+ BOOL bReMirror = ( ImplIsAntiparallel() );
+
+ Rectangle aRectMirror( rRect );
+ if( bReMirror )
+ {
+ // --- RTL --- make sure the invalidate region of this window is
+ // computed in the same coordinate space as the one from the overlap windows
+ ImplReMirror( aRectMirror );
+ }
+
+ // Paint-Bereiche anpassen
+ ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChilds );
+
+ if ( !(nFlags & SCROLL_NOINVALIDATE) )
+ {
+ ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChilds, TRUE, FALSE );
+
+ // --- RTL ---
+ // if the scrolling on the device is performed in the opposite direction
+ // then move the overlaps in that direction to compute the invalidate region
+ // on the correct side, i.e., revert nHorzScroll
+
+ if ( !aInvalidateRegion.IsEmpty() )
+ {
+ aInvalidateRegion.Move( bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll );
+ bErase = TRUE;
+ }
+ if ( !(nFlags & SCROLL_NOWINDOWINVALIDATE) )
+ {
+ Rectangle aDestRect( aRectMirror );
+ aDestRect.Move( bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll );
+ Region aWinInvalidateRegion( aRectMirror );
+ aWinInvalidateRegion.Exclude( aDestRect );
+
+ aInvalidateRegion.Union( aWinInvalidateRegion );
+ }
+ }
+
+ Point aPoint( mnOutOffX, mnOutOffY );
+ Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
+ if ( nFlags & SCROLL_CLIP )
+ aRegion.Intersect( rRect );
+ if ( mpWindowImpl->mbWinRegion )
+ aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+
+ aRegion.Exclude( aInvalidateRegion );
+
+ ImplClipBoundaries( aRegion, FALSE, TRUE );
+ if ( !bScrollChilds )
+ {
+ if ( nOrgFlags & SCROLL_NOCHILDREN )
+ ImplClipAllChilds( aRegion );
+ else
+ ImplClipChilds( aRegion );
+ }
+ if ( mbClipRegion && (nFlags & SCROLL_USECLIPREGION) )
+ aRegion.Intersect( maRegion );
+ if ( !aRegion.IsEmpty() )
+ {
+ if ( mpWindowImpl->mpWinData )
+ {
+ if ( mpWindowImpl->mbFocusVisible )
+ ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) );
+ if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & SHOWTRACK_WINDOW) )
+ InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags );
+ }
+
+ SalGraphics* pGraphics = ImplGetFrameGraphics();
+ if ( pGraphics )
+ {
+ if( bReMirror )
+ {
+ // --- RTL --- frame coordinates require re-mirroring
+ ImplReMirror( aRegion );
+ }
+
+ ImplSelectClipRegion( aRegion, pGraphics );
+ pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll,
+ rRect.Left(), rRect.Top(),
+ rRect.GetWidth(), rRect.GetHeight(),
+ SAL_COPYAREA_WINDOWINVALIDATE, this );
+ }
+
+ if ( mpWindowImpl->mpWinData )
+ {
+ if ( mpWindowImpl->mbFocusVisible )
+ ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) );
+ if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & SHOWTRACK_WINDOW) )
+ InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags );
+ }
+ }
+
+ if ( !aInvalidateRegion.IsEmpty() )
+ {
+ // --- RTL --- the invalidate region for this windows is already computed in frame coordinates
+ // so it has to be re-mirrored before calling the Paint-handler
+ mpWindowImpl->mnPaintFlags |= IMPL_PAINT_CHECKRTL;
+
+ USHORT nPaintFlags = INVALIDATE_CHILDREN;
+ if ( !bErase )
+ nPaintFlags |= INVALIDATE_NOERASE;
+ if ( !bScrollChilds )
+ {
+ if ( nOrgFlags & SCROLL_NOCHILDREN )
+ ImplClipAllChilds( aInvalidateRegion );
+ else
+ ImplClipChilds( aInvalidateRegion );
+ }
+ ImplInvalidateFrameRegion( &aInvalidateRegion, nPaintFlags );
+ }
+
+ if ( bScrollChilds )
+ {
+ Window* pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ Point aPos = pWindow->GetPosPixel();
+ aPos += Point( nHorzScroll, nVertScroll );
+ pWindow->SetPosPixel( aPos );
+
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ }
+
+ if ( nFlags & SCROLL_UPDATE )
+ Update();
+
+ if ( mpWindowImpl->mpCursor )
+ mpWindowImpl->mpCursor->ImplShow( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateAll( BOOL bOverlapWindows )
+{
+ if ( !mpWindowImpl->mbReallyVisible )
+ return;
+
+ BOOL bFlush = FALSE;
+ if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
+ {
+ Point aPoint( 0, 0 );
+ Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
+ ImplInvalidateOverlapFrameRegion( aRegion );
+ if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
+ bFlush = TRUE;
+ }
+
+ // Ein Update wirkt immer auf das OverlapWindow, damit bei spaeteren
+ // Paints nicht zuviel gemalt wird, wenn dort ALLCHILDREN usw. gesetzt
+ // ist
+ Window* pWindow = ImplGetFirstOverlapWindow();
+ if ( bOverlapWindows )
+ pWindow->ImplCallOverlapPaint();
+ else
+ {
+ if ( pWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDS) )
+ pWindow->ImplCallPaint( NULL, pWindow->mpWindowImpl->mnPaintFlags );
+ }
+
+ if ( bFlush )
+ Flush();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateWindowPtr( Window* pWindow )
+{
+ if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow )
+ {
+ // Graphic freigeben
+ ImplReleaseGraphics();
+ }
+
+ mpWindowImpl->mpFrameData = pWindow->mpWindowImpl->mpFrameData;
+ mpWindowImpl->mpFrame = pWindow->mpWindowImpl->mpFrame;
+ mpWindowImpl->mpFrameWindow = pWindow->mpWindowImpl->mpFrameWindow;
+ if ( pWindow->ImplIsOverlapWindow() )
+ mpWindowImpl->mpOverlapWindow = pWindow;
+ else
+ mpWindowImpl->mpOverlapWindow = pWindow->mpWindowImpl->mpOverlapWindow;
+
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->ImplUpdateWindowPtr( pWindow );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateWindowPtr()
+{
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->ImplUpdateWindowPtr( this );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateOverlapWindowPtr( BOOL bNewFrame )
+{
+ BOOL bVisible = IsVisible();
+ Show( FALSE );
+ ImplRemoveWindow( bNewFrame );
+ Window* pRealParent = mpWindowImpl->mpRealParent;
+ ImplInsertWindow( ImplGetParent() );
+ mpWindowImpl->mpRealParent = pRealParent;
+ ImplUpdateWindowPtr();
+ if ( ImplUpdatePos() )
+ ImplUpdateSysObjPos();
+
+ if ( bNewFrame )
+ {
+ Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
+ pOverlapWindow = pNextOverlapWindow;
+ }
+ }
+
+ if ( bVisible )
+ Show( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplUpdatePos()
+{
+ BOOL bSysChild = FALSE;
+
+ if ( ImplIsOverlapWindow() )
+ {
+ mnOutOffX = mpWindowImpl->mnX;
+ mnOutOffY = mpWindowImpl->mnY;
+ }
+ else
+ {
+ Window* pParent = ImplGetParent();
+
+ mnOutOffX = mpWindowImpl->mnX + pParent->mnOutOffX;
+ mnOutOffY = mpWindowImpl->mnY + pParent->mnOutOffY;
+ }
+
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ if ( pChild->ImplUpdatePos() )
+ bSysChild = TRUE;
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+
+ if ( mpWindowImpl->mpSysObj )
+ bSysChild = TRUE;
+
+ return bSysChild;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplUpdateSysObjPos()
+{
+ if ( mpWindowImpl->mpSysObj )
+ mpWindowImpl->mpSysObj->SetPosSize( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight );
+
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->ImplUpdateSysObjPos();
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+// -----------------------------------------------------------------------
+
+void Window::ImplPosSizeWindow( long nX, long nY,
+ long nWidth, long nHeight, USHORT nFlags )
+{
+ BOOL bNewPos = FALSE;
+ BOOL bNewSize = FALSE;
+ BOOL bNewWidth = FALSE;
+ BOOL bCopyBits = FALSE;
+ long nOldOutOffX = mnOutOffX;
+ long nOldOutOffY = mnOutOffY;
+ long nOldOutWidth = mnOutWidth;
+ long nOldOutHeight = mnOutHeight;
+ Region* pOverlapRegion = NULL;
+ Region* pOldRegion = NULL;
+
+ if ( IsReallyVisible() )
+ {
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+
+ Rectangle aOldWinRect( Point( nOldOutOffX, nOldOutOffY ),
+ Size( nOldOutWidth, nOldOutHeight ) );
+ pOldRegion = new Region( aOldWinRect );
+ if ( mpWindowImpl->mbWinRegion )
+ pOldRegion->Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+
+ if ( mnOutWidth && mnOutHeight && !mpWindowImpl->mbPaintTransparent &&
+ !mpWindowImpl->mbInitWinClipRegion && !mpWindowImpl->maWinClipRegion.IsEmpty() &&
+ !HasPaintEvent() )
+ bCopyBits = TRUE;
+ }
+
+ BOOL bnXRecycled = FALSE; // avoid duplicate mirroring in RTL case
+ if ( nFlags & WINDOW_POSSIZE_WIDTH )
+ {
+ if(!( nFlags & WINDOW_POSSIZE_X ))
+ {
+ nX = mpWindowImpl->mnX;
+ nFlags |= WINDOW_POSSIZE_X;
+ bnXRecycled = TRUE; // we're using a mnX which was already mirrored in RTL case
+ }
+
+ if ( nWidth < 0 )
+ nWidth = 0;
+ if ( nWidth != mnOutWidth )
+ {
+ mnOutWidth = nWidth;
+ bNewSize = TRUE;
+ bCopyBits = FALSE;
+ bNewWidth = TRUE;
+ }
+ }
+ if ( nFlags & WINDOW_POSSIZE_HEIGHT )
+ {
+ if ( nHeight < 0 )
+ nHeight = 0;
+ if ( nHeight != mnOutHeight )
+ {
+ mnOutHeight = nHeight;
+ bNewSize = TRUE;
+ bCopyBits = FALSE;
+ }
+ }
+
+ if ( nFlags & WINDOW_POSSIZE_X )
+ {
+ long nOrgX = nX;
+ // --- RTL --- (compare the screen coordinates)
+ Point aPtDev( Point( nX+mnOutOffX, 0 ) );
+ if( ImplHasMirroredGraphics() )
+ {
+ mpGraphics->mirror( aPtDev.X(), this );
+
+ // #106948# always mirror our pos if our parent is not mirroring, even
+ // if we are also not mirroring
+ // --- RTL --- check if parent is in different coordinates
+ if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() )
+ {
+ // --- RTL --- (re-mirror at parent window)
+ nX = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - nX;
+ }
+ /* #i99166# An LTR window in RTL UI that gets sized only would be
+ expected to not moved its upper left point
+ */
+ if( bnXRecycled )
+ {
+ if( ImplIsAntiparallel() )
+ {
+ aPtDev.X() = mpWindowImpl->mnAbsScreenX;
+ nOrgX = mpWindowImpl->maPos.X();
+ }
+ }
+ }
+ else if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() )
+ {
+ // mirrored window in LTR UI
+ {
+ // --- RTL --- (re-mirror at parent window)
+ nX = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - nX;
+ }
+ }
+
+ // check maPos as well, as it could have been changed for client windows (ImplCallMove())
+ if ( mpWindowImpl->mnAbsScreenX != aPtDev.X() || nX != mpWindowImpl->mnX || nOrgX != mpWindowImpl->maPos.X() )
+ {
+ if ( bCopyBits && !pOverlapRegion )
+ {
+ pOverlapRegion = new Region();
+ ImplCalcOverlapRegion( Rectangle( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) ),
+ *pOverlapRegion, FALSE, TRUE, TRUE );
+ }
+ mpWindowImpl->mnX = nX;
+ mpWindowImpl->maPos.X() = nOrgX;
+ mpWindowImpl->mnAbsScreenX = aPtDev.X(); // --- RTL --- (store real screen pos)
+ bNewPos = TRUE;
+ }
+ }
+ if ( nFlags & WINDOW_POSSIZE_Y )
+ {
+ // check maPos as well, as it could have been changed for client windows (ImplCallMove())
+ if ( nY != mpWindowImpl->mnY || nY != mpWindowImpl->maPos.Y() )
+ {
+ if ( bCopyBits && !pOverlapRegion )
+ {
+ pOverlapRegion = new Region();
+ ImplCalcOverlapRegion( Rectangle( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) ),
+ *pOverlapRegion, FALSE, TRUE, TRUE );
+ }
+ mpWindowImpl->mnY = nY;
+ mpWindowImpl->maPos.Y() = nY;
+ bNewPos = TRUE;
+ }
+ }
+
+/* if ( nFlags & (WINDOW_POSSIZE_X|WINDOW_POSSIZE_Y) )
+ {
+ POINT aPt;
+ aPt.x = mpWindowImpl->maPos.X();
+ aPt.y = mpWindowImpl->maPos.Y();
+ ClientToScreen( mpWindowImpl->mpFrame->maFrameData.mhWnd , &aPt );
+ mpWindowImpl->maPos.X() = aPt.x;
+ mpWindowImpl->maPos.Y() = aPt.y;
+ }
+*/
+ if ( bNewPos || bNewSize )
+ {
+ BOOL bUpdateSysObjPos = FALSE;
+ if ( bNewPos )
+ bUpdateSysObjPos = ImplUpdatePos();
+
+ // the borderwindow always specifies the position for its client window
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->maPos = mpWindowImpl->mpBorderWindow->mpWindowImpl->maPos;
+
+ if ( mpWindowImpl->mpClientWindow )
+ {
+ mpWindowImpl->mpClientWindow->ImplPosSizeWindow( mpWindowImpl->mpClientWindow->mpWindowImpl->mnLeftBorder,
+ mpWindowImpl->mpClientWindow->mpWindowImpl->mnTopBorder,
+ mnOutWidth-mpWindowImpl->mpClientWindow->mpWindowImpl->mnLeftBorder-mpWindowImpl->mpClientWindow->mpWindowImpl->mnRightBorder,
+ mnOutHeight-mpWindowImpl->mpClientWindow->mpWindowImpl->mnTopBorder-mpWindowImpl->mpClientWindow->mpWindowImpl->mnBottomBorder,
+ WINDOW_POSSIZE_X | WINDOW_POSSIZE_Y |
+ WINDOW_POSSIZE_WIDTH | WINDOW_POSSIZE_HEIGHT );
+ // Wenn wir ein ClientWindow haben, dann hat dieses fuer die
+ // Applikation auch die Position des FloatingWindows
+ mpWindowImpl->mpClientWindow->mpWindowImpl->maPos = mpWindowImpl->maPos;
+ if ( bNewPos )
+ {
+ if ( mpWindowImpl->mpClientWindow->IsVisible() )
+ {
+ mpWindowImpl->mpClientWindow->ImplCallMove();
+ }
+ else
+ {
+ mpWindowImpl->mpClientWindow->mpWindowImpl->mbCallMove = TRUE;
+ }
+ }
+ }
+// else
+// {
+// if ( mpWindowImpl->mpBorderWindow )
+// mpWindowImpl->maPos = mpWindowImpl->mpBorderWindow->mpWindowImpl->maPos;
+// }
+
+ // Move()/Resize() werden erst bei Show() gerufen, damit min. eins vor
+ // einem Show() kommt
+ if ( IsVisible() )
+ {
+ if ( bNewPos )
+ {
+ ImplCallMove();
+ }
+ if ( bNewSize )
+ {
+ ImplCallResize();
+ }
+ }
+ else
+ {
+ if ( bNewPos )
+ mpWindowImpl->mbCallMove = TRUE;
+ if ( bNewSize )
+ mpWindowImpl->mbCallResize = TRUE;
+ }
+
+ BOOL bUpdateSysObjClip = FALSE;
+ if ( IsReallyVisible() )
+ {
+ if ( bNewPos || bNewSize )
+ {
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mpSaveBackDev )
+ ImplDeleteOverlapBackground();
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+ // Clip-Flag neu setzen
+ bUpdateSysObjClip = !ImplSetClipFlag( TRUE );
+ }
+
+ // Fensterinhalt invalidieren ?
+ if ( bNewPos || (mnOutWidth > nOldOutWidth) || (mnOutHeight > nOldOutHeight) )
+ {
+ if ( bNewPos )
+ {
+ BOOL bInvalidate = FALSE;
+ BOOL bParentPaint = TRUE;
+ if ( !ImplIsOverlapWindow() )
+ bParentPaint = mpWindowImpl->mpParent->IsPaintEnabled();
+ if ( bCopyBits && bParentPaint && !HasPaintEvent() )
+ {
+ Point aPoint( mnOutOffX, mnOutOffY );
+ Region aRegion( Rectangle( aPoint,
+ Size( mnOutWidth, mnOutHeight ) ) );
+ if ( mpWindowImpl->mbWinRegion )
+ aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+ ImplClipBoundaries( aRegion, FALSE, TRUE );
+ if ( !pOverlapRegion->IsEmpty() )
+ {
+ pOverlapRegion->Move( mnOutOffX-nOldOutOffX, mnOutOffY-nOldOutOffY );
+ aRegion.Exclude( *pOverlapRegion );
+ }
+ if ( !aRegion.IsEmpty() )
+ {
+ // Paint-Bereiche anpassen
+ ImplMoveAllInvalidateRegions( Rectangle( Point( nOldOutOffX, nOldOutOffY ),
+ Size( nOldOutWidth, nOldOutHeight ) ),
+ mnOutOffX-nOldOutOffX, mnOutOffY-nOldOutOffY,
+ TRUE );
+ SalGraphics* pGraphics = ImplGetFrameGraphics();
+ if ( pGraphics )
+ {
+ const bool bSelectClipRegion = ImplSelectClipRegion( aRegion, pGraphics );
+ if ( bSelectClipRegion )
+ {
+ pGraphics->CopyArea( mnOutOffX, mnOutOffY,
+ nOldOutOffX, nOldOutOffY,
+ nOldOutWidth, nOldOutHeight,
+ SAL_COPYAREA_WINDOWINVALIDATE, this );
+ }
+ else
+ bInvalidate = TRUE;
+ }
+ else
+ bInvalidate = TRUE;
+ if ( !bInvalidate )
+ {
+ if ( !pOverlapRegion->IsEmpty() )
+ ImplInvalidateFrameRegion( pOverlapRegion, INVALIDATE_CHILDREN );
+ }
+ }
+ else
+ bInvalidate = TRUE;
+ }
+ else
+ bInvalidate = TRUE;
+ if ( bInvalidate )
+ ImplInvalidateFrameRegion( NULL, INVALIDATE_CHILDREN );
+ }
+ else
+ {
+ Point aPoint( mnOutOffX, mnOutOffY );
+ Region aRegion( Rectangle( aPoint,
+ Size( mnOutWidth, mnOutHeight ) ) );
+ aRegion.Exclude( *pOldRegion );
+ if ( mpWindowImpl->mbWinRegion )
+ aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
+ ImplClipBoundaries( aRegion, FALSE, TRUE );
+ if ( !aRegion.IsEmpty() )
+ ImplInvalidateFrameRegion( &aRegion, INVALIDATE_CHILDREN );
+ }
+ }
+
+ // Parent oder Overlaps invalidieren
+ if ( bNewPos ||
+ (mnOutWidth < nOldOutWidth) || (mnOutHeight < nOldOutHeight) )
+ {
+ Region aRegion( *pOldRegion );
+ if ( !mpWindowImpl->mbPaintTransparent )
+ ImplExcludeWindowRegion( aRegion );
+ ImplClipBoundaries( aRegion, FALSE, TRUE );
+ if ( !aRegion.IsEmpty() && !mpWindowImpl->mpBorderWindow )
+ ImplInvalidateParentFrameRegion( aRegion );
+ }
+ }
+
+ // System-Objekte anpassen
+ if ( bUpdateSysObjClip )
+ ImplUpdateSysObjClip();
+ if ( bUpdateSysObjPos )
+ ImplUpdateSysObjPos();
+ if ( bNewSize && mpWindowImpl->mpSysObj )
+ mpWindowImpl->mpSysObj->SetPosSize( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight );
+ }
+
+ if ( pOverlapRegion )
+ delete pOverlapRegion;
+ if ( pOldRegion )
+ delete pOldRegion;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplToBottomChild()
+{
+ if ( !ImplIsOverlapWindow() && !mpWindowImpl->mbReallyVisible && (mpWindowImpl->mpParent->mpWindowImpl->mpLastChild != this) )
+ {
+ // Fenster an das Ende der Liste setzen
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ mpWindowImpl->mpPrev = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ mpWindowImpl->mpNext = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCalcToTop( ImplCalcToTopData* pPrevData )
+{
+ DBG_ASSERT( ImplIsOverlapWindow(), "Window::ImplCalcToTop(): Is not a OverlapWindow" );
+
+ if ( !mpWindowImpl->mbFrame )
+ {
+ if ( IsReallyVisible() )
+ {
+ // Region berechnen, wo das Fenster mit anderen Fenstern ueberlappt
+ Point aPoint( mnOutOffX, mnOutOffY );
+ Region aRegion( Rectangle( aPoint,
+ Size( mnOutWidth, mnOutHeight ) ) );
+ Region aInvalidateRegion;
+ ImplCalcOverlapRegionOverlaps( aRegion, aInvalidateRegion );
+
+ if ( !aInvalidateRegion.IsEmpty() )
+ {
+ ImplCalcToTopData* pData = new ImplCalcToTopData;
+ pPrevData->mpNext = pData;
+ pData->mpNext = NULL;
+ pData->mpWindow = this;
+ pData->mpInvalidateRegion = new Region( aInvalidateRegion );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCalcChildOverlapToTop( ImplCalcToTopData* pPrevData )
+{
+ DBG_ASSERT( ImplIsOverlapWindow(), "Window::ImplCalcChildOverlapToTop(): Is not a OverlapWindow" );
+
+ ImplCalcToTop( pPrevData );
+ if ( pPrevData->mpNext )
+ pPrevData = pPrevData->mpNext;
+
+ Window* pOverlap = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlap )
+ {
+ pOverlap->ImplCalcToTop( pPrevData );
+ if ( pPrevData->mpNext )
+ pPrevData = pPrevData->mpNext;
+ pOverlap = pOverlap->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplToTop( USHORT nFlags )
+{
+ DBG_ASSERT( ImplIsOverlapWindow(), "Window::ImplToTop(): Is not a OverlapWindow" );
+
+ if ( mpWindowImpl->mbFrame )
+ {
+ // Wenn in das externe Fenster geklickt wird, ist dieses
+ // dafuer zustaendig dafuer zu sorgen, das unser Frame
+ // nach vorne kommt
+ if ( !mpWindowImpl->mpFrameData->mbHasFocus &&
+ !mpWindowImpl->mpFrameData->mbSysObjFocus &&
+ !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl &&
+ !mpWindowImpl->mpFrameData->mbInSysObjToTopHdl )
+ {
+ // do not bring floating windows on the client to top
+ if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN) )
+ {
+ USHORT nSysFlags = 0;
+ if ( nFlags & TOTOP_RESTOREWHENMIN )
+ nSysFlags |= SAL_FRAME_TOTOP_RESTOREWHENMIN;
+ if ( nFlags & TOTOP_FOREGROUNDTASK )
+ nSysFlags |= SAL_FRAME_TOTOP_FOREGROUNDTASK;
+ if ( nFlags & TOTOP_GRABFOCUSONLY )
+ nSysFlags |= SAL_FRAME_TOTOP_GRABFOCUS_ONLY;
+ mpWindowImpl->mpFrame->ToTop( nSysFlags );
+ }
+ }
+ }
+ else
+ {
+ if ( mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap != this )
+ {
+ // Fenster aus der Liste entfernen
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+
+ // AlwaysOnTop beruecksichtigen
+ BOOL bOnTop = IsAlwaysOnTopEnabled();
+ Window* pNextWin = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ if ( !bOnTop )
+ {
+ while ( pNextWin )
+ {
+ if ( !pNextWin->IsAlwaysOnTopEnabled() )
+ break;
+ pNextWin = pNextWin->mpWindowImpl->mpNext;
+ }
+ }
+
+ // TopLevel abpruefen
+ BYTE nTopLevel = mpWindowImpl->mpOverlapData->mnTopLevel;
+ while ( pNextWin )
+ {
+ if ( (bOnTop != pNextWin->IsAlwaysOnTopEnabled()) ||
+ (nTopLevel <= pNextWin->mpWindowImpl->mpOverlapData->mnTopLevel) )
+ break;
+ pNextWin = pNextWin->mpWindowImpl->mpNext;
+ }
+
+ // Fenster in die Liste wieder eintragen
+ mpWindowImpl->mpNext = pNextWin;
+ if ( pNextWin )
+ {
+ mpWindowImpl->mpPrev = pNextWin->mpWindowImpl->mpPrev;
+ pNextWin->mpWindowImpl->mpPrev = this;
+ }
+ else
+ {
+ mpWindowImpl->mpPrev = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
+ }
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
+
+ // ClipRegion muss von diesem Fenster und allen weiteren
+ // ueberlappenden Fenstern neu berechnet werden.
+ if ( IsReallyVisible() )
+ {
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+ mpWindowImpl->mpOverlapWindow->ImplSetClipFlagOverlapWindows();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplStartToTop( USHORT nFlags )
+{
+ ImplCalcToTopData aStartData;
+ ImplCalcToTopData* pCurData;
+ ImplCalcToTopData* pNextData;
+ Window* pOverlapWindow;
+ if ( ImplIsOverlapWindow() )
+ pOverlapWindow = this;
+ else
+ pOverlapWindow = mpWindowImpl->mpOverlapWindow;
+
+ // Zuerst die Paint-Bereiche berechnen
+ Window* pTempOverlapWindow = pOverlapWindow;
+ aStartData.mpNext = NULL;
+ pCurData = &aStartData;
+ do
+ {
+ pTempOverlapWindow->ImplCalcToTop( pCurData );
+ if ( pCurData->mpNext )
+ pCurData = pCurData->mpNext;
+ pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
+ // Dann die Paint-Bereiche der ChildOverlap-Windows berechnen
+ pTempOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pTempOverlapWindow )
+ {
+ pTempOverlapWindow->ImplCalcToTop( pCurData );
+ if ( pCurData->mpNext )
+ pCurData = pCurData->mpNext;
+ pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpNext;
+ }
+
+ // Dann die Fenster-Verkettung aendern
+ pTempOverlapWindow = pOverlapWindow;
+ do
+ {
+ pTempOverlapWindow->ImplToTop( nFlags );
+ pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
+ // Und zum Schluss invalidieren wir die ungueltigen Bereiche
+ pCurData = aStartData.mpNext;
+ while ( pCurData )
+ {
+ pCurData->mpWindow->ImplInvalidateFrameRegion( pCurData->mpInvalidateRegion, INVALIDATE_CHILDREN );
+ pNextData = pCurData->mpNext;
+ delete pCurData->mpInvalidateRegion;
+ delete pCurData;
+ pCurData = pNextData;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplFocusToTop( USHORT nFlags, BOOL bReallyVisible )
+{
+ // Soll Focus auch geholt werden?
+ if ( !(nFlags & TOTOP_NOGRABFOCUS) )
+ {
+ // Erstes Fenster mit GrabFocus-Activate bekommt den Focus
+ Window* pFocusWindow = this;
+ while ( !pFocusWindow->ImplIsOverlapWindow() )
+ {
+ // Nur wenn Fenster kein Border-Fenster hat, da wir
+ // immer das dazugehoerende BorderFenster finden wollen
+ if ( !pFocusWindow->mpWindowImpl->mpBorderWindow )
+ {
+ if ( pFocusWindow->mpWindowImpl->mnActivateMode & ACTIVATE_MODE_GRABFOCUS )
+ break;
+ }
+ pFocusWindow = pFocusWindow->ImplGetParent();
+ }
+ if ( (pFocusWindow->mpWindowImpl->mnActivateMode & ACTIVATE_MODE_GRABFOCUS) &&
+ !pFocusWindow->HasChildPathFocus( TRUE ) )
+ pFocusWindow->GrabFocus();
+ }
+
+ if ( bReallyVisible )
+ ImplGenerateMouseMove();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplShowAllOverlaps()
+{
+ Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ if ( pOverlapWindow->mpWindowImpl->mbOverlapVisible )
+ {
+ pOverlapWindow->Show( TRUE, SHOW_NOACTIVATE );
+ pOverlapWindow->mpWindowImpl->mbOverlapVisible = FALSE;
+ }
+
+ pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplHideAllOverlaps()
+{
+ Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ if ( pOverlapWindow->IsVisible() )
+ {
+ pOverlapWindow->mpWindowImpl->mbOverlapVisible = TRUE;
+ pOverlapWindow->Show( FALSE );
+ }
+
+ pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallMouseMove( USHORT nMouseCode, BOOL bModChanged )
+{
+ if ( mpWindowImpl->mpFrameData->mbMouseIn && mpWindowImpl->mpFrameWindow->mpWindowImpl->mbReallyVisible )
+ {
+ ULONG nTime = Time::GetSystemTicks();
+ long nX = mpWindowImpl->mpFrameData->mnLastMouseX;
+ long nY = mpWindowImpl->mpFrameData->mnLastMouseY;
+ USHORT nCode = nMouseCode;
+ USHORT nMode = mpWindowImpl->mpFrameData->mnMouseMode;
+ BOOL bLeave;
+ // Auf MouseLeave testen
+ if ( ((nX < 0) || (nY < 0) ||
+ (nX >= mpWindowImpl->mpFrameWindow->mnOutWidth) ||
+ (nY >= mpWindowImpl->mpFrameWindow->mnOutHeight)) &&
+ !ImplGetSVData()->maWinData.mpCaptureWin )
+ bLeave = TRUE;
+ else
+ bLeave = FALSE;
+ nMode |= MOUSE_SYNTHETIC;
+ if ( bModChanged )
+ nMode |= MOUSE_MODIFIERCHANGED;
+ ImplHandleMouseEvent( mpWindowImpl->mpFrameWindow, EVENT_MOUSEMOVE, bLeave, nX, nY, nTime, nCode, nMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplGenerateMouseMove()
+{
+ if ( !mpWindowImpl->mpFrameData->mnMouseMoveId )
+ Application::PostUserEvent( mpWindowImpl->mpFrameData->mnMouseMoveId, LINK( mpWindowImpl->mpFrameWindow, Window, ImplGenerateMouseMoveHdl ) );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Window, ImplGenerateMouseMoveHdl, void*, EMPTYARG )
+{
+ mpWindowImpl->mpFrameData->mnMouseMoveId = 0;
+ Window* pCaptureWin = ImplGetSVData()->maWinData.mpCaptureWin;
+ if( ! pCaptureWin ||
+ (pCaptureWin->mpWindowImpl && pCaptureWin->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame)
+ )
+ {
+ ImplCallMouseMove( mpWindowImpl->mpFrameData->mnMouseCode );
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInvertFocus( const Rectangle& rRect )
+{
+ InvertTracking( rRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallFocusChangeActivate( Window* pNewOverlapWindow,
+ Window* pOldOverlapWindow )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pNewRealWindow;
+ Window* pOldRealWindow;
+ Window* pLastRealWindow;
+ BOOL bCallActivate = TRUE;
+ BOOL bCallDeactivate = TRUE;
+
+ pOldRealWindow = pOldOverlapWindow->ImplGetWindow();
+ pNewRealWindow = pNewOverlapWindow->ImplGetWindow();
+ if ( (pOldRealWindow->GetType() != WINDOW_FLOATINGWINDOW) ||
+ pOldRealWindow->GetActivateMode() )
+ {
+ if ( (pNewRealWindow->GetType() == WINDOW_FLOATINGWINDOW) &&
+ !pNewRealWindow->GetActivateMode() )
+ {
+ pSVData->maWinData.mpLastDeacWin = pOldOverlapWindow;
+ bCallDeactivate = FALSE;
+ }
+ }
+ else if ( (pNewRealWindow->GetType() != WINDOW_FLOATINGWINDOW) ||
+ pNewRealWindow->GetActivateMode() )
+ {
+ if ( pSVData->maWinData.mpLastDeacWin )
+ {
+ if ( pSVData->maWinData.mpLastDeacWin == pNewOverlapWindow )
+ bCallActivate = FALSE;
+ else
+ {
+ pLastRealWindow = pSVData->maWinData.mpLastDeacWin->ImplGetWindow();
+ pSVData->maWinData.mpLastDeacWin->mpWindowImpl->mbActive = FALSE;
+ pSVData->maWinData.mpLastDeacWin->Deactivate();
+ if ( pLastRealWindow != pSVData->maWinData.mpLastDeacWin )
+ {
+ pLastRealWindow->mpWindowImpl->mbActive = TRUE;
+ pLastRealWindow->Activate();
+ }
+ }
+ pSVData->maWinData.mpLastDeacWin = NULL;
+ }
+ }
+
+ if ( bCallDeactivate )
+ {
+ if( pOldOverlapWindow->mpWindowImpl->mbActive )
+ {
+ pOldOverlapWindow->mpWindowImpl->mbActive = FALSE;
+ pOldOverlapWindow->Deactivate();
+ }
+ if ( pOldRealWindow != pOldOverlapWindow )
+ {
+ if( pOldRealWindow->mpWindowImpl->mbActive )
+ {
+ pOldRealWindow->mpWindowImpl->mbActive = FALSE;
+ pOldRealWindow->Deactivate();
+ }
+ }
+ }
+ if ( bCallActivate && ! pNewOverlapWindow->mpWindowImpl->mbActive )
+ {
+ if( ! pNewOverlapWindow->mpWindowImpl->mbActive )
+ {
+ pNewOverlapWindow->mpWindowImpl->mbActive = TRUE;
+ pNewOverlapWindow->Activate();
+ }
+ if ( pNewRealWindow != pNewOverlapWindow )
+ {
+ if( ! pNewRealWindow->mpWindowImpl->mbActive )
+ {
+ pNewRealWindow->mpWindowImpl->mbActive = TRUE;
+ pNewRealWindow->Activate();
+ }
+ }
+ }
+}
+
+static bool IsWindowFocused(const WindowImpl& rWinImpl)
+{
+ if (rWinImpl.mpSysObj)
+ return true;
+
+ if (rWinImpl.mpFrameData->mbHasFocus)
+ return true;
+
+ if (rWinImpl.mbFakeFocusSet)
+ return true;
+
+ return false;
+}
+
+// -----------------------------------------------------------------------
+void Window::ImplGrabFocus( USHORT nFlags )
+{
+ // #143570# no focus for destructing windows
+ if( mpWindowImpl->mbInDtor )
+ return;
+
+ // some event listeners do really bad stuff
+ // => prepare for the worst
+ ImplDelData aDogTag( this );
+
+ // Currently the client window should always get the focus
+ // Should the border window at some point be focusable
+ // we need to change all GrabFocus() instances in VCL,
+ // e.g. in ToTop()
+
+ if ( mpWindowImpl->mpClientWindow )
+ {
+ // For a lack of design we need a little hack here to
+ // ensure that dialogs on close pass the focus back to
+ // the correct window
+ if ( mpWindowImpl->mpLastFocusWindow && (mpWindowImpl->mpLastFocusWindow != this) &&
+ !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) &&
+ mpWindowImpl->mpLastFocusWindow->IsEnabled() &&
+ mpWindowImpl->mpLastFocusWindow->IsInputEnabled() &&
+ ! mpWindowImpl->mpLastFocusWindow->IsInModalMode()
+ )
+ mpWindowImpl->mpLastFocusWindow->GrabFocus();
+ else
+ mpWindowImpl->mpClientWindow->GrabFocus();
+ return;
+ }
+ else if ( mpWindowImpl->mbFrame )
+ {
+ // For a lack of design we need a little hack here to
+ // ensure that dialogs on close pass the focus back to
+ // the correct window
+ if ( mpWindowImpl->mpLastFocusWindow && (mpWindowImpl->mpLastFocusWindow != this) &&
+ !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) &&
+ mpWindowImpl->mpLastFocusWindow->IsEnabled() &&
+ mpWindowImpl->mpLastFocusWindow->IsInputEnabled() &&
+ ! mpWindowImpl->mpLastFocusWindow->IsInModalMode()
+ )
+ {
+ mpWindowImpl->mpLastFocusWindow->GrabFocus();
+ return;
+ }
+ }
+
+ // If the Window is disabled, then we don't change the focus
+ if ( !IsEnabled() || !IsInputEnabled() || IsInModalMode() )
+ return;
+
+ // we only need to set the focus if it is not already set
+ // note: if some other frame is waiting for an asynchrounous focus event
+ // we also have to post an asynchronous focus event for this frame
+ // which is done using ToTop
+ ImplSVData* pSVData = ImplGetSVData();
+
+ BOOL bAsyncFocusWaiting = FALSE;
+ Window *pFrame = pSVData->maWinData.mpFirstFrame;
+ while( pFrame )
+ {
+ if( pFrame != mpWindowImpl->mpFrameWindow && pFrame->mpWindowImpl->mpFrameData->mnFocusId )
+ {
+ bAsyncFocusWaiting = TRUE;
+ break;
+ }
+ pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+
+ bool bHasFocus = IsWindowFocused(*mpWindowImpl);
+
+ BOOL bMustNotGrabFocus = FALSE;
+ // #100242#, check parent hierarchy if some floater prohibits grab focus
+
+ Window *pParent = this;
+ while( pParent )
+ {
+ // #102158#, ignore grabfocus only if the floating parent grabs keyboard focus by itself (GrabsFocus())
+ // otherwise we cannot set the focus in a floating toolbox
+ if( ( (pParent->mpWindowImpl->mbFloatWin && ((FloatingWindow*)pParent)->GrabsFocus()) || ( pParent->GetStyle() & WB_SYSTEMFLOATWIN ) ) && !( pParent->GetStyle() & WB_MOVEABLE ) )
+ {
+ bMustNotGrabFocus = TRUE;
+ break;
+ }
+ pParent = pParent->mpWindowImpl->mpParent;
+ }
+
+
+ if ( ( pSVData->maWinData.mpFocusWin != this && ! mpWindowImpl->mbInDtor ) || ( bAsyncFocusWaiting && !bHasFocus && !bMustNotGrabFocus ) )
+ {
+ // EndExtTextInput if it is not the same window
+ if ( pSVData->maWinData.mpExtTextInputWin &&
+ (pSVData->maWinData.mpExtTextInputWin != this) )
+ pSVData->maWinData.mpExtTextInputWin->EndExtTextInput( EXTTEXTINPUT_END_COMPLETE );
+
+ // Dieses Fenster als letztes FocusWindow merken
+ Window* pOverlapWindow = ImplGetFirstOverlapWindow();
+ pOverlapWindow->mpWindowImpl->mpLastFocusWindow = this;
+ mpWindowImpl->mpFrameData->mpFocusWin = this;
+
+ if( !bHasFocus )
+ {
+ // menue windows never get the system focus
+ // the application will keep the focus
+ if( bMustNotGrabFocus )
+ return;
+ else
+ {
+ // Hier setzen wir schon den Focus um, da ToTop() den Focus
+ // nicht auf ein anderes Fenster setzen darf
+ //DBG_WARNING( "Window::GrabFocus() - Frame doesn't have the focus" );
+ mpWindowImpl->mpFrame->ToTop( SAL_FRAME_TOTOP_GRABFOCUS | SAL_FRAME_TOTOP_GRABFOCUS_ONLY );
+ return;
+ }
+ }
+
+ Window* pOldFocusWindow = pSVData->maWinData.mpFocusWin;
+ ImplDelData aOldFocusDel( pOldFocusWindow );
+
+ pSVData->maWinData.mpFocusWin = this;
+
+ if ( pOldFocusWindow )
+ {
+ // Cursor hiden
+ if ( pOldFocusWindow->mpWindowImpl->mpCursor )
+ pOldFocusWindow->mpWindowImpl->mpCursor->ImplHide();
+ }
+
+ // !!!!! Wegen altem SV-Office Activate/Deavtivate Handling
+ // !!!!! erstmal so wie frueher
+ if ( pOldFocusWindow )
+ {
+ // Focus merken
+ Window* pOldOverlapWindow = pOldFocusWindow->ImplGetFirstOverlapWindow();
+ Window* pNewOverlapWindow = ImplGetFirstOverlapWindow();
+ if ( pOldOverlapWindow != pNewOverlapWindow )
+ ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow );
+ }
+ else
+ {
+ Window* pNewOverlapWindow = ImplGetFirstOverlapWindow();
+ Window* pNewRealWindow = pNewOverlapWindow->ImplGetWindow();
+ pNewOverlapWindow->mpWindowImpl->mbActive = TRUE;
+ pNewOverlapWindow->Activate();
+ if ( pNewRealWindow != pNewOverlapWindow )
+ {
+ pNewRealWindow->mpWindowImpl->mbActive = TRUE;
+ pNewRealWindow->Activate();
+ }
+ }
+/*
+ // call Deactivate and Activate
+ Window* pDeactivateParent;
+ Window* pActivateParent;
+ Window* pParent;
+ Window* pLastParent;
+ pDeactivateParent = pOldFocusWindow;
+ while ( pDeactivateParent )
+ {
+ pParent = pDeactivateParent;
+ if ( pParent->ImplIsChild( this ) )
+ break;
+
+ if ( pDeactivateParent->ImplIsOverlapWindow() )
+ {
+ if ( !pDeactivateParent->mpWindowImpl->mbParentActive )
+ break;
+ }
+
+ pDeactivateParent = pDeactivateParent->ImplGetParent();
+ }
+ if ( pOldFocusWindow )
+ {
+ pActivateParent = this;
+ while ( pActivateParent )
+ {
+ pParent = pActivateParent;
+ if ( pParent->ImplIsChild( pOldFocusWindow ) )
+ break;
+
+ if ( pActivateParent->ImplIsOverlapWindow() )
+ {
+ if ( !pActivateParent->mpWindowImpl->mbParentActive )
+ break;
+ }
+
+ pActivateParent = pActivateParent->ImplGetParent();
+ }
+ }
+ else
+ {
+ if ( ImplIsOverlapWindow() )
+ pActivateParent = this;
+ else
+ pActivateParent = mpWindowImpl->mpOverlapWindow;
+ while ( pActivateParent )
+ {
+ if ( pActivateParent->ImplIsOverlapWindow() )
+ {
+ if ( !pActivateParent->mpWindowImpl->mbParentActive )
+ break;
+ }
+
+ pActivateParent = pActivateParent->ImplGetParent();
+ }
+ }
+ if ( pDeactivateParent )
+ {
+ do
+ {
+ pLastParent = pOldFocusWindow;
+ if ( pLastParent != pDeactivateParent )
+ {
+ pParent = pLastParent->ImplGetParent();
+ while ( pParent )
+ {
+ if ( pParent == pDeactivateParent )
+ break;
+ pLastParent = pParent;
+ pParent = pParent->ImplGetParent();
+ }
+ }
+ else
+ pParent = pLastParent;
+
+ pParent->mpWindowImpl->mbActive = FALSE;
+ pParent->Deactivate();
+ pDeactivateParent = pLastParent;
+ }
+ while ( pDeactivateParent != pOldFocusWindow );
+ }
+ do
+ {
+ pLastParent = this;
+ if ( pLastParent != pActivateParent )
+ {
+ pParent = pLastParent->ImplGetParent();
+ while ( pParent )
+ {
+ if ( pParent == pActivateParent )
+ break;
+ pLastParent = pParent;
+ pParent = pParent->ImplGetParent();
+ }
+ }
+ else
+ pParent = pLastParent;
+
+ pParent->mpWindowImpl->mbActive = TRUE;
+ pParent->Activate();
+ pActivateParent = pLastParent;
+ }
+ while ( pActivateParent != this );
+*/
+ // call Get- and LoseFocus
+ if ( pOldFocusWindow && ! aOldFocusDel.IsDelete() )
+ {
+ if ( pOldFocusWindow->IsTracking() &&
+ (pSVData->maWinData.mnTrackFlags & STARTTRACK_FOCUSCANCEL) )
+ pOldFocusWindow->EndTracking( ENDTRACK_CANCEL | ENDTRACK_FOCUS );
+ NotifyEvent aNEvt( EVENT_LOSEFOCUS, pOldFocusWindow );
+ if ( !ImplCallPreNotify( aNEvt ) )
+ pOldFocusWindow->LoseFocus();
+ pOldFocusWindow->ImplCallDeactivateListeners( this );
+ }
+
+ if ( pSVData->maWinData.mpFocusWin == this )
+ {
+ if ( mpWindowImpl->mpSysObj )
+ {
+ mpWindowImpl->mpFrameData->mpFocusWin = this;
+ if ( !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl )
+ mpWindowImpl->mpSysObj->GrabFocus();
+ }
+
+ if ( pSVData->maWinData.mpFocusWin == this )
+ {
+ if ( mpWindowImpl->mpCursor )
+ mpWindowImpl->mpCursor->ImplShow();
+ mpWindowImpl->mbInFocusHdl = TRUE;
+ mpWindowImpl->mnGetFocusFlags = nFlags;
+ // if we're changing focus due to closing a popup floating window
+ // notify the new focus window so it can restore the inner focus
+ // eg, toolboxes can select their recent active item
+ if( pOldFocusWindow &&
+ ! aOldFocusDel.IsDelete() &&
+ ( pOldFocusWindow->GetDialogControlFlags() & WINDOW_DLGCTRL_FLOATWIN_POPUPMODEEND_CANCEL ) )
+ mpWindowImpl->mnGetFocusFlags |= GETFOCUS_FLOATWIN_POPUPMODEEND_CANCEL;
+ NotifyEvent aNEvt( EVENT_GETFOCUS, this );
+ if ( !ImplCallPreNotify( aNEvt ) && !aDogTag.IsDelete() )
+ GetFocus();
+ if( !aDogTag.IsDelete() )
+ ImplCallActivateListeners( (pOldFocusWindow && ! aOldFocusDel.IsDelete()) ? pOldFocusWindow : NULL );
+ if( !aDogTag.IsDelete() )
+ {
+ mpWindowImpl->mnGetFocusFlags = 0;
+ mpWindowImpl->mbInFocusHdl = FALSE;
+ }
+ }
+ }
+
+ GetpApp()->FocusChanged();
+ ImplNewInputContext();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplNewInputContext()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pFocusWin = pSVData->maWinData.mpFocusWin;
+ if ( !pFocusWin )
+ return;
+
+ // Is InputContext changed?
+ const InputContext& rInputContext = pFocusWin->GetInputContext();
+ if ( rInputContext == pFocusWin->mpWindowImpl->mpFrameData->maOldInputContext )
+ return;
+
+ pFocusWin->mpWindowImpl->mpFrameData->maOldInputContext = rInputContext;
+
+ SalInputContext aNewContext;
+ const Font& rFont = rInputContext.GetFont();
+ const XubString& rFontName = rFont.GetName();
+ ImplFontEntry* pFontEntry = NULL;
+ aNewContext.mpFont = NULL;
+ if ( rFontName.Len() )
+ {
+ Size aSize = pFocusWin->ImplLogicToDevicePixel( rFont.GetSize() );
+ if ( !aSize.Height() )
+ {
+ // Nur dann Defaultgroesse setzen, wenn Fonthoehe auch in logischen
+ // Koordinaaten 0 ist
+ if ( rFont.GetSize().Height() )
+ aSize.Height() = 1;
+ else
+ aSize.Height() = (12*pFocusWin->mnDPIY)/72;
+ }
+ // TODO: No display device uses ImplDirectFontSubstitution thingy, right? => remove it
+ ImplDirectFontSubstitution* pFontSubst = NULL;
+ //if( pFocusWin->mpOutDevData )
+ // pFontSubst = &pFocusWin->mpOutDevData->maDevFontSubst;
+ pFontEntry = pFocusWin->mpFontCache->GetFontEntry( pFocusWin->mpFontList,
+ rFont, aSize, static_cast<float>(aSize.Height()), pFontSubst );
+ if ( pFontEntry )
+ aNewContext.mpFont = &pFontEntry->maFontSelData;
+ }
+ aNewContext.meLanguage = rFont.GetLanguage();
+ aNewContext.mnOptions = rInputContext.GetOptions();
+ pFocusWin->ImplGetFrame()->SetInputContext( &aNewContext );
+
+ if ( pFontEntry )
+ pFocusWin->mpFontCache->Release( pFontEntry );
+}
+
+// -----------------------------------------------------------------------
+
+Window::Window( WindowType nType )
+{
+ DBG_CTOR( Window, ImplDbgCheckWindow );
+
+ ImplInitWindowData( nType );
+}
+
+// -----------------------------------------------------------------------
+
+Window::Window( Window* pParent, WinBits nStyle )
+{
+ DBG_CTOR( Window, ImplDbgCheckWindow );
+
+ ImplInitWindowData( WINDOW_WINDOW );
+ ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Window::Window( Window* pParent, const ResId& rResId )
+{
+ DBG_CTOR( Window, ImplDbgCheckWindow );
+
+ ImplInitWindowData( WINDOW_WINDOW );
+ rResId.SetRT( RSC_WINDOW );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle, NULL );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+#if OSL_DEBUG_LEVEL > 0
+namespace
+{
+ void lcl_appendWindowInfo( ByteString& io_rErrorString, const Window& i_rWindow )
+ {
+ // skip border windows, they don't carry information which helps diagnosing the problem
+ const Window* pWindow( &i_rWindow );
+ while ( pWindow && ( pWindow->GetType() == WINDOW_BORDERWINDOW ) )
+ pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD );
+ if ( !pWindow )
+ pWindow = &i_rWindow;
+
+ io_rErrorString += char(13);
+ io_rErrorString += typeid( *pWindow ).name();
+ io_rErrorString += " (window text: '";
+ io_rErrorString += ByteString( pWindow->GetText(), RTL_TEXTENCODING_UTF8 );
+ io_rErrorString += "')";
+ }
+}
+#endif
+// -----------------------------------------------------------------------
+
+Window::~Window()
+{
+ vcl::LazyDeletor<Window>::Undelete( this );
+
+ DBG_DTOR( Window, ImplDbgCheckWindow );
+ DBG_ASSERT( !mpWindowImpl->mbInDtor, "~Window - already in DTOR!" );
+
+
+ // remove Key and Mouse events issued by Application::PostKey/MouseEvent
+ Application::RemoveMouseAndKeyEvents( this );
+
+ // Dispose of the canvas implementation (which, currently, has an
+ // own wrapper window as a child to this one.
+ Reference< rendering::XCanvas > xCanvas( mpWindowImpl->mxCanvas );
+ if( xCanvas.is() )
+ {
+ uno::Reference < lang::XComponent > xCanvasComponent( xCanvas,
+ uno::UNO_QUERY );
+ if( xCanvasComponent.is() )
+ xCanvasComponent->dispose();
+ }
+
+ mpWindowImpl->mbInDtor = TRUE;
+
+ ImplCallEventListeners( VCLEVENT_OBJECT_DYING );
+
+ // do not send child events for frames that were registered as native frames
+ if( !ImplIsAccessibleNativeFrame() && mpWindowImpl->mbReallyVisible )
+ if ( ImplIsAccessibleCandidate() && GetAccessibleParentWindow() )
+ GetAccessibleParentWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_CHILDDESTROYED, this );
+
+ // remove associated data structures from dockingmanager
+ ImplGetDockingManager()->RemoveWindow( this );
+
+
+ // remove ownerdraw decorated windows from list in the top-most frame window
+ if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
+ {
+ ::std::vector< Window* >& rList = ImplGetOwnerDrawList();
+ ::std::vector< Window* >::iterator p;
+ p = ::std::find( rList.begin(), rList.end(), this );
+ if( p != rList.end() )
+ rList.erase( p );
+ }
+
+ // shutdown drag and drop
+ ::com::sun::star::uno::Reference < ::com::sun::star::lang::XComponent > xDnDComponent( mpWindowImpl->mxDNDListenerContainer, ::com::sun::star::uno::UNO_QUERY );
+
+ if( xDnDComponent.is() )
+ xDnDComponent->dispose();
+
+ if( mpWindowImpl->mbFrame && mpWindowImpl->mpFrameData )
+ {
+ try
+ {
+ // deregister drop target listener
+ if( mpWindowImpl->mpFrameData->mxDropTargetListener.is() )
+ {
+ Reference< XDragGestureRecognizer > xDragGestureRecognizer =
+ Reference< XDragGestureRecognizer > (mpWindowImpl->mpFrameData->mxDragSource, UNO_QUERY);
+ if( xDragGestureRecognizer.is() )
+ {
+ xDragGestureRecognizer->removeDragGestureListener(
+ Reference< XDragGestureListener > (mpWindowImpl->mpFrameData->mxDropTargetListener, UNO_QUERY));
+ }
+
+ mpWindowImpl->mpFrameData->mxDropTarget->removeDropTargetListener( mpWindowImpl->mpFrameData->mxDropTargetListener );
+ mpWindowImpl->mpFrameData->mxDropTargetListener.clear();
+ }
+
+ // shutdown drag and drop for this frame window
+ Reference< XComponent > xComponent( mpWindowImpl->mpFrameData->mxDropTarget, UNO_QUERY );
+
+ // DNDEventDispatcher does not hold a reference of the DropTarget,
+ // so it's ok if it does not support XComponent
+ if( xComponent.is() )
+ xComponent->dispose();
+ }
+
+ catch ( Exception exc )
+ {
+ // can be safely ignored here.
+ }
+ }
+
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper( FALSE );
+ if ( pWrapper )
+ pWrapper->WindowDestroyed( this );
+
+ // MT: Must be called after WindowDestroyed!
+ // Otherwise, if the accessible is a VCLXWindow, it will try to destroy this window again!
+ // But accessibility implementations from applications need this dispose.
+ if ( mpWindowImpl->mxAccessible.is() )
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xC( mpWindowImpl->mxAccessible, ::com::sun::star::uno::UNO_QUERY );
+ if ( xC.is() )
+ xC->dispose();
+ }
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maHelpData.mpHelpWin && (pSVData->maHelpData.mpHelpWin->GetParent() == this) )
+ ImplDestroyHelpWindow( true );
+
+ DBG_ASSERT( pSVData->maWinData.mpTrackWin != this,
+ "Window::~Window(): Window is in TrackingMode" );
+ DBG_ASSERT( pSVData->maWinData.mpCaptureWin != this,
+ "Window::~Window(): Window has the mouse captured" );
+ // #103442# DefModalDialogParent is now determined on-the-fly, so this pointer is unimportant now
+ //DBG_ASSERT( pSVData->maWinData.mpDefDialogParent != this,
+ // "Window::~Window(): Window is DefModalDialogParent" );
+
+ // Wegen alter kompatibilitaet
+ if ( pSVData->maWinData.mpTrackWin == this )
+ EndTracking();
+ if ( pSVData->maWinData.mpCaptureWin == this )
+ ReleaseMouse();
+ if ( pSVData->maWinData.mpDefDialogParent == this )
+ pSVData->maWinData.mpDefDialogParent = NULL;
+
+#ifdef DBG_UTIL
+ if ( TRUE ) // always perform these tests in non-pro versions
+ {
+ ByteString aErrorStr;
+ BOOL bError = FALSE;
+ Window* pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pTempWin )
+ {
+ if ( ImplIsRealParentPath( pTempWin ) )
+ {
+ bError = TRUE;
+ lcl_appendWindowInfo( aErrorStr, *pTempWin );
+ }
+ pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
+ }
+ if ( bError )
+ {
+ ByteString aTempStr( "Window (" );
+ aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 );
+ aTempStr += ") with living SystemWindow(s) destroyed: ";
+ aTempStr += aErrorStr;
+ DBG_ERROR( aTempStr.GetBuffer() );
+ GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed!
+ }
+
+ bError = FALSE;
+ pTempWin = pSVData->maWinData.mpFirstFrame;
+ while ( pTempWin )
+ {
+ if ( ImplIsRealParentPath( pTempWin ) )
+ {
+ bError = TRUE;
+ lcl_appendWindowInfo( aErrorStr, *pTempWin );
+ }
+ pTempWin = pTempWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ if ( bError )
+ {
+ ByteString aTempStr( "Window (" );
+ aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 );
+ aTempStr += ") with living SystemWindow(s) destroyed: ";
+ aTempStr += aErrorStr;
+ DBG_ERROR( aTempStr.GetBuffer() );
+ GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed!
+ }
+
+ if ( mpWindowImpl->mpFirstChild )
+ {
+ ByteString aTempStr( "Window (" );
+ aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 );
+ aTempStr += ") with living Child(s) destroyed: ";
+ pTempWin = mpWindowImpl->mpFirstChild;
+ while ( pTempWin )
+ {
+ lcl_appendWindowInfo( aTempStr, *pTempWin );
+ pTempWin = pTempWin->mpWindowImpl->mpNext;
+ }
+ DBG_ERROR( aTempStr.GetBuffer() );
+ GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed!
+ }
+
+ if ( mpWindowImpl->mpFirstOverlap )
+ {
+ ByteString aTempStr( "Window (" );
+ aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 );
+ aTempStr += ") with living SystemWindow(s) destroyed: ";
+ pTempWin = mpWindowImpl->mpFirstOverlap;
+ while ( pTempWin )
+ {
+ lcl_appendWindowInfo( aTempStr, *pTempWin );
+ pTempWin = pTempWin->mpWindowImpl->mpNext;
+ }
+ DBG_ERROR( aTempStr.GetBuffer() );
+ GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed!
+ }
+
+ Window* pMyParent = this;
+ SystemWindow* pMySysWin = NULL;
+
+ while ( pMyParent )
+ {
+ if ( pMyParent->IsSystemWindow() )
+ pMySysWin = (SystemWindow*)pMyParent;
+ pMyParent = pMyParent->GetParent();
+ }
+ if ( pMySysWin && pMySysWin->ImplIsInTaskPaneList( this ) )
+ {
+ ByteString aTempStr( "Window (" );
+ aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 );
+ aTempStr += ") still in TaskPanelList!";
+ DBG_ERROR( aTempStr.GetBuffer() );
+ GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed!
+ }
+ }
+#endif
+
+ if( mpWindowImpl->mbIsInTaskPaneList )
+ {
+ Window* pMyParent = this;
+ SystemWindow* pMySysWin = NULL;
+
+ while ( pMyParent )
+ {
+ if ( pMyParent->IsSystemWindow() )
+ pMySysWin = (SystemWindow*)pMyParent;
+ pMyParent = pMyParent->GetParent();
+ }
+ if ( pMySysWin && pMySysWin->ImplIsInTaskPaneList( this ) )
+ {
+ pMySysWin->GetTaskPaneList()->RemoveWindow( this );
+ }
+ else
+ {
+ ByteString aTempStr( "Window (" );
+ aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 );
+ aTempStr += ") not found in TaskPanelList!";
+ DBG_ERROR( aTempStr.GetBuffer() );
+ }
+ }
+
+ // Fenster hiden, um das entsprechende Paint-Handling auszuloesen
+ Hide();
+
+ // Mitteilen, das Fenster zerstoert wird
+ {
+ NotifyEvent aNEvt( EVENT_DESTROY, this );
+ Notify( aNEvt );
+ }
+
+ // EndExtTextInputMode
+ if ( pSVData->maWinData.mpExtTextInputWin == this )
+ {
+ EndExtTextInput( EXTTEXTINPUT_END_COMPLETE );
+ if ( pSVData->maWinData.mpExtTextInputWin == this )
+ pSVData->maWinData.mpExtTextInputWin = NULL;
+ }
+
+ // check if the focus window is our child
+ BOOL bHasFocussedChild = FALSE;
+ if( pSVData->maWinData.mpFocusWin && ImplIsRealParentPath( pSVData->maWinData.mpFocusWin ) )
+ {
+ // #122232#, this must not happen and is an application bug ! but we try some cleanup to hopefully avoid crashes, see below
+ bHasFocussedChild = TRUE;
+#ifdef DBG_UTIL
+ ByteString aTempStr( "Window (" );
+ aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 );
+ aTempStr += ") with focussed child window destroyed ! THIS WILL LEAD TO CRASHES AND MUST BE FIXED !";
+ DBG_ERROR( aTempStr.GetBuffer() );
+ GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed!
+#endif
+ }
+
+ // Wenn wir den Focus haben, dann den Focus auf ein anderes Fenster setzen
+ Window* pOverlapWindow = ImplGetFirstOverlapWindow();
+ if ( pSVData->maWinData.mpFocusWin == this
+ || bHasFocussedChild ) // #122232#, see above, try some cleanup
+ {
+ if ( mpWindowImpl->mbFrame )
+ {
+ pSVData->maWinData.mpFocusWin = NULL;
+ pOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL;
+ GetpApp()->FocusChanged();
+ }
+ else
+ {
+ Window* pParent = GetParent();
+ Window* pBorderWindow = mpWindowImpl->mpBorderWindow;
+ // Bei ueberlappenden Fenstern wird der Focus auf den
+ // Parent vom naechsten FrameWindow gesetzt
+ if ( pBorderWindow )
+ {
+ if ( pBorderWindow->ImplIsOverlapWindow() )
+ pParent = pBorderWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ else if ( ImplIsOverlapWindow() )
+ pParent = mpWindowImpl->mpOverlapWindow;
+
+ if ( pParent && pParent->IsEnabled() && pParent->IsInputEnabled() && ! pParent->IsInModalMode() )
+ pParent->GrabFocus();
+ else
+ mpWindowImpl->mpFrameWindow->GrabFocus();
+
+ // If the focus was set back to 'this' set it to nothing
+ if ( pSVData->maWinData.mpFocusWin == this )
+ {
+ pSVData->maWinData.mpFocusWin = NULL;
+ pOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL;
+ GetpApp()->FocusChanged();
+ }
+ }
+ }
+
+
+ if ( pOverlapWindow->mpWindowImpl->mpLastFocusWindow == this )
+ pOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL;
+
+ // reset hint for DefModalDialogParent
+ if( pSVData->maWinData.mpActiveApplicationFrame == this )
+ pSVData->maWinData.mpActiveApplicationFrame = NULL;
+
+ // gemerkte Fenster zuruecksetzen
+ if ( mpWindowImpl->mpFrameData->mpFocusWin == this )
+ mpWindowImpl->mpFrameData->mpFocusWin = NULL;
+ if ( mpWindowImpl->mpFrameData->mpMouseMoveWin == this )
+ mpWindowImpl->mpFrameData->mpMouseMoveWin = NULL;
+ if ( mpWindowImpl->mpFrameData->mpMouseDownWin == this )
+ mpWindowImpl->mpFrameData->mpMouseDownWin = NULL;
+
+ // Deactivate-Window zuruecksetzen
+ if ( pSVData->maWinData.mpLastDeacWin == this )
+ pSVData->maWinData.mpLastDeacWin = NULL;
+
+ if ( mpWindowImpl->mbFrame )
+ {
+ if ( mpWindowImpl->mpFrameData->mnFocusId )
+ Application::RemoveUserEvent( mpWindowImpl->mpFrameData->mnFocusId );
+ if ( mpWindowImpl->mpFrameData->mnMouseMoveId )
+ Application::RemoveUserEvent( mpWindowImpl->mpFrameData->mnMouseMoveId );
+ }
+
+ // Graphic freigeben
+ ImplReleaseGraphics();
+
+ // Evt. anderen Funktion mitteilen, das das Fenster geloescht
+ // wurde
+ ImplDelData* pDelData = mpWindowImpl->mpFirstDel;
+ while ( pDelData )
+ {
+ pDelData->mbDel = TRUE;
+ pDelData->mpWindow = NULL; // #112873# pDel is not associated with a Window anymore
+ pDelData = pDelData->mpNext;
+ }
+
+ // Fenster aus den Listen austragen
+ ImplRemoveWindow( TRUE );
+
+ // de-register as "top window child" at our parent, if necessary
+ if ( mpWindowImpl->mbFrame )
+ {
+ BOOL bIsTopWindow = mpWindowImpl->mpWinData && ( mpWindowImpl->mpWinData->mnIsTopWindow == 1 );
+ if ( mpWindowImpl->mpRealParent && bIsTopWindow )
+ {
+ ImplWinData* pParentWinData = mpWindowImpl->mpRealParent->ImplGetWinData();
+
+ ::std::list< Window* >::iterator myPos = ::std::find( pParentWinData->maTopWindowChildren.begin(),
+ pParentWinData->maTopWindowChildren.end(), this );
+ DBG_ASSERT( myPos != pParentWinData->maTopWindowChildren.end(), "Window::~Window: inconsistency in top window chain!" );
+ if ( myPos != pParentWinData->maTopWindowChildren.end() )
+ pParentWinData->maTopWindowChildren.erase( myPos );
+ }
+ }
+
+ // Extra Window Daten loeschen
+ if ( mpWindowImpl->mpWinData )
+ {
+ if ( mpWindowImpl->mpWinData->mpExtOldText )
+ delete mpWindowImpl->mpWinData->mpExtOldText;
+ if ( mpWindowImpl->mpWinData->mpExtOldAttrAry )
+ delete mpWindowImpl->mpWinData->mpExtOldAttrAry;
+ if ( mpWindowImpl->mpWinData->mpCursorRect )
+ delete mpWindowImpl->mpWinData->mpCursorRect;
+ if ( mpWindowImpl->mpWinData->mpFocusRect )
+ delete mpWindowImpl->mpWinData->mpFocusRect;
+ if ( mpWindowImpl->mpWinData->mpTrackRect )
+ delete mpWindowImpl->mpWinData->mpTrackRect;
+ if ( mpWindowImpl->mpWinData->mpSmartHelpId )
+ delete mpWindowImpl->mpWinData->mpSmartHelpId;
+ if ( mpWindowImpl->mpWinData->mpSmartUniqueId )
+ delete mpWindowImpl->mpWinData->mpSmartUniqueId;
+
+ delete mpWindowImpl->mpWinData;
+ }
+
+
+ // Overlap-Window-Daten loeschen
+ if ( mpWindowImpl->mpOverlapData )
+ {
+ delete mpWindowImpl->mpOverlapData;
+ }
+
+ // Evt. noch BorderWindow oder Frame zerstoeren
+ if ( mpWindowImpl->mpBorderWindow )
+ delete mpWindowImpl->mpBorderWindow;
+ else if ( mpWindowImpl->mbFrame )
+ {
+ if ( pSVData->maWinData.mpFirstFrame == this )
+ pSVData->maWinData.mpFirstFrame = mpWindowImpl->mpFrameData->mpNextFrame;
+ else
+ {
+ Window* pSysWin = pSVData->maWinData.mpFirstFrame;
+ while ( pSysWin->mpWindowImpl->mpFrameData->mpNextFrame != this )
+ pSysWin = pSysWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ pSysWin->mpWindowImpl->mpFrameData->mpNextFrame = mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ mpWindowImpl->mpFrame->SetCallback( NULL, NULL );
+ pSVData->mpDefInst->DestroyFrame( mpWindowImpl->mpFrame );
+ delete mpWindowImpl->mpFrameData;
+ }
+
+ if ( mpWindowImpl->mpChildClipRegion )
+ delete mpWindowImpl->mpChildClipRegion;
+
+ delete mpWindowImpl->mpAccessibleInfos;
+ delete mpWindowImpl->mpControlFont;
+
+ // should be the last statements
+ delete mpWindowImpl; mpWindowImpl = NULL;
+}
+
+// -----------------------------------------------------------------------
+void Window::doLazyDelete()
+{
+ SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(this);
+ DockingWindow* pDockWin = dynamic_cast<DockingWindow*>(this);
+ if( pSysWin || ( pDockWin && pDockWin->IsFloatingMode() ) )
+ {
+ Show( FALSE );
+ SetParent( ImplGetDefaultWindow() );
+ }
+ vcl::LazyDeletor<Window>::Delete( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::MouseMove( const MouseEvent& rMEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ NotifyEvent aNEvt( EVENT_MOUSEMOVE, this, &rMEvt );
+ if ( !Notify( aNEvt ) )
+ mpWindowImpl->mbMouseMove = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ NotifyEvent aNEvt( EVENT_MOUSEBUTTONDOWN, this, &rMEvt );
+ if ( !Notify( aNEvt ) )
+ mpWindowImpl->mbMouseButtonDown = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ NotifyEvent aNEvt( EVENT_MOUSEBUTTONUP, this, &rMEvt );
+ if ( !Notify( aNEvt ) )
+ mpWindowImpl->mbMouseButtonUp = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::KeyInput( const KeyEvent& rKEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ NotifyEvent aNEvt( EVENT_KEYINPUT, this, &rKEvt );
+ if ( !Notify( aNEvt ) )
+ mpWindowImpl->mbKeyInput = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::KeyUp( const KeyEvent& rKEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ NotifyEvent aNEvt( EVENT_KEYUP, this, &rKEvt );
+ if ( !Notify( aNEvt ) )
+ mpWindowImpl->mbKeyUp = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::PrePaint()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Paint( const Rectangle& rRect )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ ImplCallEventListeners( VCLEVENT_WINDOW_PAINT, (void*)&rRect );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Draw( OutputDevice*, const Point&, const Size&, ULONG )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Move()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Resize()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Activate()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Deactivate()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::GetFocus()
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ if ( HasFocus() && mpWindowImpl->mpLastFocusWindow && !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) )
+ {
+ ImplDelData aDogtag( this );
+ mpWindowImpl->mpLastFocusWindow->GrabFocus();
+ if( aDogtag.IsDelete() )
+ return;
+ }
+
+ NotifyEvent aNEvt( EVENT_GETFOCUS, this );
+ Notify( aNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::LoseFocus()
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ NotifyEvent aNEvt( EVENT_LOSEFOCUS, this );
+ Notify( aNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::RequestHelp( const HelpEvent& rHEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ // Wenn Balloon-Help angefordert wird, dann den Balloon mit dem
+ // gesetzten Hilfetext anzeigen
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ {
+ const XubString* pStr = &(GetHelpText());
+ if ( !pStr->Len() )
+ pStr = &(GetQuickHelpText());
+ if ( !pStr->Len() && ImplGetParent() && !ImplIsOverlapWindow() )
+ ImplGetParent()->RequestHelp( rHEvt );
+ else
+ Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), *pStr );
+ }
+ else if ( rHEvt.GetMode() & HELPMODE_QUICK )
+ {
+ const XubString* pStr = &(GetQuickHelpText());
+ if ( !pStr->Len() && ImplGetParent() && !ImplIsOverlapWindow() )
+ ImplGetParent()->RequestHelp( rHEvt );
+ else
+ {
+ Point aPos = GetPosPixel();
+ if ( ImplGetParent() && !ImplIsOverlapWindow() )
+ aPos = ImplGetParent()->OutputToScreenPixel( aPos );
+ Rectangle aRect( aPos, GetSizePixel() );
+ String aHelpText;
+ if ( pStr->Len() )
+ aHelpText = GetHelpText();
+ Help::ShowQuickHelp( this, aRect, *pStr, aHelpText, QUICKHELP_CTRLTEXT );
+ }
+ }
+ else
+ {
+ SmartId aSmartId = GetSmartHelpId();
+
+ ULONG nNumHelpId = 0;
+ String aStrHelpId;
+ if( aSmartId.HasString() )
+ aStrHelpId = aSmartId.GetStr();
+ if( aSmartId.HasNumeric() )
+ nNumHelpId = aSmartId.GetNum();
+
+ if ( !nNumHelpId && aStrHelpId.Len() == 0 && ImplGetParent() )
+ ImplGetParent()->RequestHelp( rHEvt );
+ else
+ {
+ if ( !nNumHelpId && aStrHelpId.Len() == 0 )
+ nNumHelpId = OOO_HELP_INDEX;
+
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if( aStrHelpId.Len() > 0 )
+ pHelp->Start( aStrHelpId, this );
+ else
+ pHelp->Start( nNumHelpId, this );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Command( const CommandEvent& rCEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ ImplCallEventListeners( VCLEVENT_WINDOW_COMMAND, (void*)&rCEvt );
+
+ NotifyEvent aNEvt( EVENT_COMMAND, this, &rCEvt );
+ if ( !Notify( aNEvt ) )
+ mpWindowImpl->mbCommand = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Tracking( const TrackingEvent& rTEvt )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper )
+ pWrapper->Tracking( rTEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::UserEvent( ULONG, void* )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::StateChanged( StateChangedType )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::DataChanged( const DataChangedEvent& )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplNotifyKeyMouseCommandEventListeners( NotifyEvent& rNEvt )
+{
+ if( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ const CommandEvent* pCEvt = rNEvt.GetCommandEvent();
+ if ( pCEvt->GetCommand() != COMMAND_CONTEXTMENU )
+ // non context menu events are not to be notified up the chain
+ // so we return immediately
+ return;
+
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ {
+ if ( rNEvt.GetWindow() == this )
+ // not interested in: The event listeners are already called in ::Command,
+ // and calling them here a second time doesn't make sense
+ ;
+ else
+ {
+ CommandEvent aCommandEvent = ImplTranslateCommandEvent( *pCEvt, rNEvt.GetWindow(), this );
+ ImplCallEventListeners( VCLEVENT_WINDOW_COMMAND, &aCommandEvent );
+ }
+ }
+ }
+
+ // #82968# notify event listeners for mouse and key events seperately and
+ // not in PreNotify ( as for focus listeners )
+ // this allows for procesing those events internally first and pass it to
+ // the toolkit later
+
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+ if( rNEvt.GetType() == EVENT_MOUSEMOVE )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ {
+ if ( rNEvt.GetWindow() == this )
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, (void*)rNEvt.GetMouseEvent() );
+ else
+ {
+ MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, &aMouseEvent );
+ }
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_MOUSEBUTTONUP )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ {
+ if ( rNEvt.GetWindow() == this )
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, (void*)rNEvt.GetMouseEvent() );
+ else
+ {
+ MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, &aMouseEvent );
+ }
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ {
+ if ( rNEvt.GetWindow() == this )
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, (void*)rNEvt.GetMouseEvent() );
+ else
+ {
+ MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, &aMouseEvent );
+ }
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ ImplCallEventListeners( VCLEVENT_WINDOW_KEYINPUT, (void*)rNEvt.GetKeyEvent() );
+ }
+ else if( rNEvt.GetType() == EVENT_KEYUP )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ ImplCallEventListeners( VCLEVENT_WINDOW_KEYUP, (void*)rNEvt.GetKeyEvent() );
+ }
+
+ if ( aDelData.IsDelete() )
+ return;
+ ImplRemoveDel( &aDelData );
+
+ // #106721# check if we're part of a compound control and notify
+ Window *pParent = ImplGetParent();
+ while( pParent )
+ {
+ if( pParent->IsCompoundControl() )
+ {
+ pParent->ImplNotifyKeyMouseCommandEventListeners( rNEvt );
+ break;
+ }
+ pParent = pParent->ImplGetParent();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long Window::PreNotify( NotifyEvent& rNEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ long bDone = FALSE;
+ if ( mpWindowImpl->mpParent && !ImplIsOverlapWindow() )
+ bDone = mpWindowImpl->mpParent->PreNotify( rNEvt );
+
+ if ( !bDone )
+ {
+ if( rNEvt.GetType() == EVENT_GETFOCUS )
+ {
+ BOOL bCompoundFocusChanged = FALSE;
+ if ( mpWindowImpl->mbCompoundControl && !mpWindowImpl->mbCompoundControlHasFocus && HasChildPathFocus() )
+ {
+ mpWindowImpl->mbCompoundControlHasFocus = TRUE;
+ bCompoundFocusChanged = TRUE;
+ }
+
+ if ( bCompoundFocusChanged || ( rNEvt.GetWindow() == this ) )
+ ImplCallEventListeners( VCLEVENT_WINDOW_GETFOCUS );
+ }
+ else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ BOOL bCompoundFocusChanged = FALSE;
+ if ( mpWindowImpl->mbCompoundControl && mpWindowImpl->mbCompoundControlHasFocus && !HasChildPathFocus() )
+ {
+ mpWindowImpl->mbCompoundControlHasFocus = FALSE ;
+ bCompoundFocusChanged = TRUE;
+ }
+
+ if ( bCompoundFocusChanged || ( rNEvt.GetWindow() == this ) )
+ ImplCallEventListeners( VCLEVENT_WINDOW_LOSEFOCUS );
+ }
+
+ // #82968# mouse and key events will be notified after processing ( in ImplNotifyKeyMouseCommandEventListeners() )!
+ // see also ImplHandleMouseEvent(), ImplHandleKey()
+
+ /*
+ else if( rNEvt.GetType() == EVENT_MOUSEMOVE )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ {
+ if ( rNEvt.GetWindow() == this )
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, (void*)rNEvt.GetMouseEvent() );
+ else
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, &ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ) );
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_MOUSEBUTTONUP )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ {
+ if ( rNEvt.GetWindow() == this )
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, (void*)rNEvt.GetMouseEvent() );
+ else
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, &ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ) );
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ {
+ if ( rNEvt.GetWindow() == this )
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, (void*)rNEvt.GetMouseEvent() );
+ else
+ ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, &ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ) );
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ ImplCallEventListeners( VCLEVENT_WINDOW_KEYINPUT, (void*)rNEvt.GetKeyEvent() );
+ }
+ else if( rNEvt.GetType() == EVENT_KEYUP )
+ {
+ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
+ ImplCallEventListeners( VCLEVENT_WINDOW_KEYUP, (void*)rNEvt.GetKeyEvent() );
+ }
+ */
+ }
+
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+long Window::Notify( NotifyEvent& rNEvt )
+{
+ { // Klammerung, da in diesem Handler das Window zerstoert werden darf
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ }
+
+ long nRet = FALSE;
+
+ // check for docking window
+ // but do nothing if window is docked and locked
+ ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
+ if( pWrapper && !( !pWrapper->IsFloatingMode() && pWrapper->IsLocked() ) )
+ {
+ if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN )
+ {
+ const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
+ BOOL bHit = pWrapper->GetDragArea().IsInside( pMEvt->GetPosPixel() );
+ if ( pMEvt->IsLeft() )
+ {
+ if ( pMEvt->IsMod1() && (pMEvt->GetClicks() == 2) )
+ {
+ // ctrl double click toggles floating mode
+ pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() );
+ return TRUE;
+ }
+ else if ( pMEvt->GetClicks() == 1 && bHit)
+ {
+ // allow start docking during mouse move
+ pWrapper->ImplEnableStartDocking();
+ return TRUE;
+ }
+ }
+ }
+ else if ( rNEvt.GetType() == EVENT_MOUSEMOVE )
+ {
+ const MouseEvent* pMEvt = rNEvt.GetMouseEvent();
+ BOOL bHit = pWrapper->GetDragArea().IsInside( pMEvt->GetPosPixel() );
+ if ( pMEvt->IsLeft() )
+ {
+ // check if a single click initiated this sequence ( ImplStartDockingEnabled() )
+ // check if window is docked and
+ if( pWrapper->ImplStartDockingEnabled() && !pWrapper->IsFloatingMode() &&
+ !pWrapper->IsDocking() && bHit )
+ {
+ Point aPos = pMEvt->GetPosPixel();
+ Window* pWindow = rNEvt.GetWindow();
+ if ( pWindow != this )
+ {
+ aPos = pWindow->OutputToScreenPixel( aPos );
+ aPos = ScreenToOutputPixel( aPos );
+ }
+ pWrapper->ImplStartDocking( aPos );
+ }
+ return TRUE;
+ }
+ }
+ else if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ const KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode();
+ if( rKey.GetCode() == KEY_F10 && rKey.GetModifier() &&
+ rKey.IsShift() && rKey.IsMod1() )
+ {
+ pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() );
+ /* At this point the floating toolbar frame does not have the
+ * input focus since these frames don't get the focus per default
+ * To enable keyboard handling of this toolbar set the input focus
+ * to the frame. This needs to be done with ToTop since GrabFocus
+ * would not notice any change since "this" already has the focus.
+ */
+ if( pWrapper->IsFloatingMode() )
+ ToTop( TOTOP_GRABFOCUSONLY );
+ return TRUE;
+ }
+ }
+ }
+
+ // Dialog-Steuerung
+ if ( (GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL )
+ {
+ // Wenn Parent auch DialogSteuerung aktiviert hat, uebernimmt dieser die Steuerung
+ if ( (rNEvt.GetType() == EVENT_KEYINPUT) || (rNEvt.GetType() == EVENT_KEYUP) )
+ {
+ if ( ImplIsOverlapWindow() ||
+ ((ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) )
+ {
+ nRet = ImplDlgCtrl( *rNEvt.GetKeyEvent(), rNEvt.GetType() == EVENT_KEYINPUT );
+ }
+ }
+ else if ( (rNEvt.GetType() == EVENT_GETFOCUS) || (rNEvt.GetType() == EVENT_LOSEFOCUS) )
+ {
+ ImplDlgCtrlFocusChanged( rNEvt.GetWindow(), rNEvt.GetType() == EVENT_GETFOCUS );
+ if ( (rNEvt.GetWindow() == this) && (rNEvt.GetType() == EVENT_GETFOCUS) &&
+ !(GetStyle() & WB_TABSTOP) && !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) )
+ {
+ USHORT n = 0;
+ Window* pFirstChild = ImplGetDlgWindow( n, DLGWINDOW_FIRST );
+ if ( pFirstChild )
+ pFirstChild->ImplControlFocus();
+ }
+ }
+ }
+
+ if ( !nRet )
+ {
+ if ( mpWindowImpl->mpParent && !ImplIsOverlapWindow() )
+ nRet = mpWindowImpl->mpParent->Notify( rNEvt );
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallEventListeners( ULONG nEvent, void* pData )
+{
+ // The implementation was moved to CallEventListeners(),
+ // because derived classes in svtools must be able to
+ // call the event listeners and ImplCallEventListeners()
+ // is not exported.
+ // TODO: replace ImplCallEventListeners() by CallEventListeners() in vcl
+
+ CallEventListeners( nEvent, pData );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::CallEventListeners( ULONG nEvent, void* pData )
+{
+ VclWindowEvent aEvent( this, nEvent, pData );
+
+ ImplDelData aDelData;
+ ImplAddDel( &aDelData );
+
+ ImplGetSVData()->mpApp->ImplCallEventListeners( &aEvent );
+
+ if ( aDelData.IsDelete() )
+ return;
+
+ if ( !mpWindowImpl->maEventListeners.empty() )
+ mpWindowImpl->maEventListeners.Call( &aEvent );
+
+ if ( aDelData.IsDelete() )
+ return;
+
+ ImplRemoveDel( &aDelData );
+
+ Window* pWindow = this;
+ while ( pWindow )
+ {
+ pWindow->ImplAddDel( &aDelData );
+
+ if ( !pWindow->mpWindowImpl->maChildEventListeners.empty() )
+ pWindow->mpWindowImpl->maChildEventListeners.Call( &aEvent );
+
+ if ( aDelData.IsDelete() )
+ return;
+
+ pWindow->ImplRemoveDel( &aDelData );
+
+ pWindow = pWindow->GetParent();
+ }
+}
+
+void Window::FireVclEvent( VclSimpleEvent* pEvent )
+{
+ ImplGetSVData()->mpApp->ImplCallEventListeners(pEvent);
+}
+
+// -----------------------------------------------------------------------
+
+void Window::AddEventListener( const Link& rEventListener )
+{
+ mpWindowImpl->maEventListeners.push_back( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::RemoveEventListener( const Link& rEventListener )
+{
+ mpWindowImpl->maEventListeners.remove( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::AddChildEventListener( const Link& rEventListener )
+{
+ mpWindowImpl->maChildEventListeners.push_back( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::RemoveChildEventListener( const Link& rEventListener )
+{
+ mpWindowImpl->maChildEventListeners.remove( rEventListener );
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Window::PostUserEvent( ULONG nEvent, void* pEventData )
+{
+ ULONG nEventId;
+ PostUserEvent( nEventId, nEvent, pEventData );
+ return nEventId;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Window::PostUserEvent( const Link& rLink, void* pCaller )
+{
+ ULONG nEventId;
+ PostUserEvent( nEventId, rLink, pCaller );
+ return nEventId;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::PostUserEvent( ULONG& rEventId, ULONG nEvent, void* pEventData )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVEvent* pSVEvent = new ImplSVEvent;
+ pSVEvent->mnEvent = nEvent;
+ pSVEvent->mpData = pEventData;
+ pSVEvent->mpLink = NULL;
+ pSVEvent->mpWindow = this;
+ pSVEvent->mbCall = TRUE;
+ ImplAddDel( &(pSVEvent->maDelData) );
+ rEventId = (ULONG)pSVEvent;
+ if ( mpWindowImpl->mpFrame->PostEvent( pSVEvent ) )
+ return TRUE;
+ else
+ {
+ rEventId = 0;
+ ImplRemoveDel( &(pSVEvent->maDelData) );
+ delete pSVEvent;
+ return FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::PostUserEvent( ULONG& rEventId, const Link& rLink, void* pCaller )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVEvent* pSVEvent = new ImplSVEvent;
+ pSVEvent->mnEvent = 0;
+ pSVEvent->mpData = pCaller;
+ pSVEvent->mpLink = new Link( rLink );
+ pSVEvent->mpWindow = this;
+ pSVEvent->mbCall = TRUE;
+ ImplAddDel( &(pSVEvent->maDelData) );
+ rEventId = (ULONG)pSVEvent;
+ if ( mpWindowImpl->mpFrame->PostEvent( pSVEvent ) )
+ return TRUE;
+ else
+ {
+ rEventId = 0;
+ ImplRemoveDel( &(pSVEvent->maDelData) );
+ delete pSVEvent;
+ return FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::RemoveUserEvent( ULONG nUserEvent )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVEvent* pSVEvent = (ImplSVEvent*)nUserEvent;
+
+ DBG_ASSERT( pSVEvent->mpWindow == this,
+ "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed" );
+ DBG_ASSERT( pSVEvent->mbCall,
+ "Window::RemoveUserEvent(): Event is already removed" );
+
+ if ( pSVEvent->mpWindow )
+ {
+ pSVEvent->mpWindow->ImplRemoveDel( &(pSVEvent->maDelData) );
+ pSVEvent->mpWindow = NULL;
+ }
+
+ pSVEvent->mbCall = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Window, ImplAsyncStateChangedHdl, void*, pState )
+{
+ StateChanged( (StateChangedType)(ULONG)pState );
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::PostStateChanged( StateChangedType nState )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ PostUserEvent( LINK( this, Window, ImplAsyncStateChangedHdl ), (void*)(ULONG)nState );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsLocked( BOOL bChilds ) const
+{
+ if ( mpWindowImpl->mnLockCount != 0 )
+ return TRUE;
+
+ if ( bChilds || mpWindowImpl->mbChildNotify )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ if ( pChild->IsLocked( TRUE ) )
+ return TRUE;
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetStyle( WinBits nStyle )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mnStyle != nStyle )
+ {
+ mpWindowImpl->mnPrevStyle = mpWindowImpl->mnStyle;
+ mpWindowImpl->mnStyle = nStyle;
+ StateChanged( STATE_CHANGE_STYLE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetExtendedStyle( WinBits nExtendedStyle )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mnExtendedStyle != nExtendedStyle )
+ {
+ Window* pWindow = ImplGetBorderWindow();
+ if( ! pWindow )
+ pWindow = this;
+ if( pWindow->mpWindowImpl->mbFrame )
+ {
+ SalExtStyle nExt = 0;
+ if( (nExtendedStyle & WB_EXT_DOCUMENT) )
+ nExt |= SAL_FRAME_EXT_STYLE_DOCUMENT;
+ if( (nExtendedStyle & WB_EXT_DOCMODIFIED) )
+ nExt |= SAL_FRAME_EXT_STYLE_DOCMODIFIED;
+
+ pWindow->ImplGetFrame()->SetExtendedFrameStyle( nExt );
+ }
+ mpWindowImpl->mnPrevExtendedStyle = mpWindowImpl->mnExtendedStyle;
+ mpWindowImpl->mnExtendedStyle = nExtendedStyle;
+ StateChanged( STATE_CHANGE_EXTENDEDSTYLE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SystemWindow* Window::GetSystemWindow() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ const Window* pWin = this;
+ while ( pWin && !pWin->IsSystemWindow() )
+ pWin = pWin->GetParent();
+ return (SystemWindow*)pWin;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetBorderStyle( USHORT nBorderStyle )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ if( nBorderStyle == WINDOW_BORDER_REMOVEBORDER &&
+ ! mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame &&
+ mpWindowImpl->mpBorderWindow->mpWindowImpl->mpParent
+ )
+ {
+ // this is a little awkward: some controls (e.g. svtools ProgressBar)
+ // cannot avoid getting constructed with WB_BORDER but want to disable
+ // borders in case of NWF drawing. So they need a method to remove their border window
+ Window* pBorderWin = mpWindowImpl->mpBorderWindow;
+ // remove us as border window's client
+ pBorderWin->mpWindowImpl->mpClientWindow = NULL;
+ mpWindowImpl->mpBorderWindow = NULL;
+ mpWindowImpl->mpRealParent = pBorderWin->mpWindowImpl->mpParent;
+ // reparent us above the border window
+ SetParent( pBorderWin->mpWindowImpl->mpParent );
+ // set us to the position and size of our previous border
+ Point aBorderPos( pBorderWin->GetPosPixel() );
+ Size aBorderSize( pBorderWin->GetSizePixel() );
+ SetPosSizePixel( aBorderPos.X(), aBorderPos.Y(), aBorderSize.Width(), aBorderSize.Height() );
+ // release border window
+ delete pBorderWin;
+
+ // set new style bits
+ SetStyle( GetStyle() & (~WB_BORDER) );
+ }
+ else
+ {
+ if ( mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetBorderStyle( nBorderStyle );
+ else
+ mpWindowImpl->mpBorderWindow->SetBorderStyle( nBorderStyle );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Window::GetBorderStyle() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ if ( mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW )
+ return ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->GetBorderStyle();
+ else
+ return mpWindowImpl->mpBorderWindow->GetBorderStyle();
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+long Window::CalcTitleWidth() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ if ( mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW )
+ return ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->CalcTitleWidth();
+ else
+ return mpWindowImpl->mpBorderWindow->CalcTitleWidth();
+ }
+ else if ( mpWindowImpl->mbFrame && (mpWindowImpl->mnStyle & WB_MOVEABLE) )
+ {
+ // Fuer Frame-Fenster raten wir die Breite, da wir den Border fuer
+ // externe Dialoge nicht kennen
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Font aFont = GetFont();
+ ((Window*)this)->SetPointFont( rStyleSettings.GetTitleFont() );
+ long nTitleWidth = GetTextWidth( GetText() );
+ ((Window*)this)->SetFont( aFont );
+ nTitleWidth += rStyleSettings.GetTitleHeight() * 3;
+ nTitleWidth += rStyleSettings.GetBorderSize() * 2;
+ nTitleWidth += 10;
+ return nTitleWidth;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EnableClipSiblings( BOOL bClipSiblings )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->EnableClipSiblings( bClipSiblings );
+
+ mpWindowImpl->mbClipSiblings = bClipSiblings;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetMouseTransparent( BOOL bTransparent )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->SetMouseTransparent( bTransparent );
+
+ if( mpWindowImpl->mpSysObj )
+ mpWindowImpl->mpSysObj->SetMouseTransparent( bTransparent );
+
+ mpWindowImpl->mbMouseTransparent = bTransparent;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetPaintTransparent( BOOL bTransparent )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ // transparency is not useful for frames as the background would have to be provided by a different frame
+ if( bTransparent && mpWindowImpl->mbFrame )
+ return;
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
+
+ mpWindowImpl->mbPaintTransparent = bTransparent;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetInputContext( const InputContext& rInputContext )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ mpWindowImpl->maInputContext = rInputContext;
+ if ( !mpWindowImpl->mbInFocusHdl && HasFocus() )
+ ImplNewInputContext();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EndExtTextInput( USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mbExtTextInput )
+ ImplGetFrame()->EndExtTextInput( nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetCursorRect( const Rectangle* pRect, long nExtTextInputWidth )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplWinData* pWinData = ImplGetWinData();
+ if ( pWinData->mpCursorRect )
+ {
+ if ( pRect )
+ *pWinData->mpCursorRect = *pRect;
+ else
+ {
+ delete pWinData->mpCursorRect;
+ pWinData->mpCursorRect = NULL;
+ }
+ }
+ else
+ {
+ if ( pRect )
+ pWinData->mpCursorRect = new Rectangle( *pRect );
+ }
+
+ pWinData->mnCursorExtWidth = nExtTextInputWidth;
+
+}
+
+// -----------------------------------------------------------------------
+
+const Rectangle* Window::GetCursorRect() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplWinData* pWinData = ImplGetWinData();
+ return pWinData->mpCursorRect;
+}
+
+// -----------------------------------------------------------------------
+
+long Window::GetCursorExtTextInputWidth() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplWinData* pWinData = ImplGetWinData();
+ return pWinData->mnCursorExtWidth;
+}
+
+// -----------------------------------------------------------------------
+void Window::SetSettings( const AllSettings& rSettings )
+{
+ SetSettings( rSettings, FALSE );
+}
+
+void Window::SetSettings( const AllSettings& rSettings, BOOL bChild )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpBorderWindow->SetSettings( rSettings, FALSE );
+ if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) &&
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->SetSettings( rSettings, TRUE );
+ }
+
+ AllSettings aOldSettings = maSettings;
+ OutputDevice::SetSettings( rSettings );
+ ULONG nChangeFlags = aOldSettings.GetChangeFlags( rSettings );
+
+ // AppFont-Aufloesung und DPI-Aufloesung neu berechnen
+ ImplInitResolutionSettings();
+
+ if ( nChangeFlags )
+ {
+ DataChangedEvent aDCEvt( DATACHANGED_SETTINGS, &aOldSettings, nChangeFlags );
+ DataChanged( aDCEvt );
+ }
+
+ if ( bChild || mpWindowImpl->mbChildNotify )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->SetSettings( rSettings, bChild );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::UpdateSettings( const AllSettings& rSettings, BOOL bChild )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpBorderWindow->UpdateSettings( rSettings, FALSE );
+ if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) &&
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->UpdateSettings( rSettings, TRUE );
+ }
+
+ AllSettings aOldSettings = maSettings;
+ ULONG nChangeFlags = maSettings.Update( maSettings.GetWindowUpdate(), rSettings );
+ nChangeFlags |= SETTINGS_IN_UPDATE_SETTINGS; // Set this flag so the receiver of the data changed
+ // event can distinguish between the changing of global
+ // setting and a local change ( with SetSettings )
+
+ // AppFont-Aufloesung und DPI-Aufloesung neu berechnen
+ ImplInitResolutionSettings();
+
+ /* #i73785#
+ * do not overwrite a WheelBehavior with false
+ * this looks kind of a hack, but WheelBehavior
+ * is always a local change, not a system property,
+ * so we can spare all our users the hassle of reacting on
+ * this in their respective DataChanged.
+ */
+ MouseSettings aSet( maSettings.GetMouseSettings() );
+ aSet.SetWheelBehavior( aOldSettings.GetMouseSettings().GetWheelBehavior() );
+ maSettings.SetMouseSettings( aSet );
+
+ if( (nChangeFlags & SETTINGS_STYLE) && IsBackground() )
+ {
+ Wallpaper aWallpaper = GetBackground();
+ if( !aWallpaper.IsBitmap() && !aWallpaper.IsGradient() )
+ {
+ if ( mpWindowImpl->mnStyle & WB_3DLOOK )
+ SetBackground( Wallpaper( rSettings.GetStyleSettings().GetFaceColor() ) );
+ else
+ SetBackground( Wallpaper( rSettings.GetStyleSettings().GetWindowColor() ) );
+ }
+ }
+
+ if ( nChangeFlags )
+ {
+ DataChangedEvent aDCEvt( DATACHANGED_SETTINGS, &aOldSettings, nChangeFlags );
+ DataChanged( aDCEvt );
+ // notify data change handler
+ ImplCallEventListeners( VCLEVENT_WINDOW_DATACHANGED, &aDCEvt);
+ }
+
+ if ( bChild || mpWindowImpl->mbChildNotify )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->UpdateSettings( rSettings, bChild );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::NotifyAllChilds( DataChangedEvent& rDCEvt )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ DataChanged( rDCEvt );
+
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->NotifyAllChilds( rDCEvt );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetPointFont( const Font& rFont )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Font aFont = rFont;
+ ImplPointToLogic( aFont );
+ SetFont( aFont );
+}
+
+// -----------------------------------------------------------------------
+
+Font Window::GetPointFont() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Font aFont = GetFont();
+ ImplLogicToPoint( aFont );
+ return aFont;
+}
+
+// -----------------------------------------------------------------------
+
+// TODO: remove in next incompatible build
+void Window::GetFontResolution( sal_Int32& nDPIX, sal_Int32& nDPIY ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ nDPIX = mpWindowImpl->mpFrameData->mnDPIX;
+ nDPIY = mpWindowImpl->mpFrameData->mnDPIY;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetParentClipMode( USHORT nMode )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->SetParentClipMode( nMode );
+ else
+ {
+ if ( !ImplIsOverlapWindow() )
+ {
+ mpWindowImpl->mnParentClipMode = nMode;
+ if ( nMode & PARENTCLIPMODE_CLIP )
+ mpWindowImpl->mpParent->mpWindowImpl->mbClipChildren = TRUE;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Window::GetParentClipMode() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ return mpWindowImpl->mpBorderWindow->GetParentClipMode();
+ else
+ return mpWindowImpl->mnParentClipMode;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetWindowRegionPixel()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();
+ else if( mpWindowImpl->mbFrame )
+ {
+ mpWindowImpl->maWinRegion = Region( REGION_NULL);
+ mpWindowImpl->mbWinRegion = FALSE;
+ mpWindowImpl->mpFrame->ResetClipRegion();
+ }
+ else
+ {
+ if ( mpWindowImpl->mbWinRegion )
+ {
+ mpWindowImpl->maWinRegion = Region( REGION_NULL );
+ mpWindowImpl->mbWinRegion = FALSE;
+ ImplSetClipFlag();
+
+ if ( IsReallyVisible() )
+ {
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mpSaveBackDev )
+ ImplDeleteOverlapBackground();
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+ Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ Region aRegion( aRect );
+ ImplInvalidateParentFrameRegion( aRegion );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetWindowRegionPixel( const Region& rRegion )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion );
+ else if( mpWindowImpl->mbFrame )
+ {
+ if( rRegion.GetType() != REGION_NULL )
+ {
+ mpWindowImpl->maWinRegion = rRegion;
+ mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty();
+ if( mpWindowImpl->mbWinRegion )
+ {
+ // ClipRegion setzen/updaten
+ long nX;
+ long nY;
+ long nWidth;
+ long nHeight;
+ ULONG nRectCount;
+ ImplRegionInfo aInfo;
+ BOOL bRegionRect;
+
+ nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
+ mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
+ bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
+ while ( bRegionRect )
+ {
+ mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
+ bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
+ }
+ mpWindowImpl->mpFrame->EndSetClipRegion();
+ }
+ else
+ SetWindowRegionPixel();
+ }
+ else
+ SetWindowRegionPixel();
+ }
+ else
+ {
+ BOOL bInvalidate = FALSE;
+
+ if ( rRegion.GetType() == REGION_NULL )
+ {
+ if ( mpWindowImpl->mbWinRegion )
+ {
+ mpWindowImpl->maWinRegion = Region( REGION_NULL );
+ mpWindowImpl->mbWinRegion = FALSE;
+ ImplSetClipFlag();
+ bInvalidate = TRUE;
+ }
+ }
+ else
+ {
+ mpWindowImpl->maWinRegion = rRegion;
+ mpWindowImpl->mbWinRegion = TRUE;
+ ImplSetClipFlag();
+ bInvalidate = TRUE;
+ }
+
+ if ( IsReallyVisible() )
+ {
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mpSaveBackDev )
+ ImplDeleteOverlapBackground();
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+ Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ Region aRegion( aRect );
+ ImplInvalidateParentFrameRegion( aRegion );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Region& Window::GetWindowRegionPixel() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ return mpWindowImpl->mpBorderWindow->GetWindowRegionPixel();
+ else
+ return mpWindowImpl->maWinRegion;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsWindowRegionPixel() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ return mpWindowImpl->mpBorderWindow->IsWindowRegionPixel();
+ else
+ return mpWindowImpl->mbWinRegion;
+}
+
+// -----------------------------------------------------------------------
+
+Region Window::GetWindowClipRegionPixel( USHORT nFlags ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Region aWinClipRegion;
+
+ if ( nFlags & WINDOW_GETCLIPREGION_NOCHILDREN )
+ {
+ if ( mpWindowImpl->mbInitWinClipRegion )
+ ((Window*)this)->ImplInitWinClipRegion();
+ aWinClipRegion = mpWindowImpl->maWinClipRegion;
+ }
+ else
+ {
+ Region* pWinChildClipRegion = ((Window*)this)->ImplGetWinChildClipRegion();
+ aWinClipRegion = *pWinChildClipRegion;
+ // --- RTL --- remirror clip region before passing it to somebody
+ if( ImplIsAntiparallel() )
+ ImplReMirror( aWinClipRegion );
+ }
+
+ if ( nFlags & WINDOW_GETCLIPREGION_NULL )
+ {
+ Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ Region aWinRegion( aWinRect );
+
+ if ( aWinRegion == aWinClipRegion )
+ aWinClipRegion.SetNull();
+ }
+
+ aWinClipRegion.Move( -mnOutOffX, -mnOutOffY );
+
+ return aWinClipRegion;
+}
+
+// -----------------------------------------------------------------------
+
+Region Window::GetPaintRegion() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpPaintRegion )
+ {
+ Region aRegion = *mpWindowImpl->mpPaintRegion;
+ aRegion.Move( -mnOutOffX, -mnOutOffY );
+ return PixelToLogic( aRegion );
+ }
+ else
+ {
+ Region aPaintRegion( REGION_NULL );
+ return aPaintRegion;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ExpandPaintClipRegion( const Region& rRegion )
+{
+ if( mpWindowImpl->mpPaintRegion )
+ {
+ Region aPixRegion = LogicToPixel( rRegion );
+ Region aDevPixRegion = ImplPixelToDevicePixel( aPixRegion );
+
+ Region aWinChildRegion = *ImplGetWinChildClipRegion();
+ // --- RTL -- only this region is in frame coordinates, so re-mirror it
+ if( ImplIsAntiparallel() )
+ ImplReMirror( aWinChildRegion );
+ aDevPixRegion.Intersect( aWinChildRegion );
+ if( ! aDevPixRegion.IsEmpty() )
+ {
+ mpWindowImpl->mpPaintRegion->Union( aDevPixRegion );
+ mbInitClipRegion = TRUE;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static SystemWindow *ImplGetLastSystemWindow( Window *pWin )
+{
+ // get the most top-level system window, the one that contains the taskpanelist
+ SystemWindow *pSysWin = NULL;
+ if( !pWin )
+ return pSysWin;
+ Window *pMyParent = pWin;
+ while ( pMyParent )
+ {
+ if ( pMyParent->IsSystemWindow() )
+ pSysWin = (SystemWindow*)pMyParent;
+ pMyParent = pMyParent->GetParent();
+ }
+ return pSysWin;
+}
+
+void Window::SetParent( Window* pNewParent )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ DBG_ASSERT( pNewParent, "Window::SetParent(): pParent == NULL" );
+ DBG_ASSERT( pNewParent != this, "someone tried to reparent a window to itself" );
+
+ if( pNewParent == this )
+ return;
+
+ // check if the taskpanelist would change and move the window pointer accordingly
+ SystemWindow *pSysWin = ImplGetLastSystemWindow(this);
+ SystemWindow *pNewSysWin = NULL;
+ BOOL bChangeTaskPaneList = FALSE;
+ if( pSysWin && pSysWin->ImplIsInTaskPaneList( this ) )
+ {
+ pNewSysWin = ImplGetLastSystemWindow( pNewParent );
+ if( pNewSysWin && pNewSysWin != pSysWin )
+ {
+ bChangeTaskPaneList = TRUE;
+ pSysWin->GetTaskPaneList()->RemoveWindow( this );
+ }
+ }
+ // remove ownerdraw decorated windows from list in the top-most frame window
+ if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
+ {
+ ::std::vector< Window* >& rList = ImplGetOwnerDrawList();
+ ::std::vector< Window* >::iterator p;
+ p = ::std::find( rList.begin(), rList.end(), this );
+ if( p != rList.end() )
+ rList.erase( p );
+ }
+
+ ImplSetFrameParent( pNewParent );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpRealParent = pNewParent;
+ mpWindowImpl->mpBorderWindow->SetParent( pNewParent );
+ return;
+ }
+
+ if ( mpWindowImpl->mpParent == pNewParent )
+ return;
+
+ if ( mpWindowImpl->mbFrame )
+ mpWindowImpl->mpFrame->SetParent( pNewParent->mpWindowImpl->mpFrame );
+
+ BOOL bVisible = IsVisible();
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ // Testen, ob sich das Overlap-Window aendert
+ Window* pOldOverlapWindow;
+ Window* pNewOverlapWindow = NULL;
+ if ( ImplIsOverlapWindow() )
+ pOldOverlapWindow = NULL;
+ else
+ {
+ pNewOverlapWindow = pNewParent->ImplGetFirstOverlapWindow();
+ if ( mpWindowImpl->mpOverlapWindow != pNewOverlapWindow )
+ pOldOverlapWindow = mpWindowImpl->mpOverlapWindow;
+ else
+ pOldOverlapWindow = NULL;
+ }
+
+ // Fenster in der Hirachie umsetzen
+ BOOL bFocusOverlapWin = HasChildPathFocus( TRUE );
+ BOOL bFocusWin = HasChildPathFocus();
+ BOOL bNewFrame = pNewParent->mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow;
+ if ( bNewFrame )
+ {
+ if ( mpWindowImpl->mpFrameData->mpFocusWin )
+ {
+ if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpFocusWin ) )
+ mpWindowImpl->mpFrameData->mpFocusWin = NULL;
+ }
+ if ( mpWindowImpl->mpFrameData->mpMouseMoveWin )
+ {
+ if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseMoveWin ) )
+ mpWindowImpl->mpFrameData->mpMouseMoveWin = NULL;
+ }
+ if ( mpWindowImpl->mpFrameData->mpMouseDownWin )
+ {
+ if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseDownWin ) )
+ mpWindowImpl->mpFrameData->mpMouseDownWin = NULL;
+ }
+ }
+ ImplRemoveWindow( bNewFrame );
+ ImplInsertWindow( pNewParent );
+ if ( mpWindowImpl->mnParentClipMode & PARENTCLIPMODE_CLIP )
+ pNewParent->mpWindowImpl->mbClipChildren = TRUE;
+ ImplUpdateWindowPtr();
+ if ( ImplUpdatePos() )
+ ImplUpdateSysObjPos();
+
+ // Wenn sich das Overlap-Window geaendert hat, dann muss getestet werden,
+ // ob auch OverlapWindow die das Child-Fenster als Parent gehabt haben
+ // in der Window-Hirachie umgesetzt werden muessen
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( bNewFrame )
+ {
+ Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
+ pOverlapWindow = pNextOverlapWindow;
+ }
+ }
+ }
+ else if ( pOldOverlapWindow )
+ {
+ // Focus-Save zuruecksetzen
+ if ( bFocusWin ||
+ (pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow &&
+ IsWindowOrChild( pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow )) )
+ pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL;
+
+ Window* pOverlapWindow = pOldOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ if ( ImplIsRealParentPath( pOverlapWindow->ImplGetWindow() ) )
+ pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
+ pOverlapWindow = pNextOverlapWindow;
+ }
+
+ // Activate-Status beim naechsten Overlap-Window updaten
+ if ( HasChildPathFocus( TRUE ) )
+ ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow );
+ }
+
+ // Activate-Status mit umsetzen
+ if ( bNewFrame )
+ {
+ if ( (GetType() == WINDOW_BORDERWINDOW) &&
+ (ImplGetWindow()->GetType() == WINDOW_FLOATINGWINDOW) )
+ ((ImplBorderWindow*)this)->SetDisplayActive( mpWindowImpl->mpFrameData->mbHasFocus );
+ }
+
+ // Focus evtl. auf den neuen Frame umsetzen, wenn FocusWindow mit
+ // SetParent() umgesetzt wird
+ if ( bFocusOverlapWin )
+ {
+ mpWindowImpl->mpFrameData->mpFocusWin = Application::GetFocusWindow();
+ if ( !mpWindowImpl->mpFrameData->mbHasFocus )
+ {
+ mpWindowImpl->mpFrame->ToTop( 0 );
+ }
+ }
+
+ // Assure DragSource and DropTarget members are created
+ if ( bNewFrame )
+ {
+ GetDropTarget();
+ }
+
+ if( bChangeTaskPaneList )
+ pNewSysWin->GetTaskPaneList()->AddWindow( this );
+
+ if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
+ ImplGetOwnerDrawList().push_back( this );
+
+ if ( bVisible )
+ Show( TRUE, SHOW_NOFOCUSCHANGE | SHOW_NOACTIVATE );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Show( BOOL bVisible, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mbVisible == bVisible )
+ return;
+
+ ImplDelData aDogTag( this );
+
+ BOOL bRealVisibilityChanged = FALSE;
+ mpWindowImpl->mbVisible = (bVisible != 0);
+
+ if ( !bVisible )
+ {
+ ImplHideAllOverlaps();
+ if( aDogTag.IsDelete() )
+ return;
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ BOOL bOldUpdate = mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate;
+ if ( mpWindowImpl->mbNoParentUpdate )
+ mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate = TRUE;
+ mpWindowImpl->mpBorderWindow->Show( FALSE, nFlags );
+ mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate = bOldUpdate;
+ }
+ else if ( mpWindowImpl->mbFrame )
+ {
+ mpWindowImpl->mbSuppressAccessibilityEvents = TRUE;
+ mpWindowImpl->mpFrame->Show( FALSE, FALSE );
+ }
+
+ StateChanged( STATE_CHANGE_VISIBLE );
+
+ if ( mpWindowImpl->mbReallyVisible )
+ {
+ Region aInvRegion( REGION_EMPTY );
+ BOOL bSaveBack = FALSE;
+
+ if ( ImplIsOverlapWindow() && !mpWindowImpl->mbFrame )
+ {
+ if ( ImplRestoreOverlapBackground( aInvRegion ) )
+ bSaveBack = TRUE;
+ }
+
+ if ( !bSaveBack )
+ {
+ if ( mpWindowImpl->mbInitWinClipRegion )
+ ImplInitWinClipRegion();
+ aInvRegion = mpWindowImpl->maWinClipRegion;
+ }
+
+ if( aDogTag.IsDelete() )
+ return;
+
+ bRealVisibilityChanged = mpWindowImpl->mbReallyVisible;
+ ImplResetReallyVisible();
+ ImplSetClipFlag();
+
+ if ( ImplIsOverlapWindow() && !mpWindowImpl->mbFrame )
+ {
+ // Focus umsetzen
+ if ( !(nFlags & SHOW_NOFOCUSCHANGE) && HasChildPathFocus() )
+ {
+ if ( mpWindowImpl->mpOverlapWindow->IsEnabled() &&
+ mpWindowImpl->mpOverlapWindow->IsInputEnabled() &&
+ ! mpWindowImpl->mpOverlapWindow->IsInModalMode()
+ )
+ mpWindowImpl->mpOverlapWindow->GrabFocus();
+ }
+ }
+
+ if ( !mpWindowImpl->mbFrame )
+ {
+ if( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mbEnableNativeWidget )
+ {
+ /*
+ * #i48371# native theming: some themes draw outside the control
+ * area we tell them to (bad thing, but we cannot do much about it ).
+ * On hiding these controls they get invalidated with their window rectangle
+ * which leads to the parts outside the control area being left and not
+ * invalidated. Workaround: invalidate an area on the parent, too
+ */
+ const int workaround_border = 5;
+ Rectangle aBounds( aInvRegion.GetBoundRect() );
+ aBounds.Left() -= workaround_border;
+ aBounds.Top() -= workaround_border;
+ aBounds.Right() += workaround_border;
+ aBounds.Bottom() += workaround_border;
+ aInvRegion = aBounds;
+ }
+ if ( !mpWindowImpl->mbNoParentUpdate && !(nFlags & SHOW_NOPARENTUPDATE) )
+ {
+ if ( !aInvRegion.IsEmpty() )
+ ImplInvalidateParentFrameRegion( aInvRegion );
+ }
+ ImplGenerateMouseMove();
+ }
+ }
+ }
+ else
+ {
+ // inherit native widget flag for form controls
+ // required here, because frames never show up in the child hierarchy - which should be fixed....
+ // eg, the drop down of a combobox which is a system floating window
+ if( mpWindowImpl->mbFrame && GetParent() && GetParent()->IsCompoundControl() &&
+ GetParent()->IsNativeWidgetEnabled() != IsNativeWidgetEnabled() )
+ EnableNativeWidget( GetParent()->IsNativeWidgetEnabled() );
+
+ if ( mpWindowImpl->mbCallMove )
+ {
+ ImplCallMove();
+ }
+ if ( mpWindowImpl->mbCallResize )
+ {
+ ImplCallResize();
+ }
+
+ StateChanged( STATE_CHANGE_VISIBLE );
+
+ Window* pTestParent;
+ if ( ImplIsOverlapWindow() )
+ pTestParent = mpWindowImpl->mpOverlapWindow;
+ else
+ pTestParent = ImplGetParent();
+ if ( mpWindowImpl->mbFrame || pTestParent->mpWindowImpl->mbReallyVisible )
+ {
+ // Wenn ein Window gerade sichtbar wird, schicken wir allen
+ // Child-Fenstern ein StateChanged, damit diese sich
+ // initialisieren koennen
+ ImplCallInitShow();
+
+ // Wenn es ein SystemWindow ist, dann kommt es auch automatisch
+ // nach vorne, wenn es gewuenscht ist
+ if ( ImplIsOverlapWindow() && !(nFlags & SHOW_NOACTIVATE) )
+ {
+ ImplStartToTop(( nFlags & SHOW_FOREGROUNDTASK ) ? TOTOP_FOREGROUNDTASK : 0 );
+ ImplFocusToTop( 0, FALSE );
+ }
+
+ // Hintergrund sichern
+ if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mbSaveBack )
+ ImplSaveOverlapBackground();
+ // adjust mpWindowImpl->mbReallyVisible
+ bRealVisibilityChanged = !mpWindowImpl->mbReallyVisible;
+ ImplSetReallyVisible();
+
+ // Dafuer sorgen, das Clip-Rechtecke neu berechnet werden
+ ImplSetClipFlag();
+
+ if ( !mpWindowImpl->mbFrame )
+ {
+ USHORT nInvalidateFlags = INVALIDATE_CHILDREN;
+ if( ! IsPaintTransparent() )
+ nInvalidateFlags |= INVALIDATE_NOTRANSPARENT;
+ ImplInvalidate( NULL, nInvalidateFlags );
+ ImplGenerateMouseMove();
+ }
+ }
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->Show( TRUE, nFlags );
+ else if ( mpWindowImpl->mbFrame )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ // #106431#, hide SplashScreen
+ if( pSVData->mpIntroWindow && !ImplIsWindowOrChild( pSVData->mpIntroWindow ) )
+ pSVData->mpIntroWindow->Hide();
+
+ //DBG_ASSERT( !mpWindowImpl->mbSuppressAccessibilityEvents, "Window::Show() - Frame reactivated");
+ mpWindowImpl->mbSuppressAccessibilityEvents = FALSE;
+
+ mpWindowImpl->mbPaintFrame = TRUE;
+ BOOL bNoActivate = (nFlags & (SHOW_NOACTIVATE|SHOW_NOFOCUSCHANGE)) ? TRUE : FALSE;
+ mpWindowImpl->mpFrame->Show( TRUE, bNoActivate );
+ if( aDogTag.IsDelete() )
+ return;
+
+ // Query the correct size of the window, if we are waiting for
+ // a system resize
+ if ( mpWindowImpl->mbWaitSystemResize )
+ {
+ long nOutWidth;
+ long nOutHeight;
+ mpWindowImpl->mpFrame->GetClientSize( nOutWidth, nOutHeight );
+ ImplHandleResize( this, nOutWidth, nOutHeight );
+ }
+ }
+
+ if( aDogTag.IsDelete() )
+ return;
+
+#ifdef DBG_UTIL
+ if ( IsDialog() || (GetType() == WINDOW_TABPAGE) || (GetType() == WINDOW_DOCKINGWINDOW) )
+ {
+ DBG_DIALOGTEST( this );
+ }
+#endif
+
+ ImplShowAllOverlaps();
+ }
+
+ if( aDogTag.IsDelete() )
+ return;
+ // invalidate all saved backgrounds
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+
+ // the SHOW/HIDE events also serve as indicators to send child creation/destroy events to the access bridge
+ // However, the access bridge only uses this event if the data member is not NULL (it's kind of a hack that
+ // we re-use the SHOW/HIDE events this way, with this particular semantics).
+ // Since #104887#, the notifications for the access bridge are done in Impl(Set|Reset)ReallyVisible. Here, we
+ // now only notify with a NULL data pointer, for all other clients except the access bridge.
+ if ( !bRealVisibilityChanged )
+ ImplCallEventListeners( mpWindowImpl->mbVisible ? VCLEVENT_WINDOW_SHOW : VCLEVENT_WINDOW_HIDE, NULL );
+ if( aDogTag.IsDelete() )
+ return;
+
+ // #107575#, if a floating windows is shown that grabs the focus, we have to notify the toolkit about it
+ // ImplGrabFocus() is not called in this case
+ // Because this might lead to problems the task will be shifted to 6.y
+ // Note: top-level context menues are registered at the access bridge after being shown,
+ // so this will probably not help here....
+ /*
+ if( mpWindowImpl->mbFloatWin && ((FloatingWindow*) this )->GrabsFocus() )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if( !mpWindowImpl->mbVisible )
+ {
+ ImplCallEventListeners( VCLEVENT_WINDOW_LOSEFOCUS );
+ if( pSVData->maWinData.mpFocusWin )
+ pSVData->maWinData.mpFocusWin->ImplCallEventListeners( VCLEVENT_WINDOW_GETFOCUS );
+ }
+ else
+ {
+ if( pSVData->maWinData.mpFocusWin )
+ pSVData->maWinData.mpFocusWin->ImplCallEventListeners( VCLEVENT_WINDOW_LOSEFOCUS );
+ ImplCallEventListeners( VCLEVENT_WINDOW_GETFOCUS );
+ }
+ }
+ */
+}
+
+// -----------------------------------------------------------------------
+
+Size Window::GetSizePixel() const
+{
+ // #i43257# trigger pending resize handler to assure correct window sizes
+ if( mpWindowImpl->mpFrameData->maResizeTimer.IsActive() )
+ {
+ ImplDelData aDogtag( this );
+ mpWindowImpl->mpFrameData->maResizeTimer.Stop();
+ mpWindowImpl->mpFrameData->maResizeTimer.GetTimeoutHdl().Call( NULL );
+ if( aDogtag.IsDelete() )
+ return Size(0,0);
+ }
+
+ return Size( mnOutWidth+mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder,
+ mnOutHeight+mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder );
+}
+
+void Window::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const
+{
+ rLeftBorder = mpWindowImpl->mnLeftBorder;
+ rTopBorder = mpWindowImpl->mnTopBorder;
+ rRightBorder = mpWindowImpl->mnRightBorder;
+ rBottomBorder = mpWindowImpl->mnBottomBorder;
+}
+
+
+// -----------------------------------------------------------------------
+
+void Window::Enable( bool bEnable, bool bChild )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !bEnable )
+ {
+ // Wenn ein Fenster disablte wird, wird automatisch der Tracking-Modus
+ // beendet oder der Capture geklaut
+ if ( IsTracking() )
+ EndTracking( ENDTRACK_CANCEL );
+ if ( IsMouseCaptured() )
+ ReleaseMouse();
+ // Wenn Fenster den Focus hat und in der Dialog-Steuerung enthalten,
+ // wird versucht, den Focus auf das naechste Control weiterzuschalten
+ // mpWindowImpl->mbDisabled darf erst nach Aufruf von ImplDlgCtrlNextWindow() gesetzt
+ // werden. Ansonsten muss ImplDlgCtrlNextWindow() umgestellt werden
+ if ( HasFocus() )
+ ImplDlgCtrlNextWindow();
+ }
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpBorderWindow->Enable( bEnable, FALSE );
+ if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) &&
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->Enable( bEnable, TRUE );
+ }
+
+ // #i56102# restore app focus win in case the
+ // window was disabled when the frame focus changed
+ ImplSVData* pSVData = ImplGetSVData();
+ if( bEnable &&
+ pSVData->maWinData.mpFocusWin == NULL &&
+ mpWindowImpl->mpFrameData->mbHasFocus &&
+ mpWindowImpl->mpFrameData->mpFocusWin == this )
+ pSVData->maWinData.mpFocusWin = this;
+
+ if ( mpWindowImpl->mbDisabled != !bEnable )
+ {
+ mpWindowImpl->mbDisabled = !bEnable;
+ if ( mpWindowImpl->mpSysObj )
+ mpWindowImpl->mpSysObj->Enable( bEnable && !mpWindowImpl->mbInputDisabled );
+// if ( mpWindowImpl->mbFrame )
+// mpWindowImpl->mpFrame->Enable( bEnable && !mpWindowImpl->mbInputDisabled );
+ StateChanged( STATE_CHANGE_ENABLE );
+
+ ImplCallEventListeners( bEnable ? VCLEVENT_WINDOW_ENABLED : VCLEVENT_WINDOW_DISABLED );
+ }
+
+ if ( bChild || mpWindowImpl->mbChildNotify )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->Enable( bEnable, bChild );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+
+ if ( IsReallyVisible() )
+ ImplGenerateMouseMove();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetCallHandlersOnInputDisabled( bool bCall )
+{
+ mpWindowImpl->mbCallHandlersDuringInputDisabled = bCall ? TRUE : FALSE;
+
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->SetCallHandlersOnInputDisabled( bCall );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool Window::IsCallHandlersOnInputDisabled() const
+{
+ return mpWindowImpl->mbCallHandlersDuringInputDisabled ? true : false;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EnableInput( BOOL bEnable, BOOL bChild )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ BOOL bNotify = (bEnable != mpWindowImpl->mbInputDisabled);
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpBorderWindow->EnableInput( bEnable, FALSE );
+ if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) &&
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow )
+ ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->EnableInput( bEnable, TRUE );
+ }
+
+ if ( (! bEnable && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled) ||
+ ( bEnable && mpWindowImpl->meAlwaysInputMode != AlwaysInputDisabled) )
+ {
+ // Wenn ein Fenster disablte wird, wird automatisch der
+ // Tracking-Modus beendet oder der Capture geklaut
+ if ( !bEnable )
+ {
+ if ( IsTracking() )
+ EndTracking( ENDTRACK_CANCEL );
+ if ( IsMouseCaptured() )
+ ReleaseMouse();
+ }
+
+ if ( mpWindowImpl->mbInputDisabled != !bEnable )
+ {
+ mpWindowImpl->mbInputDisabled = !bEnable;
+ if ( mpWindowImpl->mpSysObj )
+ mpWindowImpl->mpSysObj->Enable( !mpWindowImpl->mbDisabled && bEnable );
+// if ( mpWindowImpl->mbFrame )
+// mpWindowImpl->mpFrame->Enable( !mpWindowImpl->mbDisabled && bEnable );
+ }
+ }
+
+ // #i56102# restore app focus win in case the
+ // window was disabled when the frame focus changed
+ ImplSVData* pSVData = ImplGetSVData();
+ if( bEnable &&
+ pSVData->maWinData.mpFocusWin == NULL &&
+ mpWindowImpl->mpFrameData->mbHasFocus &&
+ mpWindowImpl->mpFrameData->mpFocusWin == this )
+ pSVData->maWinData.mpFocusWin = this;
+
+ if ( bChild || mpWindowImpl->mbChildNotify )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->EnableInput( bEnable, bChild );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+
+ if ( IsReallyVisible() )
+ ImplGenerateMouseMove();
+
+ // #104827# notify parent
+ if ( bNotify )
+ {
+ NotifyEvent aNEvt( bEnable ? EVENT_INPUTENABLE : EVENT_INPUTDISABLE, this );
+ Notify( aNEvt );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EnableInput( BOOL bEnable, BOOL bChild, BOOL bSysWin,
+ const Window* pExcludeWindow )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ EnableInput( bEnable, bChild );
+ if ( bSysWin )
+ {
+ // pExculeWindow is the first Overlap-Frame --> if this
+ // shouldn't be the case, than this must be changed in dialog.cxx
+ if( pExcludeWindow )
+ pExcludeWindow = pExcludeWindow->ImplGetFirstOverlapWindow();
+ Window* pSysWin = mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pSysWin )
+ {
+ // Is Window in the path from this window
+ if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( pSysWin, TRUE ) )
+ {
+ // Is Window not in the exclude window path or not the
+ // exclude window, than change the status
+ if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( pSysWin, TRUE ) )
+ pSysWin->EnableInput( bEnable, bChild );
+ }
+ pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
+ }
+
+ // enable/disable floating system windows as well
+ Window* pFrameWin = ImplGetSVData()->maWinData.mpFirstFrame;
+ while ( pFrameWin )
+ {
+ if( pFrameWin->ImplIsFloatingWindow() )
+ {
+ // Is Window in the path from this window
+ if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( pFrameWin, TRUE ) )
+ {
+ // Is Window not in the exclude window path or not the
+ // exclude window, than change the status
+ if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( pFrameWin, TRUE ) )
+ pFrameWin->EnableInput( bEnable, bChild );
+ }
+ }
+ pFrameWin = pFrameWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+
+ // the same for ownerdraw floating windows
+ if( mpWindowImpl->mbFrame )
+ {
+ ::std::vector< Window* >& rList = mpWindowImpl->mpFrameData->maOwnerDrawList;
+ ::std::vector< Window* >::iterator p = rList.begin();
+ while( p != rList.end() )
+ {
+ // Is Window in the path from this window
+ if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( (*p), TRUE ) )
+ {
+ // Is Window not in the exclude window path or not the
+ // exclude window, than change the status
+ if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( (*p), TRUE ) )
+ (*p)->EnableInput( bEnable, bChild );
+ }
+ p++;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::AlwaysEnableInput( BOOL bAlways, BOOL bChild )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->AlwaysEnableInput( bAlways, FALSE );
+
+ if( bAlways && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled )
+ {
+ mpWindowImpl->meAlwaysInputMode = AlwaysInputEnabled;
+
+ if ( bAlways )
+ EnableInput( TRUE, FALSE );
+ }
+ else if( ! bAlways && mpWindowImpl->meAlwaysInputMode == AlwaysInputEnabled )
+ {
+ mpWindowImpl->meAlwaysInputMode = AlwaysInputNone;
+ }
+
+ if ( bChild || mpWindowImpl->mbChildNotify )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->AlwaysEnableInput( bAlways, bChild );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::AlwaysDisableInput( BOOL bAlways, BOOL bChild )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->AlwaysDisableInput( bAlways, FALSE );
+
+ if( bAlways && mpWindowImpl->meAlwaysInputMode != AlwaysInputDisabled )
+ {
+ mpWindowImpl->meAlwaysInputMode = AlwaysInputDisabled;
+
+ if ( bAlways )
+ EnableInput( FALSE, FALSE );
+ }
+ else if( ! bAlways && mpWindowImpl->meAlwaysInputMode == AlwaysInputDisabled )
+ {
+ mpWindowImpl->meAlwaysInputMode = AlwaysInputNone;
+ }
+
+ if ( bChild || mpWindowImpl->mbChildNotify )
+ {
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->AlwaysDisableInput( bAlways, bChild );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetActivateMode( USHORT nMode )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->SetActivateMode( nMode );
+
+ if ( mpWindowImpl->mnActivateMode != nMode )
+ {
+ mpWindowImpl->mnActivateMode = nMode;
+
+ // Evtl. ein Decativate/Activate ausloesen
+ if ( mpWindowImpl->mnActivateMode )
+ {
+ if ( (mpWindowImpl->mbActive || (GetType() == WINDOW_BORDERWINDOW)) &&
+ !HasChildPathFocus( TRUE ) )
+ {
+ mpWindowImpl->mbActive = FALSE;
+ Deactivate();
+ }
+ }
+ else
+ {
+ if ( !mpWindowImpl->mbActive || (GetType() == WINDOW_BORDERWINDOW) )
+ {
+ mpWindowImpl->mbActive = TRUE;
+ Activate();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ToTop( USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplStartToTop( nFlags );
+ ImplFocusToTop( nFlags, IsReallyVisible() );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetZOrder( Window* pRefWindow, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpBorderWindow->SetZOrder( pRefWindow, nFlags );
+ return;
+ }
+
+ if ( nFlags & WINDOW_ZORDER_FIRST )
+ {
+ if ( ImplIsOverlapWindow() )
+ pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ else
+ pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
+ nFlags |= WINDOW_ZORDER_BEFOR;
+ }
+ else if ( nFlags & WINDOW_ZORDER_LAST )
+ {
+ if ( ImplIsOverlapWindow() )
+ pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
+ else
+ pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
+ nFlags |= WINDOW_ZORDER_BEHIND;
+ }
+
+ while ( pRefWindow->mpWindowImpl->mpBorderWindow )
+ pRefWindow = pRefWindow->mpWindowImpl->mpBorderWindow;
+ if ( (pRefWindow == this) || mpWindowImpl->mbFrame )
+ return;
+
+ DBG_ASSERT( pRefWindow->mpWindowImpl->mpParent == mpWindowImpl->mpParent, "Window::SetZOrder() - pRefWindow has other parent" );
+ if ( nFlags & WINDOW_ZORDER_BEFOR )
+ {
+ if ( pRefWindow->mpWindowImpl->mpPrev == this )
+ return;
+
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpPrev )
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
+ }
+ else
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpPrev )
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
+ }
+
+ mpWindowImpl->mpPrev = pRefWindow->mpWindowImpl->mpPrev;
+ mpWindowImpl->mpNext = pRefWindow;
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
+ }
+ else if ( nFlags & WINDOW_ZORDER_BEHIND )
+ {
+ if ( pRefWindow->mpWindowImpl->mpNext == this )
+ return;
+
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpNext )
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
+ }
+ else
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpNext )
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
+ }
+
+ mpWindowImpl->mpPrev = pRefWindow;
+ mpWindowImpl->mpNext = pRefWindow->mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ }
+
+ if ( IsReallyVisible() )
+ {
+ // Hintergrund-Sicherung zuruecksetzen
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin )
+ ImplInvalidateAllOverlapBackgrounds();
+
+ if ( mpWindowImpl->mbInitWinClipRegion || !mpWindowImpl->maWinClipRegion.IsEmpty() )
+ {
+ BOOL bInitWinClipRegion = mpWindowImpl->mbInitWinClipRegion;
+ ImplSetClipFlag();
+
+ // Wenn ClipRegion noch nicht initalisiert wurde, dann
+ // gehen wir davon aus, das das Fenster noch nicht
+ // ausgegeben wurde und loesen somit auch keine
+ // Invalidates aus. Dies ist eine Optimierung fuer
+ // HTML-Dokumenten mit vielen Controls. Wenn es mal
+ // Probleme mit dieser Abfrage gibt, sollte man ein
+ // Flag einfuehren, ob das Fenster nach Show schon
+ // einmal ausgegeben wurde.
+ if ( !bInitWinClipRegion )
+ {
+ // Alle nebeneinanderliegen Fenster invalidieren
+ // Noch nicht komplett implementiert !!!
+ Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ Window* pWindow = NULL;
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpOverlapWindow )
+ pWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ }
+ else
+ pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild;
+ // Alle Fenster, die vor uns liegen und von uns verdeckt wurden,
+ // invalidieren
+ while ( pWindow )
+ {
+ if ( pWindow == this )
+ break;
+ Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ),
+ Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) );
+ if ( aWinRect.IsOver( aCompRect ) )
+ pWindow->Invalidate( INVALIDATE_CHILDREN | INVALIDATE_NOTRANSPARENT );
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ // Wenn uns ein Fenster welches im Hinterund liegt verdeckt hat,
+ // dann muessen wir uns neu ausgeben
+ while ( pWindow )
+ {
+ if ( pWindow != this )
+ {
+ Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ),
+ Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) );
+ if ( aWinRect.IsOver( aCompRect ) )
+ {
+ Invalidate( INVALIDATE_CHILDREN | INVALIDATE_NOTRANSPARENT );
+ break;
+ }
+ }
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EnableAlwaysOnTop( BOOL bEnable )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ mpWindowImpl->mbAlwaysOnTop = bEnable;
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->EnableAlwaysOnTop( bEnable );
+ else if ( bEnable && IsReallyVisible() )
+ ToTop();
+
+ if ( mpWindowImpl->mbFrame )
+ mpWindowImpl->mpFrame->SetAlwaysOnTop( bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ BOOL bHasValidSize = !mpWindowImpl->mbDefSize;
+
+ if ( nFlags & WINDOW_POSSIZE_POS )
+ mpWindowImpl->mbDefPos = FALSE;
+ if ( nFlags & WINDOW_POSSIZE_SIZE )
+ mpWindowImpl->mbDefSize = FALSE;
+
+ // Oberstes BorderWindow ist das Window, welches positioniert werden soll
+ Window* pWindow = this;
+ while ( pWindow->mpWindowImpl->mpBorderWindow )
+ pWindow = pWindow->mpWindowImpl->mpBorderWindow;
+
+ if ( pWindow->mpWindowImpl->mbFrame )
+ {
+ // Note: if we're positioning a frame, the coordinates are interpreted
+ // as being the top-left corner of the window's client area and NOT
+ // as the position of the border ! (due to limitations of several UNIX window managers)
+ long nOldWidth = pWindow->mnOutWidth;
+
+ if ( !(nFlags & WINDOW_POSSIZE_WIDTH) )
+ nWidth = pWindow->mnOutWidth;
+ if ( !(nFlags & WINDOW_POSSIZE_HEIGHT) )
+ nHeight = pWindow->mnOutHeight;
+
+
+ USHORT nSysFlags=0;
+ if( nFlags & WINDOW_POSSIZE_WIDTH )
+ nSysFlags |= SAL_FRAME_POSSIZE_WIDTH;
+ if( nFlags & WINDOW_POSSIZE_HEIGHT )
+ nSysFlags |= SAL_FRAME_POSSIZE_HEIGHT;
+ if( nFlags & WINDOW_POSSIZE_X )
+ {
+ nSysFlags |= SAL_FRAME_POSSIZE_X;
+ if( pWindow->GetParent() && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) )
+ {
+ Window* pParent = pWindow->GetParent();
+ nX += pParent->mnOutOffX;
+ }
+ if( GetParent() && GetParent()->ImplIsAntiparallel() )
+ {
+ // --- RTL --- (re-mirror at parent window)
+ Rectangle aRect( Point ( nX, nY ), Size( nWidth, nHeight ) );
+ GetParent()->ImplReMirror( aRect );
+ nX = aRect.nLeft;
+ }
+ }
+ if( !(nFlags & WINDOW_POSSIZE_X) && bHasValidSize && pWindow->mpWindowImpl->mpFrame->maGeometry.nWidth )
+ {
+ // --- RTL --- make sure the old right aligned position is not changed
+ // system windows will always grow to the right
+ if( pWindow->GetParent() && pWindow->GetParent()->ImplHasMirroredGraphics() )
+ {
+ long myWidth = nOldWidth;
+ if( !myWidth )
+ myWidth = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nWidth;
+ if( !myWidth )
+ myWidth = nWidth;
+ nFlags |= WINDOW_POSSIZE_X;
+ nSysFlags |= SAL_FRAME_POSSIZE_X;
+ nX = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX - pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX -
+ mpWindowImpl->mpFrame->GetUnmirroredGeometry().nLeftDecoration;
+ nX = pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX - mpWindowImpl->mpFrame->GetUnmirroredGeometry().nLeftDecoration +
+ pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nWidth - myWidth - 1 - mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX;
+ if(!(nFlags & WINDOW_POSSIZE_Y))
+ {
+ nFlags |= WINDOW_POSSIZE_Y;
+ nSysFlags |= SAL_FRAME_POSSIZE_Y;
+ nY = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nY - pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nY -
+ mpWindowImpl->mpFrame->GetUnmirroredGeometry().nTopDecoration;
+ }
+ }
+ }
+ if( nFlags & WINDOW_POSSIZE_Y )
+ {
+ nSysFlags |= SAL_FRAME_POSSIZE_Y;
+ if( pWindow->GetParent() && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) )
+ {
+ Window* pParent = pWindow->GetParent();
+ nY += pParent->mnOutOffY;
+ }
+ }
+
+ if( nSysFlags & (SAL_FRAME_POSSIZE_WIDTH|SAL_FRAME_POSSIZE_HEIGHT) )
+ {
+ // check for min/max client size and adjust size accordingly
+ // otherwise it may happen that the resize event is ignored, i.e. the old size remains
+ // unchanged but ImplHandleResize() is called with the wrong size
+ SystemWindow *pSystemWindow = dynamic_cast< SystemWindow* >( pWindow );
+ if( pSystemWindow )
+ {
+ Size aMinSize = pSystemWindow->GetMinOutputSizePixel();
+ Size aMaxSize = pSystemWindow->GetMaxOutputSizePixel();
+ if( nWidth < aMinSize.Width() )
+ nWidth = aMinSize.Width();
+ if( nHeight < aMinSize.Height() )
+ nHeight = aMinSize.Height();
+
+ if( nWidth > aMaxSize.Width() )
+ nWidth = aMaxSize.Width();
+ if( nHeight > aMaxSize.Height() )
+ nHeight = aMaxSize.Height();
+ }
+ }
+
+ pWindow->mpWindowImpl->mpFrame->SetPosSize( nX, nY, nWidth, nHeight, nSysFlags );
+
+ // Resize should be called directly. If we havn't
+ // set the correct size, we get a second resize from
+ // the system with the correct size. This can be happend
+ // if the size is to small or to large.
+ ImplHandleResize( pWindow, nWidth, nHeight );
+ }
+ else
+ {
+ pWindow->ImplPosSizeWindow( nX, nY, nWidth, nHeight, nFlags );
+ if ( IsReallyVisible() )
+ ImplGenerateMouseMove();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Point Window::GetPosPixel() const
+{
+ return mpWindowImpl->maPos;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle Window::GetDesktopRectPixel() const
+{
+ Rectangle rRect;
+ mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrame->GetWorkArea( rRect );
+ return rRect;
+}
+
+// -----------------------------------------------------------------------
+
+Point Window::OutputToScreenPixel( const Point& rPos ) const
+{
+ // relative to top level parent
+ return Point( rPos.X()+mnOutOffX, rPos.Y()+mnOutOffY );
+}
+
+// -----------------------------------------------------------------------
+
+Point Window::ScreenToOutputPixel( const Point& rPos ) const
+{
+ // relative to top level parent
+ return Point( rPos.X()-mnOutOffX, rPos.Y()-mnOutOffY );
+}
+
+// -----------------------------------------------------------------------
+
+long Window::ImplGetUnmirroredOutOffX()
+{
+ // revert mnOutOffX changes that were potentially made in ImplPosSizeWindow
+ long offx = mnOutOffX;
+ if( ImplHasMirroredGraphics() )
+ {
+ if( mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() )
+ {
+ if ( !ImplIsOverlapWindow() )
+ offx -= mpWindowImpl->mpParent->mnOutOffX;
+
+ offx = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - offx;
+
+ if ( !ImplIsOverlapWindow() )
+ offx += mpWindowImpl->mpParent->mnOutOffX;
+
+ }
+ }
+ return offx;
+}
+
+// normalized screen pixel are independent of mirroring
+Point Window::OutputToNormalizedScreenPixel( const Point& rPos ) const
+{
+ // relative to top level parent
+ long offx = ((Window*) this)->ImplGetUnmirroredOutOffX();
+ return Point( rPos.X()+offx, rPos.Y()+mnOutOffY );
+}
+
+Point Window::NormalizedScreenToOutputPixel( const Point& rPos ) const
+{
+ // relative to top level parent
+ long offx = ((Window*) this)->ImplGetUnmirroredOutOffX();
+ return Point( rPos.X()-offx, rPos.Y()-mnOutOffY );
+}
+
+// -----------------------------------------------------------------------
+
+Point Window::OutputToAbsoluteScreenPixel( const Point& rPos ) const
+{
+ // relative to the screen
+ Point p = OutputToScreenPixel( rPos );
+ SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
+ p.X() += g.nX;
+ p.Y() += g.nY;
+ return p;
+}
+
+// -----------------------------------------------------------------------
+
+Point Window::AbsoluteScreenToOutputPixel( const Point& rPos ) const
+{
+ // relative to the screen
+ Point p = ScreenToOutputPixel( rPos );
+ SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
+ p.X() -= g.nX;
+ p.Y() -= g.nY;
+ return p;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle Window::ImplOutputToUnmirroredAbsoluteScreenPixel( const Rectangle &rRect ) const
+{
+ // this method creates unmirrored screen coordinates to be compared with the desktop
+ // and is used for positioning of RTL popup windows correctly on the screen
+ SalFrameGeometry g = mpWindowImpl->mpFrame->GetUnmirroredGeometry();
+
+ Point p1 = OutputToScreenPixel( rRect.TopRight() );
+ p1.X() = g.nX+g.nWidth-p1.X();
+ p1.Y() += g.nY;
+
+ Point p2 = OutputToScreenPixel( rRect.BottomLeft() );
+ p2.X() = g.nX+g.nWidth-p2.X();
+ p2.Y() += g.nY;
+
+ return Rectangle( p1, p2 );
+}
+
+
+// -----------------------------------------------------------------------
+
+Rectangle Window::GetWindowExtentsRelative( Window *pRelativeWindow ) const
+{
+ // with decoration
+ return ImplGetWindowExtentsRelative( pRelativeWindow, FALSE );
+}
+
+Rectangle Window::GetClientWindowExtentsRelative( Window *pRelativeWindow ) const
+{
+ // without decoration
+ return ImplGetWindowExtentsRelative( pRelativeWindow, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle Window::ImplGetWindowExtentsRelative( Window *pRelativeWindow, BOOL bClientOnly ) const
+{
+ SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
+ // make sure we use the extent of our border window,
+ // otherwise we miss a few pixels
+ const Window *pWin = (!bClientOnly && mpWindowImpl->mpBorderWindow) ? mpWindowImpl->mpBorderWindow : this;
+
+ Point aPos( pWin->OutputToScreenPixel( Point(0,0) ) );
+ aPos.X() += g.nX;
+ aPos.Y() += g.nY;
+ Size aSize ( pWin->GetSizePixel() );
+ // #104088# do not add decoration to the workwindow to be compatible to java accessibility api
+ if( !bClientOnly && (mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame && GetType() != WINDOW_WORKWINDOW)) )
+ {
+ aPos.X() -= g.nLeftDecoration;
+ aPos.Y() -= g.nTopDecoration;
+ aSize.Width() += g.nLeftDecoration + g.nRightDecoration;
+ aSize.Height() += g.nTopDecoration + g.nBottomDecoration;
+ }
+ if( pRelativeWindow )
+ {
+ // #106399# express coordinates relative to borderwindow
+ Window *pRelWin = (!bClientOnly && pRelativeWindow->mpWindowImpl->mpBorderWindow) ? pRelativeWindow->mpWindowImpl->mpBorderWindow : pRelativeWindow;
+ aPos = pRelWin->AbsoluteScreenToOutputPixel( aPos );
+ }
+ return Rectangle( aPos, aSize );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Scroll( long nHorzScroll, long nVertScroll, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplScroll( Rectangle( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) ),
+ nHorzScroll, nVertScroll, nFlags & ~SCROLL_CLIP );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Scroll( long nHorzScroll, long nVertScroll,
+ const Rectangle& rRect, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Rectangle aRect = ImplLogicToDevicePixel( rRect );
+ aRect.Intersection( Rectangle( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ) );
+ if ( !aRect.IsEmpty() )
+ ImplScroll( aRect, nHorzScroll, nVertScroll, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Invalidate( USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight )
+ return;
+
+ ImplInvalidate( NULL, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Invalidate( const Rectangle& rRect, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight )
+ return;
+
+ Rectangle aRect = ImplLogicToDevicePixel( rRect );
+ if ( !aRect.IsEmpty() )
+ {
+ Region aRegion( aRect );
+ ImplInvalidate( &aRegion, nFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Invalidate( const Region& rRegion, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight )
+ return;
+
+ if ( rRegion.IsNull() )
+ ImplInvalidate( NULL, nFlags );
+ else
+ {
+ Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
+ if ( !aRegion.IsEmpty() )
+ ImplInvalidate( &aRegion, nFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Validate( USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight )
+ return;
+
+ ImplValidate( NULL, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Validate( const Rectangle& rRect, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight )
+ return;
+
+ Rectangle aRect = ImplLogicToDevicePixel( rRect );
+ if ( !aRect.IsEmpty() )
+ {
+ Region aRegion( aRect );
+ ImplValidate( &aRegion, nFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Validate( const Region& rRegion, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight )
+ return;
+
+ if ( rRegion.IsNull() )
+ ImplValidate( NULL, nFlags );
+ else
+ {
+ Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
+ if ( !aRegion.IsEmpty() )
+ ImplValidate( &aRegion, nFlags );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::HasPaintEvent() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !mpWindowImpl->mbReallyVisible )
+ return FALSE;
+
+ if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
+ return TRUE;
+
+ if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINT )
+ return TRUE;
+
+ if ( !ImplIsOverlapWindow() )
+ {
+ const Window* pTempWindow = this;
+ do
+ {
+ pTempWindow = pTempWindow->ImplGetParent();
+ if ( pTempWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINTCHILDS | IMPL_PAINT_PAINTALLCHILDS) )
+ return TRUE;
+ }
+ while ( !pTempWindow->ImplIsOverlapWindow() );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Update()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpBorderWindow->Update();
+ return;
+ }
+
+ if ( !mpWindowImpl->mbReallyVisible )
+ return;
+
+ BOOL bFlush = FALSE;
+ if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
+ {
+ Point aPoint( 0, 0 );
+ Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
+ ImplInvalidateOverlapFrameRegion( aRegion );
+ if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
+ bFlush = TRUE;
+ }
+
+ // Zuerst muessen wir alle Fenster ueberspringen, die Paint-Transparent
+ // sind
+ Window* pUpdateWindow = this;
+ Window* pWindow = pUpdateWindow;
+ while ( !pWindow->ImplIsOverlapWindow() )
+ {
+ if ( !pWindow->mpWindowImpl->mbPaintTransparent )
+ {
+ pUpdateWindow = pWindow;
+ break;
+ }
+ pWindow = pWindow->ImplGetParent();
+ }
+ // Ein Update wirkt immer auf das Window, wo PAINTALLCHILDS gesetzt
+ // ist, damit nicht zuviel gemalt wird
+ pWindow = pUpdateWindow;
+ do
+ {
+ if ( pWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS )
+ pUpdateWindow = pWindow;
+ if ( pWindow->ImplIsOverlapWindow() )
+ break;
+ pWindow = pWindow->ImplGetParent();
+ }
+ while ( pWindow );
+
+ // Wenn es etwas zu malen gibt, dann ein Paint ausloesen
+ if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDS) )
+ {
+ // und fuer alle ueber uns stehende System-Fenster auch ein Update
+ // ausloesen, damit nicht die ganze Zeit luecken stehen bleiben
+ Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow()->mpWindowImpl->mpFirstOverlap;
+ while ( pUpdateOverlapWindow )
+ {
+ pUpdateOverlapWindow->Update();
+ pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
+ }
+
+ pUpdateWindow->ImplCallPaint( NULL, pUpdateWindow->mpWindowImpl->mnPaintFlags );
+ }
+
+ if ( bFlush )
+ Flush();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Flush()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ const Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
+ mpWindowImpl->mpFrame->Flush( aWinRect );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Sync()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ mpWindowImpl->mpFrame->Sync();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetUpdateMode( BOOL bUpdate )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ mpWindowImpl->mbNoUpdate = !bUpdate;
+ StateChanged( STATE_CHANGE_UPDATEMODE );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::GrabFocus()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplGrabFocus( 0 );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::HasFocus() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ // #107575# the first floating window always has the keyboard focus, see also winproc.cxx: ImplGetKeyInputWindow()
+ // task was shifted to 6.y, so its commented out
+ /*
+ Window* pFocusWin = ImplGetSVData()->maWinData.mpFirstFloat;
+ if( pFocusWin && pFocusWin->mpWindowImpl->mbFloatWin && ((FloatingWindow *)pFocusWin)->GrabsFocus() )
+ pFocusWin = pFocusWin->GetPreferredKeyInputWindow();
+ else
+ pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
+
+ return (this == pFocusWin);
+ */
+
+ return (this == ImplGetSVData()->maWinData.mpFocusWin);
+}
+
+// -----------------------------------------------------------------------
+
+void Window::GrabFocusToDocument()
+{
+ Window *pWin = this;
+ while( pWin )
+ {
+ if( !pWin->GetParent() )
+ {
+ pWin->ImplGetFrameWindow()->GetWindow( WINDOW_CLIENT )->GrabFocus();
+ return;
+ }
+ pWin = pWin->GetParent();
+ }
+}
+
+void Window::SetFakeFocus( bool bFocus )
+{
+ ImplGetWindowImpl()->mbFakeFocusSet = bFocus;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::HasChildPathFocus( BOOL bSystemWindow ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ // #107575#, the first floating window always has the keyboard focus, see also winproc.cxx: ImplGetKeyInputWindow()
+ // task was shifted to 6.y, so its commented out
+ /*
+ Window* pFocusWin = ImplGetSVData()->maWinData.mpFirstFloat;
+ if( pFocusWin && pFocusWin->mpWindowImpl->mbFloatWin && ((FloatingWindow *)pFocusWin)->GrabsFocus() )
+ pFocusWin = pFocusWin->GetPreferredKeyInputWindow();
+ else
+ pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
+ */
+ Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
+ if ( pFocusWin )
+ return ImplIsWindowOrChild( pFocusWin, bSystemWindow );
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::CaptureMouse()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Tracking evt. beenden
+ if ( pSVData->maWinData.mpTrackWin != this )
+ {
+ if ( pSVData->maWinData.mpTrackWin )
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL );
+ }
+
+ if ( pSVData->maWinData.mpCaptureWin != this )
+ {
+ pSVData->maWinData.mpCaptureWin = this;
+ mpWindowImpl->mpFrame->CaptureMouse( TRUE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ReleaseMouse()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ DBG_ASSERTWARNING( pSVData->maWinData.mpCaptureWin == this,
+ "Window::ReleaseMouse(): window doesn't have the mouse capture" );
+
+ if ( pSVData->maWinData.mpCaptureWin == this )
+ {
+ pSVData->maWinData.mpCaptureWin = NULL;
+ mpWindowImpl->mpFrame->CaptureMouse( FALSE );
+ ImplGenerateMouseMove();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsMouseCaptured() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ return (this == ImplGetSVData()->maWinData.mpCaptureWin);
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetPointer( const Pointer& rPointer )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->maPointer == rPointer )
+ return;
+
+ mpWindowImpl->maPointer = rPointer;
+
+ // Pointer evt. direkt umsetzen
+ if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() )
+ mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EnableChildPointerOverwrite( BOOL bOverwrite )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mbChildPtrOverwrite == bOverwrite )
+ return;
+
+ mpWindowImpl->mbChildPtrOverwrite = bOverwrite;
+
+ // Pointer evt. direkt umsetzen
+ if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() )
+ mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetPointerPosPixel( const Point& rPos )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Point aPos = ImplOutputToFrame( rPos );
+ if( ImplHasMirroredGraphics() )
+ {
+ if( !IsRTLEnabled() )
+ {
+ // --- RTL --- (re-mirror mouse pos at this window)
+ ImplReMirror( aPos );
+ }
+ // mirroring is required here, SetPointerPos bypasses SalGraphics
+ mpGraphics->mirror( aPos.X(), this );
+ }
+ else if( ImplIsAntiparallel() )
+ {
+ ImplReMirror( aPos );
+ }
+ mpWindowImpl->mpFrame->SetPointerPos( aPos.X(), aPos.Y() );
+}
+
+// -----------------------------------------------------------------------
+
+Point Window::GetPointerPosPixel()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Point aPos( mpWindowImpl->mpFrameData->mnLastMouseX, mpWindowImpl->mpFrameData->mnLastMouseY );
+ if( ImplIsAntiparallel() )
+ {
+ // --- RTL --- (re-mirror mouse pos at this window)
+ ImplReMirror( aPos );
+ }
+ return ImplFrameToOutput( aPos );
+}
+
+// -----------------------------------------------------------------------
+
+Point Window::GetLastPointerPosPixel()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Point aPos( mpWindowImpl->mpFrameData->mnBeforeLastMouseX, mpWindowImpl->mpFrameData->mnBeforeLastMouseY );
+ if( ImplIsAntiparallel() )
+ {
+ // --- RTL --- (re-mirror mouse pos at this window)
+ ImplReMirror( aPos );
+ }
+ return ImplFrameToOutput( aPos );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ShowPointer( BOOL bVisible )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mbNoPtrVisible != !bVisible )
+ {
+ mpWindowImpl->mbNoPtrVisible = !bVisible;
+
+ // Pointer evt. direkt umsetzen
+ if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() )
+ mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Window::PointerState Window::GetPointerState()
+{
+ PointerState aState;
+ aState.mnState = 0;
+
+ if (mpWindowImpl->mpFrame)
+ {
+ SalFrame::SalPointerState aSalPointerState;
+
+ aSalPointerState = mpWindowImpl->mpFrame->GetPointerState();
+ if( ImplIsAntiparallel() )
+ {
+ // --- RTL --- (re-mirror mouse pos at this window)
+ ImplReMirror( aSalPointerState.maPos );
+ }
+ aState.maPos = ImplFrameToOutput( aSalPointerState.maPos );
+ aState.mnState = aSalPointerState.mnState;
+ }
+ return aState;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsMouseOver()
+{
+ return ImplGetWinData()->mbMouseOver;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EnterWait()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ mpWindowImpl->mnWaitCount++;
+
+ if ( mpWindowImpl->mnWaitCount == 1 )
+ {
+ // Pointer evt. direkt umsetzen
+ if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() )
+ mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::LeaveWait()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mnWaitCount )
+ {
+ mpWindowImpl->mnWaitCount--;
+
+ if ( !mpWindowImpl->mnWaitCount )
+ {
+ // Pointer evt. direkt umsetzen
+ if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() )
+ mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetCursor( Cursor* pCursor )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpCursor != pCursor )
+ {
+ if ( mpWindowImpl->mpCursor )
+ mpWindowImpl->mpCursor->ImplHide();
+ mpWindowImpl->mpCursor = pCursor;
+ if ( pCursor )
+ pCursor->ImplShow();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetText( const XubString& rStr )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ String oldTitle( mpWindowImpl->maText );
+ mpWindowImpl->maText = rStr;
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->SetText( rStr );
+ else if ( mpWindowImpl->mbFrame )
+ mpWindowImpl->mpFrame->SetTitle( rStr );
+
+ ImplCallEventListeners( VCLEVENT_WINDOW_FRAMETITLECHANGED, &oldTitle );
+
+ // #107247# needed for accessibility
+ // The VCLEVENT_WINDOW_FRAMETITLECHANGED is (mis)used to notify accessible name changes.
+ // Therefore a window, which is labeled by this window, must also notify an accessible
+ // name change.
+ if ( IsReallyVisible() )
+ {
+ Window* pWindow = GetLabelFor();
+ if ( pWindow && pWindow != this )
+ pWindow->ImplCallEventListeners( VCLEVENT_WINDOW_FRAMETITLECHANGED, &oldTitle );
+ }
+
+ StateChanged( STATE_CHANGE_TEXT );
+}
+
+// -----------------------------------------------------------------------
+
+String Window::GetText() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ return mpWindowImpl->maText;
+}
+
+// -----------------------------------------------------------------------
+
+String Window::GetDisplayText() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ return GetText();
+}
+
+// -----------------------------------------------------------------------
+
+const Wallpaper& Window::GetDisplayBackground() const
+{
+ // FIXME: fix issue 52349, need to fix this really in
+ // all NWF enabled controls
+ const ToolBox* pTB = dynamic_cast<const ToolBox*>(this);
+ if( pTB )
+ {
+ if( IsNativeWidgetEnabled() )
+ return pTB->ImplGetToolBoxPrivateData()->maDisplayBackground;
+ }
+
+ if( !IsBackground() )
+ {
+ if( mpWindowImpl->mpParent )
+ return mpWindowImpl->mpParent->GetDisplayBackground();
+ }
+
+ const Wallpaper& rBack = GetBackground();
+ if( ! rBack.IsBitmap() &&
+ ! rBack.IsGradient() &&
+ rBack.GetColor().GetColor() == COL_TRANSPARENT &&
+ mpWindowImpl->mpParent )
+ return mpWindowImpl->mpParent->GetDisplayBackground();
+ return rBack;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& Window::GetHelpText() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ SmartId aSmartId = GetSmartHelpId();
+
+ ULONG nNumHelpId = 0;
+ String aStrHelpId;
+ if( aSmartId.HasString() )
+ aStrHelpId = aSmartId.GetStr();
+ if( aSmartId.HasNumeric() )
+ nNumHelpId = aSmartId.GetNum();
+ bool bStrHelpId = (aStrHelpId.Len() > 0);
+
+ if ( !mpWindowImpl->maHelpText.Len() && (nNumHelpId || bStrHelpId) )
+ {
+ if ( !IsDialog() && (mpWindowImpl->mnType != WINDOW_TABPAGE) && (mpWindowImpl->mnType != WINDOW_FLOATINGWINDOW) )
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ if( bStrHelpId )
+ ((Window*)this)->mpWindowImpl->maHelpText = pHelp->GetHelpText( aStrHelpId, this );
+ else
+ ((Window*)this)->mpWindowImpl->maHelpText = pHelp->GetHelpText( nNumHelpId, this );
+ mpWindowImpl->mbHelpTextDynamic = FALSE;
+ }
+ }
+ }
+ else if( mpWindowImpl->mbHelpTextDynamic && (nNumHelpId || bStrHelpId) )
+ {
+ static const char* pEnv = getenv( "HELP_DEBUG" );
+ if( pEnv && *pEnv )
+ {
+ rtl::OUStringBuffer aTxt( 64+mpWindowImpl->maHelpText.Len() );
+ aTxt.append( mpWindowImpl->maHelpText );
+ aTxt.appendAscii( "\n------------------\n" );
+ if( bStrHelpId )
+ aTxt.append( rtl::OUString( aStrHelpId ) );
+ else
+ aTxt.append( sal_Int32( nNumHelpId ) );
+ mpWindowImpl->maHelpText = aTxt.makeStringAndClear();
+ }
+ mpWindowImpl->mbHelpTextDynamic = FALSE;
+ }
+
+ return mpWindowImpl->maHelpText;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::FindWindow( const Point& rPos ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Point aPos = OutputToScreenPixel( rPos );
+ return ((Window*)this)->ImplFindWindow( aPos );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Window::GetChildCount() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ USHORT nChildCount = 0;
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ nChildCount++;
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+
+ return nChildCount;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::GetChild( USHORT nChild ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ USHORT nChildCount = 0;
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ if ( nChild == nChildCount )
+ return pChild;
+ pChild = pChild->mpWindowImpl->mpNext;
+ nChildCount++;
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Window* Window::GetWindow( USHORT nType ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ switch ( nType )
+ {
+ case WINDOW_PARENT:
+ return mpWindowImpl->mpRealParent;
+
+ case WINDOW_FIRSTCHILD:
+ return mpWindowImpl->mpFirstChild;
+
+ case WINDOW_LASTCHILD:
+ return mpWindowImpl->mpLastChild;
+
+ case WINDOW_PREV:
+ return mpWindowImpl->mpPrev;
+
+ case WINDOW_NEXT:
+ return mpWindowImpl->mpNext;
+
+ case WINDOW_FIRSTOVERLAP:
+ return mpWindowImpl->mpFirstOverlap;
+
+ case WINDOW_LASTOVERLAP:
+ return mpWindowImpl->mpLastOverlap;
+
+ case WINDOW_OVERLAP:
+ if ( ImplIsOverlapWindow() )
+ return (Window*)this;
+ else
+ return mpWindowImpl->mpOverlapWindow;
+
+ case WINDOW_PARENTOVERLAP:
+ if ( ImplIsOverlapWindow() )
+ return mpWindowImpl->mpOverlapWindow;
+ else
+ return mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpOverlapWindow;
+
+ case WINDOW_CLIENT:
+ return ((Window*)this)->ImplGetWindow();
+
+ case WINDOW_REALPARENT:
+ return ImplGetParent();
+
+ case WINDOW_FRAME:
+ return mpWindowImpl->mpFrameWindow;
+
+ case WINDOW_BORDER:
+ if ( mpWindowImpl->mpBorderWindow )
+ return mpWindowImpl->mpBorderWindow->GetWindow( WINDOW_BORDER );
+ return (Window*)this;
+
+ case WINDOW_FIRSTTOPWINDOWCHILD:
+ return ImplGetWinData()->maTopWindowChildren.empty() ? NULL : *ImplGetWinData()->maTopWindowChildren.begin();
+
+ case WINDOW_LASTTOPWINDOWCHILD:
+ return ImplGetWinData()->maTopWindowChildren.empty() ? NULL : *ImplGetWinData()->maTopWindowChildren.rbegin();
+
+ case WINDOW_PREVTOPWINDOWSIBLING:
+ {
+ if ( !mpWindowImpl->mpRealParent )
+ return NULL;
+ const ::std::list< Window* >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
+ ::std::list< Window* >::const_iterator myPos =
+ ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
+ if ( myPos == rTopWindows.end() )
+ return NULL;
+ if ( myPos == rTopWindows.begin() )
+ return NULL;
+ return *--myPos;
+ }
+
+ case WINDOW_NEXTTOPWINDOWSIBLING:
+ {
+ if ( !mpWindowImpl->mpRealParent )
+ return NULL;
+ const ::std::list< Window* >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
+ ::std::list< Window* >::const_iterator myPos =
+ ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
+ if ( ( myPos == rTopWindows.end() ) || ( ++myPos == rTopWindows.end() ) )
+ return NULL;
+ return *myPos;
+ }
+
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsChild( const Window* pWindow, BOOL bSystemWindow ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ DBG_CHKOBJ( pWindow, Window, ImplDbgCheckWindow );
+
+ do
+ {
+ if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
+ break;
+
+ pWindow = pWindow->ImplGetParent();
+
+ if ( pWindow == this )
+ return TRUE;
+ }
+ while ( pWindow );
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsWindowOrChild( const Window* pWindow, BOOL bSystemWindow ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ DBG_CHKOBJ( pWindow, Window, ImplDbgCheckWindow );
+
+ if ( this == pWindow )
+ return TRUE;
+ return ImplIsChild( pWindow, bSystemWindow );
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* Window::GetSystemData() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ return mpWindowImpl->mpFrame ? mpWindowImpl->mpFrame->GetSystemData() : NULL;
+}
+
+::com::sun::star::uno::Any Window::GetSystemDataAny() const
+{
+ ::com::sun::star::uno::Any aRet;
+ const SystemEnvData* pSysData = GetSystemData();
+ if( pSysData )
+ {
+ ::com::sun::star::uno::Sequence< sal_Int8 > aSeq( (sal_Int8*)pSysData, pSysData->nSize );
+ aRet <<= aSeq;
+ }
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetWindowPeer( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xPeer, VCLXWindow* pVCLXWindow )
+{
+ // be safe against re-entrance: first clear the old ref, then assign the new one
+ // #133706# / 2006-03-30 / frank.schoenheit@sun.com
+ mpWindowImpl->mxWindowPeer.clear();
+ mpWindowImpl->mxWindowPeer = xPeer;
+
+ mpWindowImpl->mpVCLXWindow = pVCLXWindow;
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > Window::GetComponentInterface( BOOL bCreate )
+{
+ if ( !mpWindowImpl->mxWindowPeer.is() && bCreate )
+ {
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
+ if ( pWrapper )
+ mpWindowImpl->mxWindowPeer = pWrapper->GetWindowInterface( this, sal_True );
+ }
+ return mpWindowImpl->mxWindowPeer;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetComponentInterface( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xIFace )
+{
+ UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
+ DBG_ASSERT( pWrapper, "SetComponentInterface: No Wrapper!" );
+ if ( pWrapper )
+ pWrapper->SetWindowInterface( this, xIFace );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallDeactivateListeners( Window *pNew )
+{
+ // no deactivation if the the newly activated window is my child
+ if ( !pNew || !ImplIsChild( pNew ) )
+ {
+ ImplDelData aDogtag( this );
+ ImplCallEventListeners( VCLEVENT_WINDOW_DEACTIVATE );
+ if( aDogtag.IsDelete() )
+ return;
+
+ // #100759#, avoid walking the wrong frame's hierarchy
+ // eg, undocked docking windows (ImplDockFloatWin)
+ if ( ImplGetParent() && mpWindowImpl->mpFrameWindow == ImplGetParent()->mpWindowImpl->mpFrameWindow )
+ ImplGetParent()->ImplCallDeactivateListeners( pNew );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplCallActivateListeners( Window *pOld )
+{
+ // no activation if the the old active window is my child
+ if ( !pOld || !ImplIsChild( pOld ) )
+ {
+ ImplDelData aDogtag( this );
+ ImplCallEventListeners( VCLEVENT_WINDOW_ACTIVATE, pOld );
+ if( aDogtag.IsDelete() )
+ return;
+
+ // #106298# revoke the change for 105369, because this change
+ // disabled the activate event for the parent,
+ // if the parent is a compound control
+ //if( !GetParent() || !GetParent()->IsCompoundControl() )
+ //{
+ // #100759#, avoid walking the wrong frame's hierarchy
+ // eg, undocked docking windows (ImplDockFloatWin)
+ // #104714#, revert the changes for 100759 because it has a side effect when pOld is a dialog
+ // additionally the gallery is not dockable anymore, so 100759 canot occur
+ if ( ImplGetParent() ) /* && mpWindowImpl->mpFrameWindow == ImplGetParent()->mpWindowImpl->mpFrameWindow ) */
+ ImplGetParent()->ImplCallActivateListeners( pOld );
+ else if( (mpWindowImpl->mnStyle & WB_INTROWIN) == 0 )
+ {
+ // top level frame reached: store hint for DefModalDialogParent
+ ImplGetSVData()->maWinData.mpActiveApplicationFrame = mpWindowImpl->mpFrameWindow;
+ }
+ //}
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool Window::ImplStopDnd()
+{
+ bool bRet = false;
+ if( mpWindowImpl->mpFrameData && mpWindowImpl->mpFrameData->mxDropTargetListener.is() )
+ {
+ bRet = true;
+ mpWindowImpl->mpFrameData->mxDropTarget.clear();
+ mpWindowImpl->mpFrameData->mxDragSource.clear();
+ mpWindowImpl->mpFrameData->mxDropTargetListener.clear();
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplStartDnd()
+{
+ GetDropTarget();
+}
+
+// -----------------------------------------------------------------------
+
+Reference< XDropTarget > Window::GetDropTarget()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( ! mpWindowImpl->mxDNDListenerContainer.is() )
+ {
+ sal_Int8 nDefaultActions = 0;
+
+ if( mpWindowImpl->mpFrameData )
+ {
+ if( ! mpWindowImpl->mpFrameData->mxDropTarget.is() )
+ {
+ // initialization is done in GetDragSource
+ Reference< XDragSource > xDragSource = GetDragSource();
+ }
+
+ if( mpWindowImpl->mpFrameData->mxDropTarget.is() )
+ {
+ nDefaultActions = mpWindowImpl->mpFrameData->mxDropTarget->getDefaultActions();
+
+ if( ! mpWindowImpl->mpFrameData->mxDropTargetListener.is() )
+ {
+ mpWindowImpl->mpFrameData->mxDropTargetListener = new DNDEventDispatcher( mpWindowImpl->mpFrameWindow );
+
+ try
+ {
+ mpWindowImpl->mpFrameData->mxDropTarget->addDropTargetListener( mpWindowImpl->mpFrameData->mxDropTargetListener );
+
+ // register also as drag gesture listener if directly supported by drag source
+ Reference< XDragGestureRecognizer > xDragGestureRecognizer =
+ Reference< XDragGestureRecognizer > (mpWindowImpl->mpFrameData->mxDragSource, UNO_QUERY);
+
+ if( xDragGestureRecognizer.is() )
+ {
+ xDragGestureRecognizer->addDragGestureListener(
+ Reference< XDragGestureListener > (mpWindowImpl->mpFrameData->mxDropTargetListener, UNO_QUERY));
+ }
+ else
+ mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = TRUE;
+
+ }
+
+ catch( RuntimeException exc )
+ {
+ // release all instances
+ mpWindowImpl->mpFrameData->mxDropTarget.clear();
+ mpWindowImpl->mpFrameData->mxDragSource.clear();
+ }
+ }
+ }
+
+ }
+
+ mpWindowImpl->mxDNDListenerContainer = static_cast < XDropTarget * > ( new DNDListenerContainer( nDefaultActions ) );
+ }
+
+ // this object is located in the same process, so there will be no runtime exception
+ return Reference< XDropTarget > ( mpWindowImpl->mxDNDListenerContainer, UNO_QUERY );
+}
+
+// -----------------------------------------------------------------------
+
+Reference< XDragSource > Window::GetDragSource()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( mpWindowImpl->mpFrameData )
+ {
+ if( ! mpWindowImpl->mpFrameData->mxDragSource.is() )
+ {
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory = vcl::unohelper::GetMultiServiceFactory();
+ if ( xFactory.is() )
+ {
+ const SystemEnvData * pEnvData = GetSystemData();
+
+ if( pEnvData )
+ {
+ Sequence< Any > aDragSourceAL( 2 ), aDropTargetAL( 2 );
+ OUString aDragSourceSN, aDropTargetSN;
+#if defined WNT
+ aDragSourceSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDragSource" );
+ aDropTargetSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDropTarget" );
+ aDragSourceAL[ 1 ] = makeAny( (sal_uInt32) pEnvData->hWnd );
+ aDropTargetAL[ 0 ] = makeAny( (sal_uInt32) pEnvData->hWnd );
+#elif defined QUARTZ
+ /* FIXME: Mac OS X specific dnd interface does not exist! *
+ * Using Windows based dnd as a temporary solution */
+ aDragSourceSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDragSource" );
+ aDropTargetSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDropTarget" );
+ aDragSourceAL[ 1 ] = makeAny( static_cast<sal_uInt64>( reinterpret_cast<sal_IntPtr>(pEnvData->pView) ) );
+ aDropTargetAL[ 0 ] = makeAny( static_cast<sal_uInt64>( reinterpret_cast<sal_IntPtr>(pEnvData->pView) ) );
+#elif defined UNX
+ aDropTargetAL.realloc( 3 );
+ aDragSourceAL.realloc( 3 );
+ aDragSourceSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.X11DragSource" );
+ aDropTargetSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.X11DropTarget" );
+
+ aDragSourceAL[ 0 ] = makeAny( Application::GetDisplayConnection() );
+ aDragSourceAL[ 2 ] = makeAny( vcl::createBmpConverter() );
+ aDropTargetAL[ 0 ] = makeAny( Application::GetDisplayConnection() );
+ aDropTargetAL[ 1 ] = makeAny( (sal_Size)(pEnvData->aShellWindow) );
+ aDropTargetAL[ 2 ] = makeAny( vcl::createBmpConverter() );
+#endif
+ if( aDragSourceSN.getLength() )
+ mpWindowImpl->mpFrameData->mxDragSource = Reference< XDragSource > ( xFactory->createInstanceWithArguments( aDragSourceSN, aDragSourceAL ), UNO_QUERY );
+
+ if( aDropTargetSN.getLength() )
+ mpWindowImpl->mpFrameData->mxDropTarget = Reference< XDropTarget > ( xFactory->createInstanceWithArguments( aDropTargetSN, aDropTargetAL ), UNO_QUERY );
+ }
+ }
+ }
+
+ // createInstance can throw any exception
+ catch( Exception exc )
+ {
+ // release all instances
+ mpWindowImpl->mpFrameData->mxDropTarget.clear();
+ mpWindowImpl->mpFrameData->mxDragSource.clear();
+ }
+ }
+
+ return mpWindowImpl->mpFrameData->mxDragSource;
+ }
+
+ return Reference< XDragSource > ();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::GetDragSourceDropTarget(Reference< XDragSource >& xDragSource, Reference< XDropTarget > &xDropTarget )
+// only for RVP transmission
+{
+ if( mpWindowImpl->mpFrameData )
+ {
+ // initialization is done in GetDragSource
+ xDragSource = GetDragSource();
+ xDropTarget = mpWindowImpl->mpFrameData->mxDropTarget;
+ }
+ else
+ {
+ xDragSource.clear();
+ xDropTarget.clear();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Reference< XDragGestureRecognizer > Window::GetDragGestureRecognizer()
+{
+ return Reference< XDragGestureRecognizer > ( GetDropTarget(), UNO_QUERY );
+}
+
+// -----------------------------------------------------------------------
+
+Reference< XClipboard > Window::GetClipboard()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( mpWindowImpl->mpFrameData )
+ {
+ if( ! mpWindowImpl->mpFrameData->mxClipboard.is() )
+ {
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( vcl::unohelper::GetMultiServiceFactory() );
+
+ if( xFactory.is() )
+ {
+ mpWindowImpl->mpFrameData->mxClipboard = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.SystemClipboardExt" ) ), UNO_QUERY );
+
+ if( !mpWindowImpl->mpFrameData->mxClipboard.is() )
+ mpWindowImpl->mpFrameData->mxClipboard = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.SystemClipboard" ) ), UNO_QUERY );
+
+#if defined(UNX) && !defined(QUARTZ) // unix clipboard needs to be initialized
+ if( mpWindowImpl->mpFrameData->mxClipboard.is() )
+ {
+ Reference< XInitialization > xInit = Reference< XInitialization >( mpWindowImpl->mpFrameData->mxClipboard, UNO_QUERY );
+
+ if( xInit.is() )
+ {
+ Sequence< Any > aArgumentList( 3 );
+ aArgumentList[ 0 ] = makeAny( Application::GetDisplayConnection() );
+ aArgumentList[ 1 ] = makeAny( OUString::createFromAscii( "CLIPBOARD" ) );
+ aArgumentList[ 2 ] = makeAny( vcl::createBmpConverter() );
+
+ xInit->initialize( aArgumentList );
+ }
+ }
+#endif
+ }
+ }
+
+ // createInstance can throw any exception
+ catch( Exception exc )
+ {
+ // release all instances
+ mpWindowImpl->mpFrameData->mxClipboard.clear();
+ }
+ }
+
+ return mpWindowImpl->mpFrameData->mxClipboard;
+ }
+
+ return static_cast < XClipboard * > (0);
+}
+
+// -----------------------------------------------------------------------
+
+Reference< XClipboard > Window::GetPrimarySelection()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( mpWindowImpl->mpFrameData )
+ {
+ if( ! mpWindowImpl->mpFrameData->mxSelection.is() )
+ {
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( vcl::unohelper::GetMultiServiceFactory() );
+
+ if( xFactory.is() )
+ {
+#if defined(UNX) && !defined(QUARTZ)
+ Sequence< Any > aArgumentList( 3 );
+ aArgumentList[ 0 ] = makeAny( Application::GetDisplayConnection() );
+ aArgumentList[ 1 ] = makeAny( OUString::createFromAscii( "PRIMARY" ) );
+ aArgumentList[ 2 ] = makeAny( vcl::createBmpConverter() );
+
+ mpWindowImpl->mpFrameData->mxSelection = Reference< XClipboard >( xFactory->createInstanceWithArguments(
+ OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.SystemClipboard" ), aArgumentList ), UNO_QUERY );
+# else
+ static Reference< XClipboard > s_xSelection;
+
+ if ( !s_xSelection.is() )
+ s_xSelection = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.GenericClipboardExt" ) ), UNO_QUERY );
+
+ if ( !s_xSelection.is() )
+ s_xSelection = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.GenericClipboard" ) ), UNO_QUERY );
+
+ mpWindowImpl->mpFrameData->mxSelection = s_xSelection;
+# endif
+ }
+ }
+
+ // createInstance can throw any exception
+ catch( Exception exc )
+ {
+ // release all instances
+ mpWindowImpl->mpFrameData->mxSelection.clear();
+ }
+ }
+
+ return mpWindowImpl->mpFrameData->mxSelection;
+ }
+
+ return static_cast < XClipboard * > (0);
+}
+
+// -----------------------------------------------------------------------
+// Accessibility
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Window::GetAccessible( BOOL bCreate )
+{
+ // do not optimize hierarchy for the top level border win (ie, when there is no parent)
+ /* // do not optimize accessible hierarchy at all to better reflect real VCL hierarchy
+ if ( GetParent() && ( GetType() == WINDOW_BORDERWINDOW ) && ( GetChildCount() == 1 ) )
+ //if( !ImplIsAccessibleCandidate() )
+ {
+ Window* pChild = GetAccessibleChildWindow( 0 );
+ if ( pChild )
+ return pChild->GetAccessible();
+ }
+ */
+ if ( !mpWindowImpl->mxAccessible.is() && bCreate )
+ mpWindowImpl->mxAccessible = CreateAccessible();
+
+ return mpWindowImpl->mxAccessible;
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Window::CreateAccessible()
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc( GetComponentInterface( TRUE ), ::com::sun::star::uno::UNO_QUERY );
+ return xAcc;
+}
+
+void Window::SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > x )
+{
+ mpWindowImpl->mxAccessible = x;
+}
+
+// skip all border windows that are no top level frames
+BOOL Window::ImplIsAccessibleCandidate() const
+{
+ if( !mpWindowImpl->mbBorderWin )
+ return TRUE;
+ else
+ // #101741 do not check for WB_CLOSEABLE because undecorated floaters (like menues!) are closeable
+ if( mpWindowImpl->mbFrame && mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+BOOL Window::ImplIsAccessibleNativeFrame() const
+{
+ if( mpWindowImpl->mbFrame )
+ // #101741 do not check for WB_CLOSEABLE because undecorated floaters (like menues!) are closeable
+ if( (mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE)) )
+ return TRUE;
+ else
+ return FALSE;
+ else
+ return FALSE;
+}
+
+USHORT Window::ImplGetAccessibleCandidateChildWindowCount( USHORT nFirstWindowType ) const
+{
+ USHORT nChildren = 0;
+ Window* pChild = GetWindow( nFirstWindowType );
+ while ( pChild )
+ {
+ if( pChild->ImplIsAccessibleCandidate() )
+ nChildren++;
+ else
+ nChildren = sal::static_int_cast<USHORT>(nChildren + pChild->ImplGetAccessibleCandidateChildWindowCount( WINDOW_FIRSTCHILD ));
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ return nChildren;
+}
+
+Window* Window::ImplGetAccessibleCandidateChild( USHORT nChild, USHORT& rChildCount, USHORT nFirstWindowType, BOOL bTopLevel ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( bTopLevel )
+ rChildCount = 0;
+
+ Window* pChild = GetWindow( nFirstWindowType );
+ while ( pChild )
+ {
+ Window *pTmpChild = pChild;
+
+ if( !pChild->ImplIsAccessibleCandidate() )
+ pTmpChild = pChild->ImplGetAccessibleCandidateChild( nChild, rChildCount, WINDOW_FIRSTCHILD, FALSE );
+
+ if ( nChild == rChildCount )
+ return pTmpChild;
+ pChild = pChild->mpWindowImpl->mpNext;
+ rChildCount++;
+ }
+
+ return NULL;
+}
+
+/*
+Window* Window::GetAccessibleParentWindow() const
+{
+ Window* pParent = GetParent();
+ while ( pParent )
+ if( pParent->ImplIsAccessibleCandidate() )
+ break;
+ else
+ pParent = pParent->GetParent();
+ return pParent;
+}
+*/
+
+Window* Window::GetAccessibleParentWindow() const
+{
+ if ( ImplIsAccessibleNativeFrame() )
+ return NULL;
+
+ Window* pParent = mpWindowImpl->mpParent;
+ if( GetType() == WINDOW_MENUBARWINDOW )
+ {
+ // report the menubar as a child of THE workwindow
+ Window *pWorkWin = GetParent()->mpWindowImpl->mpFirstChild;
+ while( pWorkWin && (pWorkWin == this) )
+ pWorkWin = pWorkWin->mpWindowImpl->mpNext;
+ pParent = pWorkWin;
+ }
+ // If this a floating window which has a native boarder window, this one should be reported as
+ // accessible parent
+ else if( GetType() == WINDOW_FLOATINGWINDOW &&
+ mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame)
+ {
+ pParent = mpWindowImpl->mpBorderWindow;
+ }
+ else if( pParent && !pParent->ImplIsAccessibleCandidate() )
+ {
+ pParent = pParent->mpWindowImpl->mpParent;
+ }
+ return pParent;
+}
+
+/*
+USHORT Window::GetAccessibleChildWindowCount()
+{
+ USHORT nChildren = ImplGetAccessibleCandidateChildWindowCount( WINDOW_FIRSTCHILD );
+
+ // Search also for SystemWindows.
+ Window* pOverlap = GetWindow( WINDOW_OVERLAP );
+ nChildren += pOverlap->ImplGetAccessibleCandidateChildWindowCount( WINDOW_FIRSTOVERLAP );
+
+ return nChildren;
+}
+*/
+
+USHORT Window::GetAccessibleChildWindowCount()
+{
+ USHORT nChildren = 0;
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while( pChild )
+ {
+ if( pChild->IsVisible() )
+ nChildren++;
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+
+ // #107176# ignore overlapwindows
+ // this only affects non-system floating windows
+ // which are either not accessible (like the HelpAgent) or should be changed to system windows anyway
+ /*
+ if( ImplIsOverlapWindow() )
+ {
+ Window* pOverlap = GetWindow( WINDOW_FIRSTOVERLAP );
+ while ( pOverlap )
+ {
+ if( pOverlap->IsVisible() )
+ nChildren++;
+ pOverlap = pOverlap->GetWindow( WINDOW_NEXT );
+ }
+ }
+ */
+
+ // report the menubarwindow as a child of THE workwindow
+ if( GetType() == WINDOW_BORDERWINDOW )
+ {
+ if( ((ImplBorderWindow *) this)->mpMenuBarWindow &&
+ ((ImplBorderWindow *) this)->mpMenuBarWindow->IsVisible()
+ )
+ --nChildren;
+ }
+ else if( GetType() == WINDOW_WORKWINDOW )
+ {
+ if( ((WorkWindow *) this)->GetMenuBar() &&
+ ((WorkWindow *) this)->GetMenuBar()->GetWindow() &&
+ ((WorkWindow *) this)->GetMenuBar()->GetWindow()->IsVisible()
+ )
+ ++nChildren;
+ }
+
+ return nChildren;
+}
+
+/*
+Window* Window::GetAccessibleChildWindow( USHORT n )
+{
+ USHORT nChildCount; // will be set in ImplGetAccessibleCandidateChild(...)
+ Window* pChild = ImplGetAccessibleCandidateChild( n, nChildCount, WINDOW_FIRSTCHILD, TRUE );
+ if ( !pChild && ( n >= nChildCount ) )
+ {
+ Window* pOverlap = GetWindow( WINDOW_OVERLAP );
+ pChild = pOverlap->ImplGetAccessibleCandidateChild( n, nChildCount, WINDOW_FIRSTOVERLAP, FALSE );
+ }
+
+ return pChild;
+}
+*/
+
+Window* Window::GetAccessibleChildWindow( USHORT n )
+{
+ // report the menubarwindow as a the first child of THE workwindow
+ if( GetType() == WINDOW_WORKWINDOW && ((WorkWindow *) this)->GetMenuBar() )
+ {
+ if( n == 0 )
+ {
+ MenuBar *pMenuBar = ((WorkWindow *) this)->GetMenuBar();
+ if( pMenuBar->GetWindow() && pMenuBar->GetWindow()->IsVisible() )
+ return pMenuBar->GetWindow();
+ }
+ else
+ --n;
+ }
+
+ // transform n to child number including invisible children
+ USHORT nChildren = n;
+ Window* pChild = mpWindowImpl->mpFirstChild;
+ while( pChild )
+ {
+ if( pChild->IsVisible() )
+ {
+ if( ! nChildren )
+ break;
+ nChildren--;
+ }
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+
+ if( GetType() == WINDOW_BORDERWINDOW && pChild && pChild->GetType() == WINDOW_MENUBARWINDOW )
+ {
+ do pChild = pChild->mpWindowImpl->mpNext; while( pChild && ! pChild->IsVisible() );
+ DBG_ASSERT( pChild, "GetAccessibleChildWindow(): wrong index in border window");
+ }
+ if ( !pChild )
+ {
+ // #107176# ignore overlapwindows
+ /*
+ if( ImplIsOverlapWindow() )
+ {
+ Window* pOverlap = GetWindow( WINDOW_FIRSTOVERLAP );
+ while ( !pChild && pOverlap )
+ {
+ if ( !nChildren && pOverlap->IsVisible() )
+ {
+ pChild = pOverlap;
+ break;
+ }
+ pOverlap = pOverlap->GetWindow( WINDOW_NEXT );
+ if( pOverlap && pOverlap->IsVisible() )
+ nChildren--;
+ }
+ }
+ */
+
+ }
+ if ( pChild && ( pChild->GetType() == WINDOW_BORDERWINDOW ) && ( pChild->GetChildCount() == 1 ) )
+ {
+ pChild = pChild->GetChild( 0 );
+ }
+ return pChild;
+}
+
+
+void Window::SetAccessibleRole( USHORT nRole )
+{
+ if ( !mpWindowImpl->mpAccessibleInfos )
+ mpWindowImpl->mpAccessibleInfos = new ImplAccessibleInfos;
+
+ DBG_ASSERT( mpWindowImpl->mpAccessibleInfos->nAccessibleRole == 0xFFFF, "AccessibleRole already set!" );
+ mpWindowImpl->mpAccessibleInfos->nAccessibleRole = nRole;
+}
+
+USHORT Window::GetAccessibleRole() const
+{
+ using namespace ::com::sun::star;
+
+ USHORT nRole = mpWindowImpl->mpAccessibleInfos ? mpWindowImpl->mpAccessibleInfos->nAccessibleRole : 0xFFFF;
+ if ( nRole == 0xFFFF )
+ {
+ switch ( GetType() )
+ {
+ case WINDOW_MESSBOX: // MT: Would be nice to have special roles!
+ case WINDOW_INFOBOX:
+ case WINDOW_WARNINGBOX:
+ case WINDOW_ERRORBOX:
+ case WINDOW_QUERYBOX: nRole = accessibility::AccessibleRole::ALERT; break;
+
+ case WINDOW_MODELESSDIALOG:
+ case WINDOW_MODALDIALOG:
+ case WINDOW_SYSTEMDIALOG:
+ case WINDOW_PRINTERSETUPDIALOG:
+ case WINDOW_PRINTDIALOG:
+ case WINDOW_TABDIALOG:
+ case WINDOW_BUTTONDIALOG:
+ case WINDOW_DIALOG: nRole = accessibility::AccessibleRole::DIALOG; break;
+
+ case WINDOW_PUSHBUTTON:
+ case WINDOW_OKBUTTON:
+ case WINDOW_CANCELBUTTON:
+ case WINDOW_HELPBUTTON:
+ case WINDOW_IMAGEBUTTON:
+ case WINDOW_MENUBUTTON:
+ case WINDOW_MOREBUTTON:
+ case WINDOW_SPINBUTTON:
+ case WINDOW_BUTTON: nRole = accessibility::AccessibleRole::PUSH_BUTTON; break;
+
+ case WINDOW_PATHDIALOG: nRole = accessibility::AccessibleRole::DIRECTORY_PANE; break;
+ case WINDOW_FILEDIALOG: nRole = accessibility::AccessibleRole::FILE_CHOOSER; break;
+ case WINDOW_COLORDIALOG: nRole = accessibility::AccessibleRole::COLOR_CHOOSER; break;
+ case WINDOW_FONTDIALOG: nRole = accessibility::AccessibleRole::FONT_CHOOSER; break;
+
+ case WINDOW_IMAGERADIOBUTTON:
+ case WINDOW_RADIOBUTTON: nRole = accessibility::AccessibleRole::RADIO_BUTTON; break;
+ case WINDOW_TRISTATEBOX:
+ case WINDOW_CHECKBOX: nRole = accessibility::AccessibleRole::CHECK_BOX; break;
+
+ case WINDOW_MULTILINEEDIT: nRole = accessibility::AccessibleRole::SCROLL_PANE; break;
+
+ case WINDOW_PATTERNFIELD:
+ case WINDOW_NUMERICFIELD:
+ case WINDOW_METRICFIELD:
+ case WINDOW_CURRENCYFIELD:
+ case WINDOW_LONGCURRENCYFIELD:
+ case WINDOW_EDIT: nRole = ( GetStyle() & WB_PASSWORD ) ? (accessibility::AccessibleRole::PASSWORD_TEXT) : (accessibility::AccessibleRole::TEXT); break;
+
+ case WINDOW_PATTERNBOX:
+ case WINDOW_NUMERICBOX:
+ case WINDOW_METRICBOX:
+ case WINDOW_CURRENCYBOX:
+ case WINDOW_LONGCURRENCYBOX:
+ case WINDOW_COMBOBOX: nRole = accessibility::AccessibleRole::COMBO_BOX; break;
+
+ case WINDOW_LISTBOX:
+ case WINDOW_MULTILISTBOX: nRole = accessibility::AccessibleRole::LIST; break;
+
+ case WINDOW_TREELISTBOX: nRole = accessibility::AccessibleRole::TREE; break;
+
+ case WINDOW_FIXEDTEXT: nRole = accessibility::AccessibleRole::LABEL; break;
+ case WINDOW_FIXEDBORDER:
+ case WINDOW_FIXEDLINE: nRole = accessibility::AccessibleRole::SEPARATOR; break;
+ case WINDOW_FIXEDBITMAP:
+ case WINDOW_FIXEDIMAGE: nRole = accessibility::AccessibleRole::ICON; break;
+ case WINDOW_GROUPBOX: nRole = accessibility::AccessibleRole::GROUP_BOX; break;
+ case WINDOW_SCROLLBAR: nRole = accessibility::AccessibleRole::SCROLL_BAR; break;
+
+ case WINDOW_SLIDER:
+ case WINDOW_SPLITTER:
+ case WINDOW_SPLITWINDOW: nRole = accessibility::AccessibleRole::SPLIT_PANE; break;
+
+ case WINDOW_DATEBOX:
+ case WINDOW_TIMEBOX:
+ case WINDOW_DATEFIELD:
+ case WINDOW_TIMEFIELD: nRole = accessibility::AccessibleRole::DATE_EDITOR; break;
+
+ case WINDOW_SPINFIELD: nRole = accessibility::AccessibleRole::SPIN_BOX; break;
+
+ case WINDOW_TOOLBOX: nRole = accessibility::AccessibleRole::TOOL_BAR; break;
+ case WINDOW_STATUSBAR: nRole = accessibility::AccessibleRole::STATUS_BAR; break;
+
+ case WINDOW_TABPAGE: nRole = accessibility::AccessibleRole::PANEL; break;
+ case WINDOW_TABCONTROL: nRole = accessibility::AccessibleRole::PAGE_TAB_LIST; break;
+
+ case WINDOW_DOCKINGWINDOW:
+ case WINDOW_SYSWINDOW: nRole = (mpWindowImpl->mbFrame) ? accessibility::AccessibleRole::FRAME :
+ accessibility::AccessibleRole::PANEL; break;
+
+ case WINDOW_FLOATINGWINDOW: nRole = ( mpWindowImpl->mbFrame ||
+ (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) ||
+ (GetStyle() & WB_OWNERDRAWDECORATION) ) ? accessibility::AccessibleRole::FRAME :
+ accessibility::AccessibleRole::WINDOW; break;
+
+ case WINDOW_WORKWINDOW: nRole = accessibility::AccessibleRole::ROOT_PANE; break;
+
+
+ case WINDOW_SCROLLBARBOX: nRole = accessibility::AccessibleRole::FILLER; break;
+
+ case WINDOW_HELPTEXTWINDOW: nRole = accessibility::AccessibleRole::TOOL_TIP; break;
+
+ case WINDOW_WINDOW:
+ case WINDOW_CONTROL:
+ case WINDOW_BORDERWINDOW:
+ case WINDOW_SYSTEMCHILDWINDOW:
+ default:
+ if (ImplIsAccessibleNativeFrame() )
+ nRole = accessibility::AccessibleRole::FRAME;
+ else if( IsScrollable() )
+ nRole = accessibility::AccessibleRole::SCROLL_PANE;
+ else if( ((Window*)this)->ImplGetWindow()->IsMenuFloatingWindow() )
+ nRole = accessibility::AccessibleRole::WINDOW; // #106002#, contextmenues are windows (i.e. toplevel)
+ else
+ // #104051# WINDOW seems to be a bad default role, use LAYEREDPANE instead
+ // a WINDOW is interpreted as a top-level window, which is typically not the case
+ //nRole = accessibility::AccessibleRole::WINDOW;
+ nRole = accessibility::AccessibleRole::PANEL;
+ }
+ }
+ return nRole;
+}
+
+void Window::SetAccessibleName( const String& rName )
+{
+ if ( !mpWindowImpl->mpAccessibleInfos )
+ mpWindowImpl->mpAccessibleInfos = new ImplAccessibleInfos;
+
+ DBG_ASSERT( !mpWindowImpl->mpAccessibleInfos->pAccessibleName, "AccessibleName already set!" );
+ delete mpWindowImpl->mpAccessibleInfos->pAccessibleName;
+ mpWindowImpl->mpAccessibleInfos->pAccessibleName = new String( rName );
+}
+
+String Window::GetAccessibleName() const
+{
+ String aAccessibleName;
+ if ( mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleName )
+ {
+ aAccessibleName = *mpWindowImpl->mpAccessibleInfos->pAccessibleName;
+ }
+ else
+ {
+ switch ( GetType() )
+ {
+// case WINDOW_IMAGERADIOBUTTON:
+// case WINDOW_RADIOBUTTON:
+// case WINDOW_TRISTATEBOX:
+// case WINDOW_CHECKBOX:
+
+ case WINDOW_MULTILINEEDIT:
+ case WINDOW_PATTERNFIELD:
+ case WINDOW_NUMERICFIELD:
+ case WINDOW_METRICFIELD:
+ case WINDOW_CURRENCYFIELD:
+ case WINDOW_LONGCURRENCYFIELD:
+ case WINDOW_EDIT:
+
+ case WINDOW_DATEBOX:
+ case WINDOW_TIMEBOX:
+ case WINDOW_CURRENCYBOX:
+ case WINDOW_LONGCURRENCYBOX:
+ case WINDOW_DATEFIELD:
+ case WINDOW_TIMEFIELD:
+ case WINDOW_SPINFIELD:
+
+ case WINDOW_COMBOBOX:
+ case WINDOW_LISTBOX:
+ case WINDOW_MULTILISTBOX:
+ case WINDOW_TREELISTBOX:
+
+ {
+ Window *pLabel = GetLabeledBy();
+ if ( pLabel && pLabel != this )
+ aAccessibleName = pLabel->GetText();
+ }
+ break;
+
+ case WINDOW_IMAGEBUTTON:
+ case WINDOW_PUSHBUTTON:
+ aAccessibleName = GetText();
+ if ( !aAccessibleName.Len() )
+ {
+ aAccessibleName = GetQuickHelpText();
+ if ( !aAccessibleName.Len() )
+ aAccessibleName = GetHelpText();
+ }
+ break;
+
+ default:
+ aAccessibleName = GetText();
+ break;
+ }
+
+ aAccessibleName = GetNonMnemonicString( aAccessibleName );
+ }
+
+ return aAccessibleName;
+}
+
+void Window::SetAccessibleDescription( const String& rDescription )
+{
+ if ( ! mpWindowImpl->mpAccessibleInfos )
+ mpWindowImpl->mpAccessibleInfos = new ImplAccessibleInfos;
+
+ DBG_ASSERT( !mpWindowImpl->mpAccessibleInfos->pAccessibleDescription, "AccessibleDescription already set!" );
+ delete mpWindowImpl->mpAccessibleInfos->pAccessibleDescription;
+ mpWindowImpl->mpAccessibleInfos->pAccessibleDescription = new String( rDescription );
+}
+
+String Window::GetAccessibleDescription() const
+{
+ String aAccessibleDescription;
+ if ( mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleDescription )
+ {
+ aAccessibleDescription = *mpWindowImpl->mpAccessibleInfos->pAccessibleDescription;
+ }
+ else
+ {
+ // Special code for help text windows. ZT asks the border window for the
+ // description so we have to forward this request to our inner window.
+ const Window* pWin = ((Window *)this)->ImplGetWindow();
+ if ( pWin->GetType() == WINDOW_HELPTEXTWINDOW )
+ aAccessibleDescription = pWin->GetHelpText();
+ else
+ aAccessibleDescription = GetHelpText();
+ }
+
+ return aAccessibleDescription;
+}
+
+BOOL Window::IsAccessibilityEventsSuppressed( BOOL bTraverseParentPath )
+{
+ if( !bTraverseParentPath )
+ return mpWindowImpl->mbSuppressAccessibilityEvents;
+ else
+ {
+ Window *pParent = this;
+ while ( pParent && pParent->mpWindowImpl)
+ {
+ if( pParent->mpWindowImpl->mbSuppressAccessibilityEvents )
+ return TRUE;
+ else
+ pParent = pParent->mpWindowImpl->mpParent; // do not use GetParent() to find borderwindows that are frames
+ }
+ return FALSE;
+ }
+}
+
+void Window::RecordLayoutData( vcl::ControlLayoutData* pLayout, const Rectangle& rRect )
+{
+ if( ! mpOutDevData )
+ ImplInitOutDevData();
+ mpOutDevData->mpRecordLayout = pLayout;
+ mpOutDevData->maRecordRect = rRect;
+ Paint( rRect );
+ mpOutDevData->mpRecordLayout = NULL;
+}
+
+// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+
+
+// returns background color used in this control
+// false: could not determine color
+BOOL Window::ImplGetCurrentBackgroundColor( Color& rCol )
+{
+ BOOL bRet = TRUE;
+
+ switch ( GetType() )
+ {
+ // peform special handling here
+ case WINDOW_PUSHBUTTON:
+ case WINDOW_OKBUTTON:
+ case WINDOW_CANCELBUTTON:
+ // etc.
+ default:
+ if( IsControlBackground() )
+ rCol = GetControlBackground();
+ else if( IsBackground() )
+ {
+ Wallpaper aWall = GetBackground();
+ if( !aWall.IsGradient() && !aWall.IsBitmap() )
+ rCol = aWall.GetColor();
+ else
+ bRet = FALSE;
+ }
+ else
+ rCol = GetSettings().GetStyleSettings().GetFaceColor();
+ break;
+ }
+ return bRet;
+}
+
+void Window::DrawSelectionBackground( const Rectangle& rRect, USHORT highlight, BOOL bChecked, BOOL bDrawBorder, BOOL bDrawExtBorderOnly )
+{
+ DrawSelectionBackground( rRect, highlight, bChecked, bDrawBorder, bDrawExtBorderOnly, 0, NULL, NULL );
+}
+
+void Window::DrawSelectionBackground( const Rectangle& rRect, USHORT highlight, BOOL bChecked, BOOL bDrawBorder, BOOL bDrawExtBorderOnly, Color* pSelectionTextColor )
+{
+ DrawSelectionBackground( rRect, highlight, bChecked, bDrawBorder, bDrawExtBorderOnly, 0, pSelectionTextColor, NULL );
+}
+
+void Window::DrawSelectionBackground( const Rectangle& rRect,
+ USHORT highlight,
+ BOOL bChecked,
+ BOOL bDrawBorder,
+ BOOL bDrawExtBorderOnly,
+ long nCornerRadius,
+ Color* pSelectionTextColor,
+ Color* pPaintColor
+ )
+{
+ if( rRect.IsEmpty() )
+ return;
+
+ bool bRoundEdges = nCornerRadius > 0;
+
+ const StyleSettings& rStyles = GetSettings().GetStyleSettings();
+
+
+ // colors used for item highlighting
+ Color aSelectionBorderCol( pPaintColor ? *pPaintColor : rStyles.GetHighlightColor() );
+ Color aSelectionFillCol( aSelectionBorderCol );
+
+ BOOL bDark = rStyles.GetFaceColor().IsDark();
+ BOOL bBright = ( rStyles.GetFaceColor() == Color( COL_WHITE ) );
+
+ int c1 = aSelectionBorderCol.GetLuminance();
+ int c2 = GetDisplayBackground().GetColor().GetLuminance();
+
+ if( !bDark && !bBright && abs( c2-c1 ) < (pPaintColor ? 40 : 75) )
+ {
+ // constrast too low
+ USHORT h,s,b;
+ aSelectionFillCol.RGBtoHSB( h, s, b );
+ if( b > 50 ) b -= 40;
+ else b += 40;
+ aSelectionFillCol.SetColor( Color::HSBtoRGB( h, s, b ) );
+ aSelectionBorderCol = aSelectionFillCol;
+ }
+
+ if( bRoundEdges )
+ {
+ if( aSelectionBorderCol.IsDark() )
+ aSelectionBorderCol.IncreaseLuminance( 128 );
+ else
+ aSelectionBorderCol.DecreaseLuminance( 128 );
+ }
+
+ Rectangle aRect( rRect );
+ if( bDrawExtBorderOnly )
+ {
+ aRect.nLeft -= 1;
+ aRect.nTop -= 1;
+ aRect.nRight += 1;
+ aRect.nBottom += 1;
+ }
+ Color oldFillCol = GetFillColor();
+ Color oldLineCol = GetLineColor();
+
+ if( bDrawBorder )
+ SetLineColor( bDark ? Color(COL_WHITE) : ( bBright ? Color(COL_BLACK) : aSelectionBorderCol ) );
+ else
+ SetLineColor();
+
+ USHORT nPercent = 0;
+ if( !highlight )
+ {
+ if( bDark )
+ aSelectionFillCol = COL_BLACK;
+ else
+ nPercent = bRoundEdges ? 90 : 80; // just checked (light)
+ }
+ else
+ {
+ if( bChecked && highlight == 2 )
+ {
+ if( bDark )
+ aSelectionFillCol = COL_LIGHTGRAY;
+ else if ( bBright )
+ {
+ aSelectionFillCol = COL_BLACK;
+ SetLineColor( COL_BLACK );
+ nPercent = 0;
+ }
+ else
+ nPercent = bRoundEdges ? 50 : 20; // selected, pressed or checked ( very dark )
+ }
+ else if( bChecked || highlight == 1 )
+ {
+ if( bDark )
+ aSelectionFillCol = COL_GRAY;
+ else if ( bBright )
+ {
+ aSelectionFillCol = COL_BLACK;
+ SetLineColor( COL_BLACK );
+ nPercent = 0;
+ }
+ else
+ nPercent = bRoundEdges ? 70 : 35; // selected, pressed or checked ( very dark )
+ }
+ else
+ {
+ if( bDark )
+ aSelectionFillCol = COL_LIGHTGRAY;
+ else if ( bBright )
+ {
+ aSelectionFillCol = COL_BLACK;
+ SetLineColor( COL_BLACK );
+ if( highlight == 3 )
+ nPercent = 80;
+ else
+ nPercent = 0;
+ }
+ else
+ nPercent = bRoundEdges ? 80 : 70; // selected ( dark )
+ }
+ }
+
+ if( bDark && bDrawExtBorderOnly )
+ {
+ SetFillColor();
+ if( pSelectionTextColor )
+ *pSelectionTextColor = rStyles.GetHighlightTextColor();
+ }
+ else
+ {
+ SetFillColor( aSelectionFillCol );
+ if( pSelectionTextColor )
+ {
+ Color aTextColor = IsControlBackground() ? GetControlForeground() : rStyles.GetButtonTextColor();
+ Color aHLTextColor = rStyles.GetHighlightTextColor();
+ int nTextDiff = abs(aSelectionFillCol.GetLuminance() - aTextColor.GetLuminance());
+ int nHLDiff = abs(aSelectionFillCol.GetLuminance() - aHLTextColor.GetLuminance());
+ *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor;
+ }
+ }
+
+
+ if( bDark )
+ {
+ DrawRect( aRect );
+ }
+ else
+ {
+ if( bRoundEdges )
+ {
+ Polygon aPoly( aRect, nCornerRadius, nCornerRadius );
+ PolyPolygon aPolyPoly( aPoly );
+ DrawTransparent( aPolyPoly, nPercent );
+ }
+ else
+ {
+ Polygon aPoly( aRect );
+ PolyPolygon aPolyPoly( aPoly );
+ DrawTransparent( aPolyPoly, nPercent );
+ }
+ }
+
+ SetFillColor( oldFillCol );
+ SetLineColor( oldLineCol );
+}
+
+/*
+void Window::DbgAssertNoEventListeners()
+{
+ VclWindowEvent aEvent( this, 0, NULL );
+ DBG_ASSERT( mpWindowImpl->maEventListeners.empty(), "Eventlistener: Who is still listening???" )
+ if ( !mpWindowImpl->maEventListeners.empty() )
+ mpWindowImpl->maEventListeners.Call( &aEvent );
+
+ DBG_ASSERT( mpWindowImpl->maChildEventListeners.empty(), "ChildEventlistener: Who is still listening???" )
+ if ( !mpWindowImpl->maChildEventListeners.empty() )
+ mpWindowImpl->maChildEventListeners.Call( &aEvent );
+}
+*/
+
+// controls should return the window that gets the
+// focus by default, so keyevents can be sent to that window directly
+Window* Window::GetPreferredKeyInputWindow()
+{
+ return this;
+}
+
+
+BOOL Window::IsScrollable() const
+{
+ // check for scrollbars
+ Window *pChild = mpWindowImpl->mpFirstChild;
+ while( pChild )
+ {
+ if( pChild->GetType() == WINDOW_SCROLLBAR )
+ return true;
+ else
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+ return false;
+}
+
+BOOL Window::IsTopWindow() const
+{
+ if ( mpWindowImpl->mbInDtor )
+ return FALSE;
+
+ // topwindows must be frames or they must have a borderwindow which is a frame
+ if( !mpWindowImpl->mbFrame && (!mpWindowImpl->mpBorderWindow || (mpWindowImpl->mpBorderWindow && !mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) ) )
+ return FALSE;
+
+ ImplGetWinData();
+ if( mpWindowImpl->mpWinData->mnIsTopWindow == (USHORT)~0) // still uninitialized
+ {
+ // #113722#, cache result of expensive queryInterface call
+ Window *pThisWin = (Window*)this;
+ Reference< XTopWindow > xTopWindow( pThisWin->GetComponentInterface(), UNO_QUERY );
+ pThisWin->mpWindowImpl->mpWinData->mnIsTopWindow = xTopWindow.is() ? 1 : 0;
+ }
+ return mpWindowImpl->mpWinData->mnIsTopWindow == 1 ? TRUE : FALSE;
+}
+
+void Window::ImplMirrorFramePos( Point &pt ) const
+{
+ pt.X() = mpWindowImpl->mpFrame->maGeometry.nWidth-1-pt.X();
+}
+
+// frame based modal counter (dialogs are not modal to the whole application anymore)
+BOOL Window::IsInModalMode() const
+{
+ return (mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrameData->mnModalMode != 0);
+}
+void Window::ImplIncModalCount()
+{
+ Window* pFrameWindow = mpWindowImpl->mpFrameWindow;
+ Window* pParent = pFrameWindow;
+ while( pFrameWindow )
+ {
+ pFrameWindow->mpWindowImpl->mpFrameData->mnModalMode++;
+ while( pParent && pParent->mpWindowImpl->mpFrameWindow == pFrameWindow )
+ {
+ pParent = pParent->GetParent();
+ }
+ pFrameWindow = pParent ? pParent->mpWindowImpl->mpFrameWindow : NULL;
+ }
+}
+void Window::ImplDecModalCount()
+{
+ Window* pFrameWindow = mpWindowImpl->mpFrameWindow;
+ Window* pParent = pFrameWindow;
+ while( pFrameWindow )
+ {
+ pFrameWindow->mpWindowImpl->mpFrameData->mnModalMode--;
+ while( pParent && pParent->mpWindowImpl->mpFrameWindow == pFrameWindow )
+ {
+ pParent = pParent->GetParent();
+ }
+ pFrameWindow = pParent ? pParent->mpWindowImpl->mpFrameWindow : NULL;
+ }
+}
+BOOL Window::ImplIsInTaskPaneList()
+{
+ return mpWindowImpl->mbIsInTaskPaneList;
+}
+void Window::ImplIsInTaskPaneList( BOOL mbIsInTaskList )
+{
+ mpWindowImpl->mbIsInTaskPaneList = mbIsInTaskList;
+}
+
+void Window::ImplNotifyIconifiedState( BOOL bIconified )
+{
+ mpWindowImpl->mpFrameWindow->ImplCallEventListeners( bIconified ? VCLEVENT_WINDOW_MINIMIZE : VCLEVENT_WINDOW_NORMALIZE );
+ // #109206# notify client window as well to have toolkit topwindow listeners notified
+ if( mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow && mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow )
+ mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow->ImplCallEventListeners( bIconified ? VCLEVENT_WINDOW_MINIMIZE : VCLEVENT_WINDOW_NORMALIZE );
+}
+
+BOOL Window::HasActiveChildFrame()
+{
+ BOOL bRet = FALSE;
+ Window *pFrameWin = ImplGetSVData()->maWinData.mpFirstFrame;
+ while( pFrameWin )
+ {
+ if( pFrameWin != mpWindowImpl->mpFrameWindow )
+ {
+ BOOL bDecorated = FALSE;
+ Window *pChildFrame = pFrameWin->ImplGetWindow();
+ // #i15285# unfortunately WB_MOVEABLE is the same as WB_TABSTOP which can
+ // be removed for ToolBoxes to influence the keyboard accessibility
+ // thus WB_MOVEABLE is no indicator for decoration anymore
+ // but FloatingWindows carry this information in their TitleType...
+ // TODO: avoid duplicate WinBits !!!
+ if( pChildFrame && pChildFrame->ImplIsFloatingWindow() )
+ bDecorated = ((FloatingWindow*) pChildFrame)->GetTitleType() != FLOATWIN_TITLE_NONE;
+ if( bDecorated || (pFrameWin->mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE) ) )
+ if( pChildFrame && pChildFrame->IsVisible() && pChildFrame->IsActive() )
+ {
+ if( ImplIsChild( pChildFrame, TRUE ) )
+ {
+ bRet = TRUE;
+ break;
+ }
+ }
+ }
+ pFrameWin = pFrameWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ return bRet;
+}
+
+LanguageType Window::GetInputLanguage() const
+{
+ return mpWindowImpl->mpFrame->GetInputLanguage();
+}
+
+void Window::EnableNativeWidget( BOOL bEnable )
+{
+ static const char* pNoNWF = getenv( "SAL_NO_NWF" );
+ if( pNoNWF && *pNoNWF )
+ bEnable = FALSE;
+
+ if( bEnable != ImplGetWinData()->mbEnableNativeWidget )
+ {
+ ImplGetWinData()->mbEnableNativeWidget = bEnable;
+
+ // send datachanged event to allow for internal changes required for NWF
+ // like clipmode, transparency, etc.
+ DataChangedEvent aDCEvt( DATACHANGED_SETTINGS, &maSettings, SETTINGS_STYLE );
+ DataChanged( aDCEvt );
+
+ // sometimes the borderwindow is queried, so keep it in sync
+ if( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->ImplGetWinData()->mbEnableNativeWidget = bEnable;
+ }
+
+ // push down, useful for compound controls
+ Window *pChild = mpWindowImpl->mpFirstChild;
+ while( pChild )
+ {
+ pChild->EnableNativeWidget( bEnable );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+
+BOOL Window::IsNativeWidgetEnabled() const
+{
+ return ImplGetWinData()->mbEnableNativeWidget;
+}
+
+#ifdef WNT // see #140456#
+#include <salframe.h>
+#endif
+
+Reference< rendering::XCanvas > Window::ImplGetCanvas( const Size& rFullscreenSize,
+ bool bFullscreen,
+ bool bSpriteCanvas ) const
+{
+ // try to retrieve hard reference from weak member
+ Reference< rendering::XCanvas > xCanvas( mpWindowImpl->mxCanvas );
+
+ // canvas still valid? Then we're done.
+ if( xCanvas.is() )
+ return xCanvas;
+
+ Sequence< Any > aArg(6);
+
+ // Feed any with operating system's window handle
+ // ==============================================
+
+ // common: first any is VCL pointer to window (for VCL canvas)
+ aArg[ 0 ] = makeAny( reinterpret_cast<sal_Int64>(this) );
+
+ // TODO(Q1): Make GetSystemData method virtual
+
+ // check whether we're a SysChild: have to fetch system data
+ // directly from SystemChildWindow, because the GetSystemData
+ // method is unfortunately not virtual
+ const SystemChildWindow* pSysChild = dynamic_cast< const SystemChildWindow* >( this );
+ if( pSysChild )
+ {
+ aArg[ 1 ] = pSysChild->GetSystemDataAny();
+ aArg[ 5 ] = pSysChild->GetSystemGfxDataAny();
+ }
+ else
+ {
+ aArg[ 1 ] = GetSystemDataAny();
+ aArg[ 5 ] = GetSystemGfxDataAny();
+ }
+
+ if( bFullscreen )
+ aArg[ 2 ] = makeAny( ::com::sun::star::awt::Rectangle( 0, 0,
+ rFullscreenSize.Width(),
+ rFullscreenSize.Height() ) );
+ else
+ aArg[ 2 ] = makeAny( ::com::sun::star::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ) );
+
+ aArg[ 3 ] = makeAny( mpWindowImpl->mbAlwaysOnTop ? sal_True : sal_False );
+ aArg[ 4 ] = makeAny( Reference< awt::XWindow >(
+ const_cast<Window*>(this)->GetComponentInterface(),
+ uno::UNO_QUERY ));
+
+ Reference< XMultiServiceFactory > xFactory = vcl::unohelper::GetMultiServiceFactory();
+
+ // Create canvas instance with window handle
+ // =========================================
+ if ( xFactory.is() )
+ {
+ static Reference<lang::XMultiServiceFactory> xCanvasFactory(
+ xFactory->createInstance(
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star."
+ "rendering.CanvasFactory") ) ), UNO_QUERY );
+ if(xCanvasFactory.is())
+ {
+#ifdef WNT
+ // see #140456# - if we're running on a multiscreen setup,
+ // request special, multi-screen safe sprite canvas
+ // implementation (not DX5 canvas, as it cannot cope with
+ // surfaces spanning multiple displays). Note: canvas
+ // (without sprite) stays the same)
+ const sal_uInt32 nDisplay = static_cast< WinSalFrame* >( mpWindowImpl->mpFrame )->mnDisplay;
+ if( (nDisplay >= Application::GetScreenCount()) )
+ {
+ xCanvas.set( xCanvasFactory->createInstanceWithArguments(
+ bSpriteCanvas ?
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.rendering.SpriteCanvas.MultiScreen" )) :
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.rendering.Canvas" )),
+ aArg ),
+ UNO_QUERY );
+
+ }
+ else
+ {
+#endif
+ xCanvas.set( xCanvasFactory->createInstanceWithArguments(
+ bSpriteCanvas ?
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.rendering.SpriteCanvas" )) :
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.rendering.Canvas" )),
+ aArg ),
+ UNO_QUERY );
+
+#ifdef WNT
+ }
+#endif
+
+ mpWindowImpl->mxCanvas = xCanvas;
+ }
+ }
+
+ // no factory??? Empty reference, then.
+ return xCanvas;
+}
+
+Reference< rendering::XCanvas > Window::GetCanvas() const
+{
+ return ImplGetCanvas( Size(), false, false );
+}
+
+Reference< rendering::XSpriteCanvas > Window::GetSpriteCanvas() const
+{
+ Reference< rendering::XSpriteCanvas > xSpriteCanvas(
+ ImplGetCanvas( Size(), false, true ), uno::UNO_QUERY );
+ return xSpriteCanvas;
+}
+
+Reference< ::com::sun::star::rendering::XSpriteCanvas > Window::GetFullscreenSpriteCanvas( const Size& rFullscreenSize ) const
+{
+ Reference< rendering::XSpriteCanvas > xSpriteCanvas(
+ ImplGetCanvas( rFullscreenSize, true, true ), uno::UNO_QUERY );
+ return xSpriteCanvas;
+}
+
+void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
+{
+ BOOL bRVisible = mpWindowImpl->mbReallyVisible;
+ mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
+ BOOL bDevOutput = mbDevOutput;
+ mbDevOutput = TRUE;
+
+ long nOldDPIX = ImplGetDPIX();
+ long nOldDPIY = ImplGetDPIY();
+ mnDPIX = i_pTargetOutDev->ImplGetDPIX();
+ mnDPIY = i_pTargetOutDev->ImplGetDPIY();
+ BOOL bOutput = IsOutputEnabled();
+ EnableOutput();
+
+ DBG_ASSERT( GetMapMode().GetMapUnit() == MAP_PIXEL, "MapMode must be PIXEL based" );
+ if ( GetMapMode().GetMapUnit() != MAP_PIXEL )
+ return;
+
+ // preserve graphicsstate
+ Push();
+ Region aClipRegion( GetClipRegion() );
+ SetClipRegion();
+
+ GDIMetaFile* pOldMtf = GetConnectMetaFile();
+ GDIMetaFile aMtf;
+ SetConnectMetaFile( &aMtf );
+
+ // put a push action to metafile
+ Push();
+ // copy graphics state to metafile
+ Font aCopyFont = GetFont();
+ if( nOldDPIX != mnDPIX || nOldDPIY != mnDPIY )
+ {
+ aCopyFont.SetHeight( aCopyFont.GetHeight() * mnDPIY / nOldDPIY );
+ aCopyFont.SetWidth( aCopyFont.GetWidth() * mnDPIX / nOldDPIX );
+ }
+ SetFont( aCopyFont );
+ SetTextColor( GetTextColor() );
+ if( IsLineColor() )
+ SetLineColor( GetLineColor() );
+ else
+ SetLineColor();
+ if( IsFillColor() )
+ SetFillColor( GetFillColor() );
+ else
+ SetFillColor();
+ if( IsTextLineColor() )
+ SetTextLineColor( GetTextLineColor() );
+ else
+ SetTextLineColor();
+ if( IsOverlineColor() )
+ SetOverlineColor( GetOverlineColor() );
+ else
+ SetOverlineColor();
+ if( IsTextFillColor() )
+ SetTextFillColor( GetTextFillColor() );
+ else
+ SetTextFillColor();
+ SetTextAlign( GetTextAlign() );
+ SetRasterOp( GetRasterOp() );
+ if( IsRefPoint() )
+ SetRefPoint( GetRefPoint() );
+ else
+ SetRefPoint();
+ SetLayoutMode( GetLayoutMode() );
+ SetDigitLanguage( GetDigitLanguage() );
+ Rectangle aPaintRect( Point( 0, 0 ), GetOutputSizePixel() );
+ aClipRegion.Intersect( aPaintRect );
+ SetClipRegion( aClipRegion );
+
+ // do the actual paint
+
+ // background
+ if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & PARENTCLIPMODE_NOCLIP ) )
+ Erase();
+ // foreground
+ Paint( aPaintRect );
+ // put a pop action to metafile
+ Pop();
+
+ SetConnectMetaFile( pOldMtf );
+ EnableOutput( bOutput );
+ mpWindowImpl->mbReallyVisible = bRVisible;
+
+ // paint metafile to VDev
+ VirtualDevice* pMaskedDevice = new VirtualDevice( *i_pTargetOutDev, 0, 0 );
+ pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel() );
+ pMaskedDevice->EnableRTL( IsRTLEnabled() );
+ aMtf.WindStart();
+ aMtf.Play( pMaskedDevice );
+ BitmapEx aBmpEx( pMaskedDevice->GetBitmapEx( Point( 0, 0 ), pMaskedDevice->GetOutputSizePixel() ) );
+ i_pTargetOutDev->DrawBitmapEx( i_rPos, aBmpEx );
+ // get rid of virtual device now so they don't pile up during recursive calls
+ delete pMaskedDevice, pMaskedDevice = NULL;
+
+
+ for( Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
+ {
+ if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
+ {
+ long nDeltaX = pChild->mnOutOffX - mnOutOffX;
+ if( ImplHasMirroredGraphics() )
+ nDeltaX = mnOutWidth - nDeltaX - pChild->mnOutWidth;
+ long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
+ Point aPos( i_rPos );
+ Point aDelta( nDeltaX, nDeltaY );
+ aPos += aDelta;
+ pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
+ }
+ }
+
+ // restore graphics state
+ Pop();
+
+ EnableOutput( bOutput );
+ mpWindowImpl->mbReallyVisible = bRVisible;
+ mbDevOutput = bDevOutput;
+ mnDPIX = nOldDPIX;
+ mnDPIY = nOldDPIY;
+}
+
+void Window::PaintToDevice( OutputDevice* pDev, const Point& rPos, const Size& /*rSize*/ )
+{
+ // FIXME: scaling: currently this is for pixel copying only
+
+ DBG_ASSERT( ! pDev->ImplHasMirroredGraphics(), "PaintToDevice to mirroring graphics" );
+ DBG_ASSERT( ! pDev->IsRTLEnabled(), "PaintToDevice to mirroring device" );
+
+
+ Point aPos = pDev->LogicToPixel( rPos );
+
+ Window* pRealParent = NULL;
+ if( ! mpWindowImpl->mbVisible )
+ {
+ Window* pTempParent = ImplGetDefaultWindow();
+ if( pTempParent )
+ pTempParent->EnableChildTransparentMode();
+ pRealParent = GetParent();
+ SetParent( pTempParent );
+ // trigger correct visibility flags for children
+ Show();
+ Hide();
+ }
+
+ BOOL bVisible = mpWindowImpl->mbVisible;
+ mpWindowImpl->mbVisible = TRUE;
+
+ if( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos );
+ else
+ ImplPaintToDevice( pDev, rPos );
+
+ mpWindowImpl->mbVisible = bVisible;
+
+ if( pRealParent )
+ SetParent( pRealParent );
+}
+
+XubString Window::GetSurroundingText() const
+{
+ return XubString::EmptyString();
+}
+
+Selection Window::GetSurroundingTextSelection() const
+{
+ return Selection( 0, 0 );
+}
+
diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx
new file mode 100644
index 000000000000..02b2713b01cc
--- /dev/null
+++ b/vcl/source/window/window2.cxx
@@ -0,0 +1,2065 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <limits.h>
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salbmp.hxx>
+#include <vcl/salgdi.hxx>
+#include <vcl/salframe.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/event.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/outfont.hxx>
+#include <vcl/outdev.h>
+#include <tools/poly.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/window.h>
+#include <vcl/window.hxx>
+#include <vcl/scrbar.hxx>
+#ifndef _SV_SCRWND_HXX
+#include <scrwnd.hxx>
+#endif
+#include <vcl/dockwin.hxx>
+
+
+
+// =======================================================================
+
+DBG_NAMEEX( Window )
+
+// =======================================================================
+
+#define IMPL_MAXSAVEBACKSIZE (640*480)
+#define IMPL_MAXALLSAVEBACKSIZE (800*600*2)
+
+// =======================================================================
+
+struct ImplFocusDelData : public ImplDelData
+{
+ Window* mpFocusWin;
+};
+
+// =======================================================================
+
+BOOL Window::ImplIsWindowInFront( const Window* pTestWindow ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+ DBG_CHKOBJ( pTestWindow, Window, ImplDbgCheckWindow );
+
+ // Testen, ob es Fenster untereinander liegen
+ pTestWindow = pTestWindow->ImplGetFirstOverlapWindow();
+ const Window* pTempWindow = pTestWindow;
+ const Window* pThisWindow = ImplGetFirstOverlapWindow();
+ if ( pTempWindow == pThisWindow )
+ return FALSE;
+ do
+ {
+ if ( pTempWindow == pThisWindow )
+ return TRUE;
+ if ( pTempWindow->mpWindowImpl->mbFrame )
+ break;
+ pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( pTempWindow );
+ pTempWindow = pThisWindow;
+ do
+ {
+ if ( pTempWindow == pTestWindow )
+ return FALSE;
+ if ( pTempWindow->mpWindowImpl->mbFrame )
+ break;
+ pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( pTempWindow );
+
+ // Fenster auf gleiche Ebene bringen
+ if ( pThisWindow->mpWindowImpl->mpOverlapWindow != pTestWindow->mpWindowImpl->mpOverlapWindow )
+ {
+ USHORT nThisLevel = 0;
+ USHORT nTestLevel = 0;
+ pTempWindow = pThisWindow;
+ do
+ {
+ nThisLevel++;
+ pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( !pTempWindow->mpWindowImpl->mbFrame );
+ pTempWindow = pTestWindow;
+ do
+ {
+ nTestLevel++;
+ pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( !pTempWindow->mpWindowImpl->mbFrame );
+
+ if ( nThisLevel < nTestLevel )
+ {
+ do
+ {
+ if ( pTestWindow->mpWindowImpl->mpOverlapWindow == pThisWindow->mpWindowImpl->mpOverlapWindow )
+ break;
+ if ( pTestWindow->mpWindowImpl->mbFrame )
+ break;
+ pTestWindow = pTestWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( pTestWindow );
+ }
+ else
+ {
+ do
+ {
+ if ( pThisWindow->mpWindowImpl->mpOverlapWindow == pTempWindow->mpWindowImpl->mpOverlapWindow )
+ break;
+ if ( pThisWindow->mpWindowImpl->mbFrame )
+ break;
+ pThisWindow = pThisWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( pThisWindow );
+ }
+ }
+
+ // Wenn TestWindow vor ThisWindow kommt, liegt es vorne
+ pTempWindow = pTestWindow;
+ do
+ {
+ if ( pTempWindow == pThisWindow )
+ return TRUE;
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+ while ( pTempWindow );
+
+ return FALSE;
+}
+
+// =======================================================================
+
+void Window::ImplSaveOverlapBackground()
+{
+ DBG_ASSERT( !mpWindowImpl->mpOverlapData->mpSaveBackDev, "Window::ImplSaveOverlapBackground() - Background already saved" );
+
+ if ( !mpWindowImpl->mbFrame )
+ {
+ ULONG nSaveBackSize = mnOutWidth*mnOutHeight;
+ if ( nSaveBackSize <= IMPL_MAXSAVEBACKSIZE )
+ {
+ if ( nSaveBackSize+mpWindowImpl->mpFrameData->mnAllSaveBackSize <= IMPL_MAXALLSAVEBACKSIZE )
+ {
+ Size aOutSize( mnOutWidth, mnOutHeight );
+ mpWindowImpl->mpOverlapData->mpSaveBackDev = new VirtualDevice( *mpWindowImpl->mpFrameWindow );
+ if ( mpWindowImpl->mpOverlapData->mpSaveBackDev->SetOutputSizePixel( aOutSize ) )
+ {
+ mpWindowImpl->mpFrameWindow->ImplUpdateAll();
+
+ if ( mpWindowImpl->mbInitWinClipRegion )
+ ImplInitWinClipRegion();
+
+ mpWindowImpl->mpOverlapData->mnSaveBackSize = nSaveBackSize;
+ mpWindowImpl->mpFrameData->mnAllSaveBackSize += nSaveBackSize;
+ Point aDevPt;
+ mpWindowImpl->mpFrameWindow->ImplGetFrameDev( Point( mnOutOffX, mnOutOffY ),
+ aDevPt, aOutSize,
+ *(mpWindowImpl->mpOverlapData->mpSaveBackDev) );
+ mpWindowImpl->mpOverlapData->mpNextBackWin = mpWindowImpl->mpFrameData->mpFirstBackWin;
+ mpWindowImpl->mpFrameData->mpFirstBackWin = this;
+ }
+ else
+ {
+ delete mpWindowImpl->mpOverlapData->mpSaveBackDev;
+ mpWindowImpl->mpOverlapData->mpSaveBackDev = NULL;
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::ImplRestoreOverlapBackground( Region& rInvRegion )
+{
+ if ( mpWindowImpl->mpOverlapData->mpSaveBackDev )
+ {
+ if ( mpWindowImpl->mbInitWinClipRegion )
+ ImplInitWinClipRegion();
+
+ if ( mpWindowImpl->mpOverlapData->mpSaveBackDev )
+ {
+ Point aDevPt;
+ Point aDestPt( mnOutOffX, mnOutOffY );
+ Size aDevSize = mpWindowImpl->mpOverlapData->mpSaveBackDev->GetOutputSizePixel();
+ if ( mpWindowImpl->mpOverlapData->mpSaveBackRgn )
+ {
+ mpWindowImpl->mpOverlapData->mpSaveBackRgn->Intersect( mpWindowImpl->maWinClipRegion );
+ rInvRegion = mpWindowImpl->maWinClipRegion;
+ rInvRegion.Exclude( *mpWindowImpl->mpOverlapData->mpSaveBackRgn );
+ mpWindowImpl->mpFrameWindow->ImplDrawFrameDev( aDestPt, aDevPt, aDevSize,
+ *(mpWindowImpl->mpOverlapData->mpSaveBackDev),
+ *mpWindowImpl->mpOverlapData->mpSaveBackRgn );
+ }
+ else
+ {
+ mpWindowImpl->mpFrameWindow->ImplDrawFrameDev( aDestPt, aDevPt, aDevSize,
+ *(mpWindowImpl->mpOverlapData->mpSaveBackDev),
+ mpWindowImpl->maWinClipRegion );
+ }
+ ImplDeleteOverlapBackground();
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplDeleteOverlapBackground()
+{
+ if ( mpWindowImpl->mpOverlapData->mpSaveBackDev )
+ {
+ mpWindowImpl->mpFrameData->mnAllSaveBackSize -= mpWindowImpl->mpOverlapData->mnSaveBackSize;
+ delete mpWindowImpl->mpOverlapData->mpSaveBackDev;
+ mpWindowImpl->mpOverlapData->mpSaveBackDev = NULL;
+ if ( mpWindowImpl->mpOverlapData->mpSaveBackRgn )
+ {
+ delete mpWindowImpl->mpOverlapData->mpSaveBackRgn;
+ mpWindowImpl->mpOverlapData->mpSaveBackRgn = NULL;
+ }
+
+ // Fenster aus der Liste entfernen
+ if ( mpWindowImpl->mpFrameData->mpFirstBackWin == this )
+ mpWindowImpl->mpFrameData->mpFirstBackWin = mpWindowImpl->mpOverlapData->mpNextBackWin;
+ else
+ {
+ Window* pTemp = mpWindowImpl->mpFrameData->mpFirstBackWin;
+ while ( pTemp->mpWindowImpl->mpOverlapData->mpNextBackWin != this )
+ pTemp = pTemp->mpWindowImpl->mpOverlapData->mpNextBackWin;
+ pTemp->mpWindowImpl->mpOverlapData->mpNextBackWin = mpWindowImpl->mpOverlapData->mpNextBackWin;
+ }
+ mpWindowImpl->mpOverlapData->mpNextBackWin = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplInvalidateAllOverlapBackgrounds()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Window* pWindow = mpWindowImpl->mpFrameData->mpFirstBackWin;
+ while ( pWindow )
+ {
+ // Naechstes Fenster schon hier merken, da dieses Fenster in
+ // der if-Abfrage aus der Liste entfernt werden kann
+ Window* pNext = pWindow->mpWindowImpl->mpOverlapData->mpNextBackWin;
+
+ if ( ImplIsWindowInFront( pWindow ) )
+ {
+ Rectangle aRect1( Point( mnOutOffX, mnOutOffY ),
+ Size( mnOutWidth, mnOutHeight ) );
+ Rectangle aRect2( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ),
+ Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) );
+ aRect1.Intersection( aRect2 );
+ if ( !aRect1.IsEmpty() )
+ {
+ if ( !pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn )
+ pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn = new Region( aRect2 );
+ pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn->Exclude( aRect1 );
+ if ( pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn->IsEmpty() )
+ pWindow->ImplDeleteOverlapBackground();
+ }
+
+ }
+
+ pWindow = pNext;
+ }
+}
+
+// =======================================================================
+
+Bitmap Window::SnapShot( BOOL bBorder ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Bitmap aBmp;
+
+ if ( IsReallyVisible() )
+ {
+ if ( bBorder && mpWindowImpl->mpBorderWindow )
+ aBmp = mpWindowImpl->mpBorderWindow->SnapShot();
+ else
+ {
+ ((Window*)this)->Update();
+
+ if ( bBorder && mpWindowImpl->mbFrame )
+ {
+ SalBitmap* pSalBmp = mpWindowImpl->mpFrame->SnapShot();
+
+ if ( pSalBmp )
+ {
+ ImpBitmap* pImpBmp = new ImpBitmap;
+ pImpBmp->ImplSetSalBitmap( pSalBmp );
+ aBmp.ImplSetImpBitmap( pImpBmp );
+ return aBmp;
+ }
+ }
+
+ mpWindowImpl->mpFrameWindow->ImplGetFrameBitmap( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ), aBmp );
+ }
+ }
+
+ return aBmp;
+}
+
+// -----------------------------------------------------------------------
+
+Bitmap Window::SnapShot() const
+{
+ // Should be merged in the next top level build !!!
+ return SnapShot( TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ShowFocus( const Rectangle& rRect )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( mpWindowImpl->mbInShowFocus )
+ return;
+ mpWindowImpl->mbInShowFocus = TRUE;
+
+ ImplWinData* pWinData = ImplGetWinData();
+
+ // native themeing suggest not to use focus rects
+ if( ! ( mpWindowImpl->mbUseNativeFocus &&
+ IsNativeWidgetEnabled() ) )
+ {
+ if ( !mpWindowImpl->mbInPaint )
+ {
+ if ( mpWindowImpl->mbFocusVisible )
+ {
+ if ( *(pWinData->mpFocusRect) == rRect )
+ {
+ mpWindowImpl->mbInShowFocus = FALSE;
+ return;
+ }
+
+ ImplInvertFocus( *(pWinData->mpFocusRect) );
+ }
+
+ ImplInvertFocus( rRect );
+ }
+ if ( !pWinData->mpFocusRect )
+ pWinData->mpFocusRect = new Rectangle( rRect );
+ else
+ *(pWinData->mpFocusRect) = rRect;
+ mpWindowImpl->mbFocusVisible = TRUE;
+ }
+ else
+ {
+ if( ! mpWindowImpl->mbNativeFocusVisible )
+ {
+ mpWindowImpl->mbNativeFocusVisible = TRUE;
+ if ( !mpWindowImpl->mbInPaint )
+ Invalidate();
+ }
+ }
+ mpWindowImpl->mbInShowFocus = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::HideFocus()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if( mpWindowImpl->mbInHideFocus )
+ return;
+ mpWindowImpl->mbInHideFocus = TRUE;
+
+ // native themeing can suggest not to use focus rects
+ if( ! ( mpWindowImpl->mbUseNativeFocus &&
+ IsNativeWidgetEnabled() ) )
+ {
+ if ( !mpWindowImpl->mbFocusVisible )
+ {
+ mpWindowImpl->mbInHideFocus = FALSE;
+ return;
+ }
+
+ if ( !mpWindowImpl->mbInPaint )
+ ImplInvertFocus( *(ImplGetWinData()->mpFocusRect) );
+ mpWindowImpl->mbFocusVisible = FALSE;
+ }
+ else
+ {
+ if( mpWindowImpl->mbNativeFocusVisible )
+ {
+ mpWindowImpl->mbNativeFocusVisible = FALSE;
+ if ( !mpWindowImpl->mbInPaint )
+ Invalidate();
+ }
+ }
+ mpWindowImpl->mbInHideFocus = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Invert( const Rectangle& rRect, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() )
+ return;
+
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+
+ if ( aRect.IsEmpty() )
+ return;
+ aRect.Justify();
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( mbOutputClipped )
+ return;
+
+ SalInvert nSalFlags = 0;
+ if ( nFlags & INVERT_HIGHLIGHT )
+ nSalFlags |= SAL_INVERT_HIGHLIGHT;
+ if ( nFlags & INVERT_50 )
+ nSalFlags |= SAL_INVERT_50;
+ mpGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), nSalFlags, this );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::Invert( const Polygon& rPoly, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( !IsDeviceOutputNecessary() )
+ return;
+
+ USHORT nPoints = rPoly.GetSize();
+
+ if ( nPoints < 2 )
+ return;
+
+ Polygon aPoly( ImplLogicToDevicePixel( rPoly ) );
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( mbOutputClipped )
+ return;
+
+ SalInvert nSalFlags = 0;
+ if ( nFlags & INVERT_HIGHLIGHT )
+ nSalFlags |= SAL_INVERT_HIGHLIGHT;
+ if ( nFlags & INVERT_50 )
+ nSalFlags |= SAL_INVERT_50;
+ const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
+ mpGraphics->Invert( nPoints, pPtAry, nSalFlags, this );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ShowTracking( const Rectangle& rRect, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplWinData* pWinData = ImplGetWinData();
+
+ if ( !mpWindowImpl->mbInPaint || !(nFlags & SHOWTRACK_WINDOW) )
+ {
+ if ( mpWindowImpl->mbTrackVisible )
+ {
+ if ( (*(pWinData->mpTrackRect) == rRect) &&
+ (pWinData->mnTrackFlags == nFlags) )
+ return;
+
+ InvertTracking( *(pWinData->mpTrackRect), pWinData->mnTrackFlags );
+ }
+
+ InvertTracking( rRect, nFlags );
+ }
+
+ if ( !pWinData->mpTrackRect )
+ pWinData->mpTrackRect = new Rectangle( rRect );
+ else
+ *(pWinData->mpTrackRect) = rRect;
+ pWinData->mnTrackFlags = nFlags;
+ mpWindowImpl->mbTrackVisible = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::HideTracking()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mbTrackVisible )
+ {
+ ImplWinData* pWinData = ImplGetWinData();
+ if ( !mpWindowImpl->mbInPaint || !(pWinData->mnTrackFlags & SHOWTRACK_WINDOW) )
+ InvertTracking( *(pWinData->mpTrackRect), pWinData->mnTrackFlags );
+ mpWindowImpl->mbTrackVisible = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::InvertTracking( const Rectangle& rRect, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
+
+ if ( aRect.IsEmpty() )
+ return;
+ aRect.Justify();
+
+ SalGraphics* pGraphics;
+
+ if ( nFlags & SHOWTRACK_WINDOW )
+ {
+ if ( !IsDeviceOutputNecessary() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( mbOutputClipped )
+ return;
+
+ pGraphics = mpGraphics;
+ }
+ else
+ {
+ pGraphics = ImplGetFrameGraphics();
+
+ if ( nFlags & SHOWTRACK_CLIP )
+ {
+ Point aPoint( mnOutOffX, mnOutOffY );
+ Region aRegion( Rectangle( aPoint,
+ Size( mnOutWidth, mnOutHeight ) ) );
+ ImplClipBoundaries( aRegion, FALSE, FALSE );
+ ImplSelectClipRegion( aRegion, pGraphics );
+ }
+ }
+
+ USHORT nStyle = nFlags & SHOWTRACK_STYLE;
+ if ( nStyle == SHOWTRACK_OBJECT )
+ pGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), SAL_INVERT_TRACKFRAME, this );
+ else if ( nStyle == SHOWTRACK_SPLIT )
+ pGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), SAL_INVERT_50, this );
+ else
+ {
+ long nBorder = 1;
+ if ( nStyle == SHOWTRACK_BIG )
+ nBorder = 5;
+ pGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), nBorder, SAL_INVERT_50, this );
+ pGraphics->Invert( aRect.Left(), aRect.Bottom()-nBorder+1, aRect.GetWidth(), nBorder, SAL_INVERT_50, this );
+ pGraphics->Invert( aRect.Left(), aRect.Top()+nBorder, nBorder, aRect.GetHeight()-(nBorder*2), SAL_INVERT_50, this );
+ pGraphics->Invert( aRect.Right()-nBorder+1, aRect.Top()+nBorder, nBorder, aRect.GetHeight()-(nBorder*2), SAL_INVERT_50, this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::InvertTracking( const Polygon& rPoly, USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ USHORT nPoints = rPoly.GetSize();
+
+ if ( nPoints < 2 )
+ return;
+
+ Polygon aPoly( ImplLogicToDevicePixel( rPoly ) );
+
+ SalGraphics* pGraphics;
+
+ if ( nFlags & SHOWTRACK_WINDOW )
+ {
+ if ( !IsDeviceOutputNecessary() )
+ return;
+
+ // we need a graphics
+ if ( !mpGraphics )
+ {
+ if ( !ImplGetGraphics() )
+ return;
+ }
+
+ if ( mbInitClipRegion )
+ ImplInitClipRegion();
+
+ if ( mbOutputClipped )
+ return;
+
+ pGraphics = mpGraphics;
+ }
+ else
+ {
+ pGraphics = ImplGetFrameGraphics();
+
+ if ( nFlags & SHOWTRACK_CLIP )
+ {
+ Point aPoint( mnOutOffX, mnOutOffY );
+ Region aRegion( Rectangle( aPoint,
+ Size( mnOutWidth, mnOutHeight ) ) );
+ ImplClipBoundaries( aRegion, FALSE, FALSE );
+ ImplSelectClipRegion( aRegion, pGraphics );
+ }
+ }
+
+ const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
+ pGraphics->Invert( nPoints, pPtAry, SAL_INVERT_TRACKFRAME, this );
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Window, ImplTrackTimerHdl, Timer*, pTimer )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Bei Button-Repeat muessen wir den Timeout umsetzen
+ if ( pSVData->maWinData.mnTrackFlags & STARTTRACK_BUTTONREPEAT )
+ pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
+
+ // Tracking-Event erzeugen
+ Point aMousePos( mpWindowImpl->mpFrameData->mnLastMouseX, mpWindowImpl->mpFrameData->mnLastMouseY );
+ if( ImplIsAntiparallel() )
+ {
+ // - RTL - re-mirror frame pos at pChild
+ ImplReMirror( aMousePos );
+ }
+ MouseEvent aMEvt( ImplFrameToOutput( aMousePos ),
+ mpWindowImpl->mpFrameData->mnClickCount, 0,
+ mpWindowImpl->mpFrameData->mnMouseCode, mpWindowImpl->mpFrameData->mnMouseCode );
+ TrackingEvent aTEvt( aMEvt, TRACKING_REPEAT );
+ Tracking( aTEvt );
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::StartTracking( USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maWinData.mpTrackWin != this )
+ {
+ if ( pSVData->maWinData.mpTrackWin )
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL );
+ }
+
+ if ( nFlags & (STARTTRACK_SCROLLREPEAT | STARTTRACK_BUTTONREPEAT) )
+ {
+ pSVData->maWinData.mpTrackTimer = new AutoTimer;
+
+ if ( nFlags & STARTTRACK_SCROLLREPEAT )
+ pSVData->maWinData.mpTrackTimer->SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() );
+ else
+ pSVData->maWinData.mpTrackTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+ pSVData->maWinData.mpTrackTimer->SetTimeoutHdl( LINK( this, Window, ImplTrackTimerHdl ) );
+ pSVData->maWinData.mpTrackTimer->Start();
+ }
+
+ pSVData->maWinData.mpTrackWin = this;
+ pSVData->maWinData.mnTrackFlags = nFlags;
+ CaptureMouse();
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EndTracking( USHORT nFlags )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maWinData.mpTrackWin == this )
+ {
+ // Hier wegen DbgChkThis geklammert, da Window im Handler zerstoert
+ // werden kann
+ {
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( pSVData->maWinData.mpTrackTimer )
+ {
+ delete pSVData->maWinData.mpTrackTimer;
+ pSVData->maWinData.mpTrackTimer = NULL;
+ }
+
+ pSVData->maWinData.mpTrackWin = NULL;
+ pSVData->maWinData.mnTrackFlags = 0;
+ ReleaseMouse();
+ }
+
+ // EndTracking rufen, wenn es gerufen werden soll
+ if ( !(nFlags & ENDTRACK_DONTCALLHDL) )
+ {
+ Point aMousePos( mpWindowImpl->mpFrameData->mnLastMouseX, mpWindowImpl->mpFrameData->mnLastMouseY );
+ if( ImplIsAntiparallel() )
+ {
+ // - RTL - re-mirror frame pos at pChild
+ ImplReMirror( aMousePos );
+ }
+
+ MouseEvent aMEvt( ImplFrameToOutput( aMousePos ),
+ mpWindowImpl->mpFrameData->mnClickCount, 0,
+ mpWindowImpl->mpFrameData->mnMouseCode, mpWindowImpl->mpFrameData->mnMouseCode );
+ TrackingEvent aTEvt( aMEvt, nFlags | ENDTRACK_END );
+ Tracking( aTEvt );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsTracking() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ return (ImplGetSVData()->maWinData.mpTrackWin == this);
+}
+
+// -----------------------------------------------------------------------
+
+void Window::StartAutoScroll( USHORT nFlags )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maWinData.mpAutoScrollWin != this )
+ {
+ if ( pSVData->maWinData.mpAutoScrollWin )
+ pSVData->maWinData.mpAutoScrollWin->EndAutoScroll();
+ }
+
+ pSVData->maWinData.mpAutoScrollWin = this;
+ pSVData->maWinData.mnAutoScrollFlags = nFlags;
+ pSVData->maAppData.mpWheelWindow = new ImplWheelWindow( this );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::EndAutoScroll()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maWinData.mpAutoScrollWin == this )
+ {
+ pSVData->maWinData.mpAutoScrollWin = NULL;
+ pSVData->maWinData.mnAutoScrollFlags = 0;
+ pSVData->maAppData.mpWheelWindow->ImplStop();
+ pSVData->maAppData.mpWheelWindow->doLazyDelete();
+ pSVData->maAppData.mpWheelWindow = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::IsAutoScroll() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ return (ImplGetSVData()->maWinData.mpAutoScrollWin == this);
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SaveBackground( const Point& rPos, const Size& rSize,
+ const Point& rDestOff, VirtualDevice& rSaveDevice )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpPaintRegion )
+ {
+ Region aClip( *mpWindowImpl->mpPaintRegion );
+ const Point aPixPos( LogicToPixel( rPos ) );
+
+ aClip.Move( -mnOutOffX, -mnOutOffY );
+ aClip.Intersect( Rectangle( aPixPos, LogicToPixel( rSize ) ) );
+
+ if ( !aClip.IsEmpty() )
+ {
+ const Region aOldClip( rSaveDevice.GetClipRegion() );
+ const Point aPixOffset( rSaveDevice.LogicToPixel( rDestOff ) );
+ const BOOL bMap = rSaveDevice.IsMapModeEnabled();
+
+ // move clip region to have the same distance to DestOffset
+ aClip.Move( aPixOffset.X() - aPixPos.X(), aPixOffset.Y() - aPixPos.Y() );
+
+ // set pixel clip region
+ rSaveDevice.EnableMapMode( FALSE );
+ rSaveDevice.SetClipRegion( aClip );
+ rSaveDevice.EnableMapMode( bMap );
+ rSaveDevice.DrawOutDev( rDestOff, rSize, rPos, rSize, *this );
+ rSaveDevice.SetClipRegion( aOldClip );
+ }
+ }
+ else
+ rSaveDevice.DrawOutDev( rDestOff, rSize, rPos, rSize, *this );
+}
+
+// -----------------------------------------------------------------------
+
+sal_uIntPtr Window::SaveFocus()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpFocusWin )
+ {
+ ImplFocusDelData* pDelData = new ImplFocusDelData;
+ pSVData->maWinData.mpFocusWin->ImplAddDel( pDelData );
+ pDelData->mpFocusWin = pSVData->maWinData.mpFocusWin;
+ return (sal_uIntPtr)(void*)pDelData;
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::EndSaveFocus( sal_uIntPtr nSaveId, BOOL bRestore )
+{
+ if ( !nSaveId )
+ return FALSE;
+ else
+ {
+ BOOL bOK = TRUE;
+ ImplFocusDelData* pDelData = (ImplFocusDelData*)(void*)nSaveId;
+ if ( !pDelData->IsDelete() )
+ {
+ pDelData->mpFocusWin->ImplRemoveDel( pDelData );
+ if ( bRestore )
+ pDelData->mpFocusWin->GrabFocus();
+ }
+ else
+ bOK = !bRestore;
+ delete pDelData;
+ return bOK;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetZoom( const Fraction& rZoom )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->maZoom != rZoom )
+ {
+ mpWindowImpl->maZoom = rZoom;
+ StateChanged( STATE_CHANGE_ZOOM );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline long WinFloatRound( double fVal )
+{
+ return( fVal > 0.0 ? (long) ( fVal + 0.5 ) : -(long) ( -fVal + 0.5 ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetZoomedPointFont( const Font& rFont )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ const Fraction& rZoom = GetZoom();
+ if ( rZoom.GetNumerator() != rZoom.GetDenominator() )
+ {
+ Font aFont( rFont );
+ Size aSize = aFont.GetSize();
+ double n = (double)aSize.Width();
+ n *= (double)rZoom.GetNumerator();
+ n /= (double)rZoom.GetDenominator();
+ aSize.Width() = WinFloatRound( n );
+ n = (double)aSize.Height();
+ n *= (double)rZoom.GetNumerator();
+ n /= (double)rZoom.GetDenominator();
+ aSize.Height() = WinFloatRound( n );
+ aFont.SetSize( aSize );
+ SetPointFont( aFont );
+
+ // Wenn Darstellung skaliert wird, nehmen wir gegebenenfalls
+ // einen anderen Font, wenn der aktuelle nicht skalierbar ist
+ FontMetric aMetric = GetFontMetric();
+ long nFontDiff = Abs( GetFont().GetSize().Height()-aMetric.GetSize().Height() );
+ if ( (aMetric.GetType() == TYPE_RASTER) && (nFontDiff >= 2) )
+ {
+ USHORT nType;
+ if ( aMetric.GetPitch() == PITCH_FIXED )
+ nType = DEFAULTFONT_FIXED;
+ else
+ nType = DEFAULTFONT_UI_SANS;
+ Font aTempFont = GetDefaultFont( nType, GetSettings().GetLanguage(), 0 );
+ aFont.SetName( aTempFont.GetName() );
+ SetPointFont( aFont );
+ }
+ }
+ else
+ SetPointFont( rFont );
+}
+
+// -----------------------------------------------------------------------
+
+long Window::CalcZoom( long nCalc ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ const Fraction& rZoom = GetZoom();
+ if ( rZoom.GetNumerator() != rZoom.GetDenominator() )
+ {
+ double n = (double)nCalc;
+ n *= (double)rZoom.GetNumerator();
+ n /= (double)rZoom.GetDenominator();
+ nCalc = WinFloatRound( n );
+ }
+ return nCalc;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetControlFont()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpControlFont )
+ {
+ delete mpWindowImpl->mpControlFont;
+ mpWindowImpl->mpControlFont = NULL;
+ StateChanged( STATE_CHANGE_CONTROLFONT );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetControlFont( const Font& rFont )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( rFont == Font() )
+ {
+ SetControlFont();
+ return;
+ }
+
+ if ( mpWindowImpl->mpControlFont )
+ {
+ if ( *mpWindowImpl->mpControlFont == rFont )
+ return;
+ *mpWindowImpl->mpControlFont = rFont;
+ }
+ else
+ mpWindowImpl->mpControlFont = new Font( rFont );
+
+ StateChanged( STATE_CHANGE_CONTROLFONT );
+}
+
+// -----------------------------------------------------------------------
+
+Font Window::GetControlFont() const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mpControlFont )
+ return *mpWindowImpl->mpControlFont;
+ else
+ {
+ Font aFont;
+ return aFont;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetControlForeground()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mbControlForeground )
+ {
+ mpWindowImpl->maControlForeground = Color( COL_TRANSPARENT );
+ mpWindowImpl->mbControlForeground = FALSE;
+ StateChanged( STATE_CHANGE_CONTROLFOREGROUND );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetControlForeground( const Color& rColor )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( rColor.GetTransparency() )
+ {
+ if ( mpWindowImpl->mbControlForeground )
+ {
+ mpWindowImpl->maControlForeground = Color( COL_TRANSPARENT );
+ mpWindowImpl->mbControlForeground = FALSE;
+ StateChanged( STATE_CHANGE_CONTROLFOREGROUND );
+ }
+ }
+ else
+ {
+ if ( mpWindowImpl->maControlForeground != rColor )
+ {
+ mpWindowImpl->maControlForeground = rColor;
+ mpWindowImpl->mbControlForeground = TRUE;
+ StateChanged( STATE_CHANGE_CONTROLFOREGROUND );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetControlBackground()
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( mpWindowImpl->mbControlBackground )
+ {
+ mpWindowImpl->maControlBackground = Color( COL_TRANSPARENT );
+ mpWindowImpl->mbControlBackground = FALSE;
+ StateChanged( STATE_CHANGE_CONTROLBACKGROUND );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::SetControlBackground( const Color& rColor )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ if ( rColor.GetTransparency() )
+ {
+ if ( mpWindowImpl->mbControlBackground )
+ {
+ mpWindowImpl->maControlBackground = Color( COL_TRANSPARENT );
+ mpWindowImpl->mbControlBackground = FALSE;
+ StateChanged( STATE_CHANGE_CONTROLBACKGROUND );
+ }
+ }
+ else
+ {
+ if ( mpWindowImpl->maControlBackground != rColor )
+ {
+ mpWindowImpl->maControlBackground = rColor;
+ mpWindowImpl->mbControlBackground = TRUE;
+ StateChanged( STATE_CHANGE_CONTROLBACKGROUND );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size Window::CalcWindowSize( const Size& rOutSz ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Size aSz = rOutSz;
+ aSz.Width() += mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder;
+ aSz.Height() += mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder;
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Size Window::CalcOutputSize( const Size& rWinSz ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Size aSz = rWinSz;
+ aSz.Width() -= mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder;
+ aSz.Height() -= mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder;
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Font Window::GetDrawPixelFont( OutputDevice* pDev ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ Font aFont = GetPointFont();
+ Size aFontSize = aFont.GetSize();
+ MapMode aPtMapMode( MAP_POINT );
+ aFontSize = pDev->LogicToPixel( aFontSize, aPtMapMode );
+ aFont.SetSize( aFontSize );
+ return aFont;
+}
+
+// -----------------------------------------------------------------------
+
+long Window::GetDrawPixel( OutputDevice* pDev, long nPixels ) const
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ long nP = nPixels;
+ if ( pDev->GetOutDevType() != OUTDEV_WINDOW )
+ {
+ MapMode aMap( MAP_100TH_MM );
+ Size aSz( nP, 0 );
+ aSz = PixelToLogic( aSz, aMap );
+ aSz = pDev->LogicToPixel( aSz, aMap );
+ nP = aSz.Width();
+ }
+ return nP;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Window::HandleScrollCommand( const CommandEvent& rCmd,
+ ScrollBar* pHScrl, ScrollBar* pVScrl )
+{
+ DBG_CHKTHIS( Window, ImplDbgCheckWindow );
+
+ BOOL bRet = FALSE;
+
+ if ( pHScrl || pVScrl )
+ {
+ switch( rCmd.GetCommand() )
+ {
+ case COMMAND_STARTAUTOSCROLL:
+ {
+ USHORT nFlags = 0;
+ if ( pHScrl )
+ {
+ if ( (pHScrl->GetVisibleSize() < pHScrl->GetRangeMax()) &&
+ pHScrl->IsEnabled() && pHScrl->IsInputEnabled() && ! pHScrl->IsInModalMode() )
+ nFlags |= AUTOSCROLL_HORZ;
+ }
+ if ( pVScrl )
+ {
+ if ( (pVScrl->GetVisibleSize() < pVScrl->GetRangeMax()) &&
+ pVScrl->IsEnabled() && pVScrl->IsInputEnabled() && ! pVScrl->IsInModalMode() )
+ nFlags |= AUTOSCROLL_VERT;
+ }
+
+ if ( nFlags )
+ {
+ StartAutoScroll( nFlags );
+ bRet = TRUE;
+ }
+ }
+ break;
+
+ case COMMAND_WHEEL:
+ {
+ const CommandWheelData* pData = rCmd.GetWheelData();
+
+ if ( pData && (COMMAND_WHEEL_SCROLL == pData->GetMode()) )
+ {
+ ULONG nScrollLines = pData->GetScrollLines();
+ long nLines;
+ if ( nScrollLines == COMMAND_WHEEL_PAGESCROLL )
+ {
+ if ( pData->GetDelta() < 0 )
+ nLines = -LONG_MAX;
+ else
+ nLines = LONG_MAX;
+ }
+ else
+ nLines = pData->GetNotchDelta() * (long)nScrollLines;
+ if ( nLines )
+ {
+ ImplHandleScroll( NULL,
+ 0L,
+ pData->IsHorz() ? pHScrl : pVScrl,
+ nLines );
+ bRet = TRUE;
+ }
+ }
+ }
+ break;
+
+ case COMMAND_AUTOSCROLL:
+ {
+ const CommandScrollData* pData = rCmd.GetAutoScrollData();
+ if ( pData && (pData->GetDeltaX() || pData->GetDeltaY()) )
+ {
+ ImplHandleScroll( pHScrl, pData->GetDeltaX(),
+ pVScrl, pData->GetDeltaY() );
+ bRet = TRUE;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplHandleScroll( ScrollBar* pHScrl, long nX,
+ ScrollBar* pVScrl, long nY )
+{
+ if ( pHScrl && nX && pHScrl->IsEnabled() && pHScrl->IsInputEnabled() && ! pHScrl->IsInModalMode() )
+ {
+ long nNewPos = pHScrl->GetThumbPos();
+
+ if ( nX == -LONG_MAX )
+ nNewPos += pHScrl->GetPageSize();
+ else if ( nX == LONG_MAX )
+ nNewPos -= pHScrl->GetPageSize();
+ else
+ {
+ const double fVal = (double)nNewPos - ((double)nX * pHScrl->GetLineSize());
+
+ if ( fVal < LONG_MIN )
+ nNewPos = LONG_MIN;
+ else if ( fVal > LONG_MAX )
+ nNewPos = LONG_MAX;
+ else
+ nNewPos = (long)fVal;
+ }
+
+ pHScrl->DoScroll( nNewPos );
+ }
+
+ if ( pVScrl && nY && pVScrl->IsEnabled() && pVScrl->IsInputEnabled() && ! pVScrl->IsInModalMode() )
+ {
+ long nNewPos = pVScrl->GetThumbPos();
+
+ if ( nY == -LONG_MAX )
+ nNewPos += pVScrl->GetPageSize();
+ else if ( nY == LONG_MAX )
+ nNewPos -= pVScrl->GetPageSize();
+ else
+ {
+ const double fVal = (double)nNewPos - ((double)nY * pVScrl->GetLineSize());
+
+ if ( fVal < LONG_MIN )
+ nNewPos = LONG_MIN;
+ else if ( fVal > LONG_MAX )
+ nNewPos = LONG_MAX;
+ else
+ nNewPos = (long)fVal;
+ }
+
+ pVScrl->DoScroll( nNewPos );
+ }
+}
+
+// support for docking
+// this is currently handled in ImplDockingWindowWrapper
+/*
+void Window::ImplSetFloatingMode( BOOL bFloatMode )
+{
+ // if the window is docked, put it into a flaoting window
+ // if it is floating put it back in the old frame
+
+ ImplDockingWindowWrapper *pWrapper = pDockingMgr->GetDockingWindowWrapper( this );
+ if( !pDockingData )
+ return;
+
+ if ( pWrapper->IsFloatingMode() != bFloatMode )
+ {
+ if ( pWrapper->PrepareToggleFloatingMode() )
+ {
+ BOOL bVisible = IsVisible();
+
+ if ( bFloatMode )
+ {
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ pWrapper->maDockPos = GetPosPixel();
+
+ Window* pRealParent = mpWindowImpl->mpRealParent;
+ pWrapper->mpOldBorderWin = mpWindowImpl->mpBorderWindow;
+
+ ImplDockFloatWin* pWin =
+ new ImplDockFloatWin2(
+ mpWindowImpl->mpParent,
+ mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? mnFloatBits | WB_SYSTEMWINDOW : mnFloatBits,
+ pWrapper );
+ pWrapper->mpFloatWin = pWin;
+ mpWindowImpl->mpBorderWindow = NULL;
+ mpWindowImpl->mnLeftBorder = 0;
+ mpWindowImpl->mnTopBorder = 0;
+ mpWindowImpl->mnRightBorder = 0;
+ mpWindowImpl->mnBottomBorder = 0;
+ // Falls Parent zerstoert wird, muessen wir auch vom
+ // BorderWindow den Parent umsetzen
+ if ( pWrapper->mpOldBorderWin )
+ pWrapper->mpOldBorderWin->SetParent( pWin );
+ SetParent( pWin );
+ pWin->SetPosPixel( Point() );
+ mpWindowImpl->mpBorderWindow = pWin;
+ pWin->mpWindowImpl->mpClientWindow = this;
+ mpWindowImpl->mpRealParent = pRealParent;
+ pWin->SetText( GetText() );
+ pWin->SetOutputSizePixel( GetSizePixel() );
+ pWin->SetPosPixel( pWrapper->maFloatPos );
+ // DockingDaten ans FloatingWindow weiterreichen
+ pWin->ShowTitleButton( TITLE_BUTTON_DOCKING, pWrapper->mbDockBtn );
+ pWin->ShowTitleButton( TITLE_BUTTON_HIDE, pWrapper->mbHideBtn );
+ pWin->SetPin( pWrapper->mbPined );
+ if ( pWrapper->mbRollUp )
+ pWin->RollUp();
+ else
+ pWin->RollDown();
+ pWin->SetRollUpOutputSizePixel( pWrapper->maRollUpOutSize );
+ pWin->SetMinOutputSizePixel( pWrapper->maMinOutSize );
+
+ pWrapper->ToggleFloatingMode();
+
+ if ( bVisible )
+ Show();
+ }
+ else
+ {
+ Show( FALSE, SHOW_NOFOCUSCHANGE );
+
+ // FloatingDaten wird im FloatingWindow speichern
+ pWrapper->maFloatPos = mpFloatWin->GetPosPixel();
+ pWrapper->mbDockBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_DOCKING );
+ pWrapper->mbHideBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_HIDE );
+ pWrapper->mbPined = mpFloatWin->IsPined();
+ pWrapper->mbRollUp = mpFloatWin->IsRollUp();
+ pWrapper->maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel();
+ pWrapper->maMinOutSize = mpFloatWin->GetMinOutputSizePixel();
+
+ Window* pRealParent = mpWindowImpl->mpRealParent;
+ mpWindowImpl->mpBorderWindow = NULL;
+ if ( pWrapper->mpOldBorderWin )
+ {
+ SetParent( pWrapper->mpOldBorderWin );
+ ((ImplBorderWindow*)pWrapper->mpOldBorderWin)->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ pWrapper->mpOldBorderWin->Resize();
+ }
+ mpWindowImpl->mpBorderWindow = pWrapper->mpOldBorderWin;
+ SetParent( pRealParent );
+ mpWindowImpl->mpRealParent = pRealParent;
+ delete static_cast<ImplDockFloatWin*>(mpFloatWin);
+ pWrapper->mpFloatWin = NULL;
+ SetPosPixel( maDockPos );
+
+ pWrapper->ToggleFloatingMode();
+
+ if ( bVisible )
+ Show();
+ }
+ }
+ }
+}
+*/
+
+DockingManager* Window::GetDockingManager()
+{
+ return ImplGetDockingManager();
+}
+
+void Window::EnableDocking( BOOL bEnable )
+{
+ // update list of dockable windows
+ if( bEnable )
+ ImplGetDockingManager()->AddWindow( this );
+ else
+ ImplGetDockingManager()->RemoveWindow( this );
+}
+
+
+// retrieves the list of owner draw decorated windows for this window hiearchy
+::std::vector<Window *>& Window::ImplGetOwnerDrawList()
+{
+ return ImplGetTopmostFrameWindow()->mpWindowImpl->mpFrameData->maOwnerDrawList;
+}
+
+Window* Window::ImplGetTopmostFrameWindow()
+{
+ Window *pTopmostParent = this;
+ while( pTopmostParent->ImplGetParent() )
+ pTopmostParent = pTopmostParent->ImplGetParent();
+ return pTopmostParent->mpWindowImpl->mpFrameWindow;
+}
+
+// making these Methods out of line to be able to change them lateron without complete rebuild
+// TODO: Set the SmartId in here and remove mpWindowImpl->mnHelpId
+void Window::SetHelpId( ULONG nHelpId )
+{
+ SetSmartHelpId(SmartId(nHelpId));
+}
+
+ULONG Window::GetHelpId() const
+{
+ return mpWindowImpl->mnHelpId;
+}
+
+void Window::SetSmartHelpId( const SmartId& aId, SmartIdUpdateMode aMode )
+{
+ // create SmartId if required
+ if ( (aMode == SMART_SET_STR) || (aMode == SMART_SET_ALL) || ( (aMode == SMART_SET_SMART) && aId.HasString() ) )
+ {
+ if ( !ImplGetWinData()->mpSmartHelpId )
+ ImplGetWinData()->mpSmartHelpId = new SmartId();
+ }
+
+ // if we have a SmartId (eather from earlier call or just created) fill with new values
+ if ( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mpSmartHelpId )
+ ImplGetWinData()->mpSmartHelpId->UpdateId( aId, aMode );
+
+ if ( (aMode == SMART_SET_NUM) || (aMode == SMART_SET_ALL) || ( (aMode == SMART_SET_SMART) && aId.HasNumeric() ) )
+ {
+ mpWindowImpl->mnHelpId = aId.GetNum();
+ }
+}
+
+SmartId Window::GetSmartHelpId() const
+{
+ if ( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mpSmartHelpId )
+ {
+ if ( mpWindowImpl->mnHelpId || mpWindowImpl->mpWinData->mpSmartHelpId->HasNumeric() )
+ mpWindowImpl->mpWinData->mpSmartHelpId->UpdateId( SmartId( mpWindowImpl->mnHelpId ), SMART_SET_NUM );
+ return *mpWindowImpl->mpWinData->mpSmartHelpId;
+ }
+ else
+ {
+ if ( mpWindowImpl->mnHelpId )
+ return SmartId( mpWindowImpl->mnHelpId );
+ else
+ return SmartId();
+ }
+}
+
+
+// making these Methods out of line to be able to change them lateron without complete rebuild
+// TODO: Set the SmartId in here and remove mpWindowImpl->mnUniqId
+void Window::SetUniqueId( ULONG nUniqueId ) { mpWindowImpl->mnUniqId = nUniqueId; }
+ULONG Window::GetUniqueId() const { return mpWindowImpl->mnUniqId; }
+
+
+void Window::SetSmartUniqueId( const SmartId& aId, SmartIdUpdateMode aMode )
+{
+ // create SmartId if required
+ if ( (aMode == SMART_SET_STR) || (aMode == SMART_SET_ALL) || ( (aMode == SMART_SET_SMART) && aId.HasString() ) )
+ {
+ if ( !ImplGetWinData()->mpSmartUniqueId )
+ ImplGetWinData()->mpSmartUniqueId = new SmartId();
+ }
+
+ // if we have a SmartId (eather from earlier call or just created) fill with new values
+ if ( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mpSmartUniqueId )
+ ImplGetWinData()->mpSmartUniqueId->UpdateId( aId, aMode );
+
+ if ( (aMode == SMART_SET_NUM) || (aMode == SMART_SET_ALL) || ( (aMode == SMART_SET_SMART) && aId.HasNumeric() ) )
+ mpWindowImpl->mnUniqId = aId.GetNum();
+}
+
+SmartId Window::GetSmartUniqueId() const
+{
+ if ( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mpSmartUniqueId )
+ {
+ if ( mpWindowImpl->mnUniqId || mpWindowImpl->mpWinData->mpSmartUniqueId->HasNumeric() )
+ mpWindowImpl->mpWinData->mpSmartUniqueId->UpdateId( SmartId( mpWindowImpl->mnUniqId ), SMART_SET_NUM );
+ return *mpWindowImpl->mpWinData->mpSmartUniqueId;
+ }
+ else
+ {
+ if ( mpWindowImpl->mnUniqId )
+ return SmartId( mpWindowImpl->mnUniqId );
+ else
+ return SmartId();
+ }
+}
+
+SmartId Window::GetSmartUniqueOrHelpId() const
+{
+ if ( ( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mpSmartHelpId ) || mpWindowImpl->mnHelpId )
+ {
+ if ( ( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mpSmartUniqueId ) || mpWindowImpl->mnUniqId )
+ {
+ SmartId aTemp = GetSmartHelpId();
+ aTemp.UpdateId( GetSmartUniqueId() );
+ return aTemp;
+ }
+ else
+ return GetSmartHelpId();
+ }
+ else
+ return GetSmartUniqueId();
+}
+
+
+
+
+// --------- old inline methods ---------------
+
+Window* Window::ImplGetWindow()
+{
+ if ( mpWindowImpl->mpClientWindow )
+ return mpWindowImpl->mpClientWindow;
+ else
+ return this;
+}
+
+ImplFrameData* Window::ImplGetFrameData()
+{
+ return mpWindowImpl->mpFrameData;
+}
+
+SalFrame* Window::ImplGetFrame() const
+{
+ return mpWindowImpl->mpFrame;
+}
+
+Window* Window::ImplGetParent() const
+{
+ return mpWindowImpl->mpParent;
+}
+
+Window* Window::ImplGetClientWindow() const
+{
+ return mpWindowImpl->mpClientWindow;
+}
+
+Window* Window::ImplGetBorderWindow() const
+{
+ return mpWindowImpl->mpBorderWindow;
+}
+
+Window* Window::ImplGetFirstOverlapWindow()
+{
+ if ( mpWindowImpl->mbOverlapWin )
+ return this;
+ else
+ return mpWindowImpl->mpOverlapWindow;
+}
+
+const Window* Window::ImplGetFirstOverlapWindow() const
+{
+ if ( mpWindowImpl->mbOverlapWin )
+ return this;
+ else
+ return mpWindowImpl->mpOverlapWindow;
+}
+
+Window* Window::ImplGetFrameWindow() const
+{
+ return mpWindowImpl->mpFrameWindow;
+}
+
+BOOL Window::ImplIsDockingWindow() const
+{
+ return mpWindowImpl->mbDockWin;
+}
+
+BOOL Window::ImplIsFloatingWindow() const
+{
+ return mpWindowImpl->mbFloatWin;
+}
+
+BOOL Window::ImplIsToolbox() const
+{
+ return mpWindowImpl->mbToolBox;
+}
+
+BOOL Window::ImplIsSplitter() const
+{
+ return mpWindowImpl->mbSplitter;
+}
+
+BOOL Window::ImplIsPushButton() const
+{
+ return mpWindowImpl->mbPushButton;
+}
+
+BOOL Window::ImplIsOverlapWindow() const
+{
+ return mpWindowImpl->mbOverlapWin;
+}
+
+void Window::ImplSetActive( BOOL bActive )
+{
+ mpWindowImpl->mbActive = bActive;
+}
+
+BOOL Window::ImplIsMouseTransparent() const
+{
+ return mpWindowImpl->mbMouseTransparent;
+}
+
+void Window::ImplSetMouseTransparent( BOOL bTransparent )
+{
+ mpWindowImpl->mbMouseTransparent = bTransparent;
+}
+
+Point Window::ImplOutputToFrame( const Point& rPos )
+{
+ return Point( rPos.X()+mnOutOffX, rPos.Y()+mnOutOffY );
+}
+
+Point Window::ImplFrameToOutput( const Point& rPos )
+{
+ return Point( rPos.X()-mnOutOffX, rPos.Y()-mnOutOffY );
+}
+
+void Window::ImplOutputToFrame( Rectangle& rRect )
+{
+ rRect.Left()+=mnOutOffX;
+ rRect.Top()+=mnOutOffY;
+ rRect.Right()+=mnOutOffX;
+ rRect.Bottom()+=mnOutOffY;
+}
+
+void Window::ImplFrameToOutput( Rectangle& rRect )
+{
+ rRect.Left()-=mnOutOffX;
+ rRect.Top()-=mnOutOffY;
+ rRect.Right()-=mnOutOffX;
+ rRect.Bottom()-=mnOutOffY;
+}
+
+void Window::SetCompoundControl( BOOL bCompound )
+{
+ mpWindowImpl->mbCompoundControl = bCompound;
+}
+
+void Window::IncrementLockCount()
+{
+ mpWindowImpl->mnLockCount++;
+}
+
+void Window::DecrementLockCount()
+{
+ mpWindowImpl->mnLockCount--;
+}
+
+WinBits Window::GetStyle() const
+{
+ return mpWindowImpl->mnStyle;
+}
+
+WinBits Window::GetPrevStyle() const
+{
+ return mpWindowImpl->mnPrevStyle;
+}
+
+WinBits Window::GetExtendedStyle() const
+{
+ return mpWindowImpl->mnExtendedStyle;
+}
+
+WinBits Window::GetPrevExtendedStyle() const
+{
+ return mpWindowImpl->mnExtendedStyle;
+}
+
+void Window::SetType( WindowType nType )
+{
+ mpWindowImpl->mnType = nType;
+}
+
+WindowType Window::GetType() const
+{
+ return mpWindowImpl->mnType;
+}
+BOOL Window::IsSystemWindow() const
+{
+ return mpWindowImpl->mbSysWin;
+}
+
+BOOL Window::IsDialog() const
+{
+ return mpWindowImpl->mbDialog;
+}
+
+BOOL Window::IsMenuFloatingWindow() const
+{
+ return mpWindowImpl->mbMenuFloatingWindow;
+}
+
+BOOL Window::IsToolbarFloatingWindow() const
+{
+ return mpWindowImpl->mbToolbarFloatingWindow;
+}
+
+void Window::EnableAllResize( BOOL bEnable )
+{
+ mpWindowImpl->mbAllResize = bEnable;
+}
+
+BOOL Window::IsAllResizeEnabled() const
+{
+ return mpWindowImpl->mbAllResize;
+}
+
+BOOL Window::IsClipSiblingsEnabled() const
+{
+ return mpWindowImpl->mbClipSiblings;
+}
+
+void Window::EnableChildTransparentMode( BOOL bEnable )
+{
+ mpWindowImpl->mbChildTransparent = bEnable;
+}
+
+BOOL Window::IsChildTransparentModeEnabled() const
+{
+ return mpWindowImpl->mbChildTransparent;
+}
+
+BOOL Window::IsMouseTransparent() const
+{
+ return mpWindowImpl->mbMouseTransparent;
+}
+
+BOOL Window::IsPaintTransparent() const
+{
+ return mpWindowImpl->mbPaintTransparent;
+}
+
+void Window::SetDialogControlStart( BOOL bStart )
+{
+ mpWindowImpl->mbDlgCtrlStart = bStart;
+}
+
+BOOL Window::IsDialogControlStart() const
+{
+ return mpWindowImpl->mbDlgCtrlStart;
+}
+
+void Window::SetDialogControlFlags( USHORT nFlags )
+{
+ mpWindowImpl->mnDlgCtrlFlags = nFlags;
+}
+
+USHORT Window::GetDialogControlFlags() const
+{
+ return mpWindowImpl->mnDlgCtrlFlags;
+}
+
+const InputContext& Window::GetInputContext() const
+{
+ return mpWindowImpl->maInputContext;
+}
+
+BOOL Window::IsExtTextInput() const
+{
+ return mpWindowImpl->mbExtTextInput;
+}
+
+void Window::EnableChildNotify( BOOL bEnable )
+{
+ mpWindowImpl->mbChildNotify = bEnable;
+}
+
+BOOL Window::IsChildNotify() const
+{
+ return mpWindowImpl->mbChildNotify;
+}
+
+BOOL Window::IsControlFont() const
+{
+ return (mpWindowImpl->mpControlFont != 0);
+}
+
+Color Window::GetControlForeground() const
+{
+ return mpWindowImpl->maControlForeground;
+}
+
+BOOL Window::IsControlForeground() const
+{
+ return mpWindowImpl->mbControlForeground;
+}
+
+Color Window::GetControlBackground() const
+{
+ return mpWindowImpl->maControlBackground;
+}
+
+BOOL Window::IsControlBackground() const
+{
+ return mpWindowImpl->mbControlBackground;
+}
+
+BOOL Window::IsInPaint() const
+{
+ return mpWindowImpl->mbInPaint;
+}
+
+Window* Window::GetParent() const
+{
+ return mpWindowImpl->mpRealParent;
+}
+
+BOOL Window::IsVisible() const
+{
+ return mpWindowImpl->mbVisible;
+}
+
+BOOL Window::IsReallyVisible() const
+{
+ return mpWindowImpl->mbReallyVisible;
+}
+
+BOOL Window::IsParentPathVisible() const
+{
+ return mpWindowImpl->mbReallyVisible;
+}
+
+BOOL Window::IsReallyShown() const
+{
+ return mpWindowImpl->mbReallyShown;
+}
+
+BOOL Window::IsInInitShow() const
+{
+ return mpWindowImpl->mbInInitShow;
+}
+
+BOOL Window::IsEnabled() const
+{
+ return !mpWindowImpl->mbDisabled;
+}
+
+BOOL Window::IsInputEnabled() const
+{
+ return !mpWindowImpl->mbInputDisabled;
+}
+
+BOOL Window::IsAlwaysEnableInput() const
+{
+ return mpWindowImpl->meAlwaysInputMode == AlwaysInputEnabled;
+}
+
+BOOL Window::IsAlwaysDisableInput() const
+{
+ return mpWindowImpl->meAlwaysInputMode == AlwaysInputDisabled;
+}
+
+USHORT Window::GetActivateMode() const
+{
+ return mpWindowImpl->mnActivateMode;
+
+}
+
+BOOL Window::IsAlwaysOnTopEnabled() const
+{
+ return mpWindowImpl->mbAlwaysOnTop;
+}
+
+BOOL Window::IsDefaultPos() const
+{
+ return mpWindowImpl->mbDefPos;
+}
+
+BOOL Window::IsDefaultSize() const
+{
+ return mpWindowImpl->mbDefSize;
+}
+
+void Window::EnablePaint( BOOL bEnable )
+{
+ mpWindowImpl->mbPaintDisabled = !bEnable;
+}
+
+BOOL Window::IsPaintEnabled() const
+{
+ return !mpWindowImpl->mbPaintDisabled;
+}
+
+BOOL Window::IsUpdateMode() const
+{
+ return !mpWindowImpl->mbNoUpdate;
+}
+
+void Window::SetParentUpdateMode( BOOL bUpdate )
+{
+ mpWindowImpl->mbNoParentUpdate = !bUpdate;
+}
+
+BOOL Window::IsParentUpdateMode() const
+{
+ return !mpWindowImpl->mbNoParentUpdate;
+}
+
+BOOL Window::IsActive() const
+{
+ return mpWindowImpl->mbActive;
+}
+
+USHORT Window::GetGetFocusFlags() const
+{
+ return mpWindowImpl->mnGetFocusFlags;
+}
+
+BOOL Window::IsCompoundControl() const
+{
+ return mpWindowImpl->mbCompoundControl;
+}
+
+BOOL Window::HasCompoundControlFocus() const
+{
+ return mpWindowImpl->mbCompoundControlHasFocus;
+}
+
+BOOL Window::IsChildPointerOverwrite() const
+{
+ return mpWindowImpl->mbChildPtrOverwrite;
+}
+
+BOOL Window::IsPointerVisible() const
+{
+ return !mpWindowImpl->mbNoPtrVisible;
+}
+
+BOOL Window::IsWait() const
+{
+ return (mpWindowImpl->mnWaitCount != 0);
+}
+
+Cursor* Window::GetCursor() const
+{
+ return mpWindowImpl->mpCursor;
+}
+
+const Fraction& Window::GetZoom() const
+{
+ return mpWindowImpl->maZoom;
+}
+
+BOOL Window::IsZoom() const
+{
+ return mpWindowImpl->maZoom.GetNumerator() != mpWindowImpl->maZoom.GetDenominator();
+}
+
+void Window::SetHelpText( const XubString& rHelpText )
+{
+ mpWindowImpl->maHelpText = rHelpText;
+ mpWindowImpl->mbHelpTextDynamic = TRUE;
+}
+
+void Window::SetQuickHelpText( const XubString& rHelpText )
+{
+ mpWindowImpl->maQuickHelpText = rHelpText;
+}
+
+const XubString& Window::GetQuickHelpText() const
+{
+ return mpWindowImpl->maQuickHelpText;
+}
+
+void Window::SetData( void* pNewData )
+{
+ mpWindowImpl->mpUserData = pNewData;
+}
+
+void* Window::GetData() const
+{
+ return mpWindowImpl->mpUserData;
+}
+
+BOOL Window::IsCreatedWithToolkit() const
+{
+ return mpWindowImpl->mbCreatedWithToolkit;
+}
+
+void Window::SetCreatedWithToolkit( BOOL b )
+{
+ mpWindowImpl->mbCreatedWithToolkit = b;
+
+}
+const Pointer& Window::GetPointer() const
+{
+ return mpWindowImpl->maPointer;
+}
+
+VCLXWindow* Window::GetWindowPeer() const
+{
+ return mpWindowImpl->mpVCLXWindow;
+}
+
+void Window::SetPosPixel( const Point& rNewPos )
+{
+ SetPosSizePixel( rNewPos.X(), rNewPos.Y(), 0, 0, WINDOW_POSSIZE_POS );
+}
+
+void Window::SetSizePixel( const Size& rNewSize )
+{
+ SetPosSizePixel( 0, 0, rNewSize.Width(), rNewSize.Height(),
+ WINDOW_POSSIZE_SIZE );
+}
+
+void Window::SetPosSizePixel( const Point& rNewPos, const Size& rNewSize )
+{
+ SetPosSizePixel( rNewPos.X(), rNewPos.Y(),
+ rNewSize.Width(), rNewSize.Height(),
+ WINDOW_POSSIZE_POSSIZE );
+}
+
+void Window::SetOutputSizePixel( const Size& rNewSize )
+{
+ SetSizePixel( Size( rNewSize.Width()+mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder,
+ rNewSize.Height()+mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder ) );
+}
+
diff --git a/vcl/source/window/window3.cxx b/vcl/source/window/window3.cxx
new file mode 100644
index 000000000000..65019ba2a4af
--- /dev/null
+++ b/vcl/source/window/window3.cxx
@@ -0,0 +1,82 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/window.hxx"
+#include "vcl/waitobj.hxx"
+#include "vcl/button.hxx"
+
+// -----------------------------------------------------------------------
+
+WaitObject::~WaitObject()
+{
+ if ( mpWindow )
+ mpWindow->LeaveWait();
+}
+
+// -----------------------------------------------------------------------
+
+Size Window::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return Size();
+ case WINDOWSIZE_PREFERRED:
+ return GetOptimalSize( WINDOWSIZE_MINIMUM );
+ case WINDOWSIZE_MAXIMUM:
+ default:
+ return Size( LONG_MAX, LONG_MAX );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Window::ImplAdjustNWFSizes()
+{
+ switch( GetType() )
+ {
+ case WINDOW_CHECKBOX:
+ ((CheckBox*)this)->ImplSetMinimumNWFSize();
+ break;
+ case WINDOW_RADIOBUTTON:
+ ((RadioButton*)this)->ImplSetMinimumNWFSize();
+ break;
+ default:
+ {
+ // iterate over children
+ Window* pWin = GetWindow( WINDOW_FIRSTCHILD );
+ while( pWin )
+ {
+ pWin->ImplAdjustNWFSizes();
+ pWin = pWin->GetWindow( WINDOW_NEXT );
+ }
+ }
+ break;
+ }
+}
diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx
new file mode 100644
index 000000000000..c964ad0d739b
--- /dev/null
+++ b/vcl/source/window/winproc.cxx
@@ -0,0 +1,2618 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salwtype.hxx>
+#include <vcl/salframe.hxx>
+#include <tools/debug.hxx>
+#ifndef _INTN_HXX
+//#include <tools/intn.hxx>
+#endif
+#include <vcl/i18nhelp.hxx>
+#include <vcl/unohelp.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/dbggui.hxx>
+#include <vcl/windata.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/event.hxx>
+#include <vcl/sound.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/accmgr.hxx>
+#include <vcl/print.h>
+#include <vcl/window.h>
+#include <vcl/wrkwin.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/dialog.hxx>
+#include <vcl/help.hxx>
+#include <vcl/helpwin.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/dockwin.hxx>
+#include <vcl/salgdi.hxx>
+#include <vcl/menu.hxx>
+
+#include <vcl/dndlcon.hxx>
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+
+#if OSL_DEBUG_LEVEL > 1
+char dbgbuffer[1024];
+#ifndef WNT
+#include <stdio.h>
+#define MyOutputDebugString(s) (fprintf(stderr, s ))
+#else
+extern void MyOutputDebugString( char *s);
+#endif
+#endif
+
+
+// =======================================================================
+
+#define IMPL_MIN_NEEDSYSWIN 49
+
+// =======================================================================
+
+long ImplCallPreNotify( NotifyEvent& rEvt )
+{
+ long nRet = Application::CallEventHooks( rEvt );
+ if ( !nRet )
+ nRet = rEvt.GetWindow()->PreNotify( rEvt );
+ return nRet;
+}
+
+// =======================================================================
+
+long ImplCallEvent( NotifyEvent& rEvt )
+{
+ long nRet = ImplCallPreNotify( rEvt );
+ if ( !nRet )
+ {
+ Window* pWindow = rEvt.GetWindow();
+ switch ( rEvt.GetType() )
+ {
+ case EVENT_MOUSEBUTTONDOWN:
+ pWindow->MouseButtonDown( *rEvt.GetMouseEvent() );
+ break;
+ case EVENT_MOUSEBUTTONUP:
+ pWindow->MouseButtonUp( *rEvt.GetMouseEvent() );
+ break;
+ case EVENT_MOUSEMOVE:
+ pWindow->MouseMove( *rEvt.GetMouseEvent() );
+ break;
+ case EVENT_KEYINPUT:
+ pWindow->KeyInput( *rEvt.GetKeyEvent() );
+ break;
+ case EVENT_KEYUP:
+ pWindow->KeyUp( *rEvt.GetKeyEvent() );
+ break;
+ case EVENT_GETFOCUS:
+ pWindow->GetFocus();
+ break;
+ case EVENT_LOSEFOCUS:
+ pWindow->LoseFocus();
+ break;
+ case EVENT_COMMAND:
+ pWindow->Command( *rEvt.GetCommandEvent() );
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+// =======================================================================
+
+static BOOL ImplHandleMouseFloatMode( Window* pChild, const Point& rMousePos,
+ USHORT nCode, USHORT nSVEvent,
+ BOOL bMouseLeave )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maWinData.mpFirstFloat && !pSVData->maWinData.mpCaptureWin &&
+ !pSVData->maWinData.mpFirstFloat->ImplIsFloatPopupModeWindow( pChild ) )
+ {
+ /*
+ * #93895# since floats are system windows, coordinates have
+ * to be converted to float relative for the hittest
+ */
+ USHORT nHitTest = IMPL_FLOATWIN_HITTEST_OUTSIDE;
+ FloatingWindow* pFloat = pSVData->maWinData.mpFirstFloat->ImplFloatHitTest( pChild, rMousePos, nHitTest );
+ FloatingWindow* pLastLevelFloat;
+ ULONG nPopupFlags;
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ {
+ if ( bMouseLeave )
+ return TRUE;
+
+ if ( !pFloat || (nHitTest & IMPL_FLOATWIN_HITTEST_RECT) )
+ {
+ if ( pSVData->maHelpData.mpHelpWin && !pSVData->maHelpData.mbKeyboardHelp )
+ ImplDestroyHelpWindow( true );
+ pChild->ImplGetFrame()->SetPointer( POINTER_ARROW );
+ return TRUE;
+ }
+ }
+ else
+ {
+ if ( nCode & MOUSE_LEFT )
+ {
+ if ( nSVEvent == EVENT_MOUSEBUTTONDOWN )
+ {
+ if ( !pFloat )
+ {
+ pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ nPopupFlags = pLastLevelFloat->GetPopupModeFlags();
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+// Erstmal ausgebaut als Hack fuer Bug 53378
+// if ( nPopupFlags & FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK )
+// return FALSE;
+// else
+ return TRUE;
+ }
+ else if ( nHitTest & IMPL_FLOATWIN_HITTEST_RECT )
+ {
+ if ( !(pFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOMOUSERECTCLOSE) )
+ pFloat->ImplSetMouseDown();
+ return TRUE;
+ }
+ }
+ else
+ {
+ if ( pFloat )
+ {
+ if ( nHitTest & IMPL_FLOATWIN_HITTEST_RECT )
+ {
+ if ( pFloat->ImplIsMouseDown() )
+ pFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL );
+ return TRUE;
+ }
+ }
+ else
+ {
+ pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ nPopupFlags = pLastLevelFloat->GetPopupModeFlags();
+ if ( !(nPopupFlags & FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE) )
+ {
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ return TRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( !pFloat )
+ {
+ pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ nPopupFlags = pLastLevelFloat->GetPopupModeFlags();
+ if ( nPopupFlags & FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE )
+ {
+ if ( (nPopupFlags & FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE) &&
+ (nSVEvent == EVENT_MOUSEBUTTONUP) )
+ return TRUE;
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ if ( nPopupFlags & FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK )
+ return FALSE;
+ else
+ return TRUE;
+ }
+ else
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleMouseHelpRequest( Window* pChild, const Point& rMousePos )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maHelpData.mpHelpWin ||
+ !( pSVData->maHelpData.mpHelpWin->IsWindowOrChild( pChild ) ||
+ pChild->IsWindowOrChild( pSVData->maHelpData.mpHelpWin ) ) )
+ {
+ USHORT nHelpMode = 0;
+ if ( pSVData->maHelpData.mbQuickHelp )
+ nHelpMode = HELPMODE_QUICK;
+ if ( pSVData->maHelpData.mbBalloonHelp )
+ nHelpMode |= HELPMODE_BALLOON;
+ if ( nHelpMode )
+ {
+ if ( pChild->IsInputEnabled() && ! pChild->IsInModalMode() )
+ {
+ HelpEvent aHelpEvent( rMousePos, nHelpMode );
+ pSVData->maHelpData.mbRequestingHelp = TRUE;
+ pChild->RequestHelp( aHelpEvent );
+ pSVData->maHelpData.mbRequestingHelp = FALSE;
+ }
+ // #104172# do not kill keyboard activated tooltips
+ else if ( pSVData->maHelpData.mpHelpWin && !pSVData->maHelpData.mbKeyboardHelp)
+ {
+ ImplDestroyHelpWindow( true );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSetMousePointer( Window* pChild )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maHelpData.mbExtHelpMode )
+ pChild->ImplGetFrame()->SetPointer( POINTER_HELP );
+ else
+ pChild->ImplGetFrame()->SetPointer( pChild->ImplGetMousePointer() );
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplCallCommand( Window* pChild, USHORT nEvt, void* pData = NULL,
+ BOOL bMouse = FALSE, Point* pPos = NULL )
+{
+ Point aPos;
+ if ( pPos )
+ aPos = *pPos;
+ else
+ {
+ if( bMouse )
+ aPos = pChild->GetPointerPosPixel();
+ else
+ {
+ // simulate mouseposition at center of window
+ Size aSize( pChild->GetOutputSizePixel() );
+ aPos = Point( aSize.getWidth()/2, aSize.getHeight()/2 );
+ }
+ }
+
+ CommandEvent aCEvt( aPos, nEvt, bMouse, pData );
+ NotifyEvent aNCmdEvt( EVENT_COMMAND, pChild, &aCEvt );
+ ImplDelData aDelData( pChild );
+ BOOL bPreNotify = (ImplCallPreNotify( aNCmdEvt ) != 0);
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ if ( !bPreNotify )
+ {
+ pChild->ImplGetWindowImpl()->mbCommand = FALSE;
+ pChild->Command( aCEvt );
+
+ if( aDelData.IsDelete() )
+ return FALSE;
+ pChild->ImplNotifyKeyMouseCommandEventListeners( aNCmdEvt );
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ if ( pChild->ImplGetWindowImpl()->mbCommand )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+/* #i34277# delayed context menu activation;
+* necessary if there already was a popup menu running.
+*/
+
+struct ContextMenuEvent
+{
+ Window* pWindow;
+ ImplDelData aDelData;
+ Point aChildPos;
+};
+
+static long ContextMenuEventLink( void* pCEvent, void* )
+{
+ ContextMenuEvent* pEv = (ContextMenuEvent*)pCEvent;
+
+ if( ! pEv->aDelData.IsDelete() )
+ {
+ pEv->pWindow->ImplRemoveDel( &pEv->aDelData );
+ ImplCallCommand( pEv->pWindow, COMMAND_CONTEXTMENU, NULL, TRUE, &pEv->aChildPos );
+ }
+ delete pEv;
+
+ return 0;
+}
+
+long ImplHandleMouseEvent( Window* pWindow, USHORT nSVEvent, BOOL bMouseLeave,
+ long nX, long nY, ULONG nMsgTime,
+ USHORT nCode, USHORT nMode )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Point aMousePos( nX, nY );
+ Window* pChild;
+ long nRet;
+ USHORT nClicks;
+ ImplFrameData* pWinFrameData = pWindow->ImplGetFrameData();
+ USHORT nOldCode = pWinFrameData->mnMouseCode;
+
+ // we need a mousemove event, befor we get a mousebuttondown or a
+ // mousebuttonup event
+ if ( (nSVEvent == EVENT_MOUSEBUTTONDOWN) ||
+ (nSVEvent == EVENT_MOUSEBUTTONUP) )
+ {
+ if ( (nSVEvent == EVENT_MOUSEBUTTONUP) && pSVData->maHelpData.mbExtHelpMode )
+ Help::EndExtHelp();
+ if ( pSVData->maHelpData.mpHelpWin )
+ {
+ if( pWindow->ImplGetWindow() == pSVData->maHelpData.mpHelpWin )
+ {
+ ImplDestroyHelpWindow( false );
+ return 1; // pWindow is dead now - avoid crash!
+ }
+ else
+ ImplDestroyHelpWindow( true );
+ }
+
+ if ( (pWinFrameData->mnLastMouseX != nX) ||
+ (pWinFrameData->mnLastMouseY != nY) )
+ {
+ ImplHandleMouseEvent( pWindow, EVENT_MOUSEMOVE, FALSE, nX, nY, nMsgTime, nCode, nMode );
+ }
+ }
+
+ // update frame data
+ pWinFrameData->mnBeforeLastMouseX = pWinFrameData->mnLastMouseX;
+ pWinFrameData->mnBeforeLastMouseY = pWinFrameData->mnLastMouseY;
+ pWinFrameData->mnLastMouseX = nX;
+ pWinFrameData->mnLastMouseY = nY;
+ pWinFrameData->mnMouseCode = nCode;
+ pWinFrameData->mnMouseMode = nMode & ~(MOUSE_SYNTHETIC | MOUSE_MODIFIERCHANGED);
+ if ( bMouseLeave )
+ {
+ pWinFrameData->mbMouseIn = FALSE;
+ if ( pSVData->maHelpData.mpHelpWin && !pSVData->maHelpData.mbKeyboardHelp )
+ {
+ ImplDelData aDelData( pWindow );
+
+ ImplDestroyHelpWindow( true );
+
+ if ( aDelData.IsDelete() )
+ return 1; // pWindow is dead now - avoid crash! (#122045#)
+ }
+ }
+ else
+ pWinFrameData->mbMouseIn = TRUE;
+
+ DBG_ASSERT( !pSVData->maWinData.mpTrackWin ||
+ (pSVData->maWinData.mpTrackWin == pSVData->maWinData.mpCaptureWin),
+ "ImplHandleMouseEvent: TrackWin != CaptureWin" );
+
+ // AutoScrollMode
+ if ( pSVData->maWinData.mpAutoScrollWin && (nSVEvent == EVENT_MOUSEBUTTONDOWN) )
+ {
+ pSVData->maWinData.mpAutoScrollWin->EndAutoScroll();
+ return 1;
+ }
+
+ // find mouse window
+ if ( pSVData->maWinData.mpCaptureWin )
+ {
+ pChild = pSVData->maWinData.mpCaptureWin;
+
+ DBG_ASSERT( pWindow == pChild->ImplGetFrameWindow(),
+ "ImplHandleMouseEvent: mouse event is not sent to capture window" );
+
+ // java client cannot capture mouse correctly
+ if ( pWindow != pChild->ImplGetFrameWindow() )
+ return 0;
+
+ if ( bMouseLeave )
+ return 0;
+ }
+ else
+ {
+ if ( bMouseLeave )
+ pChild = NULL;
+ else
+ pChild = pWindow->ImplFindWindow( aMousePos );
+ }
+
+ // test this because mouse events are buffered in the remote version
+ // and size may not be in sync
+ if ( !pChild && !bMouseLeave )
+ return 0;
+
+ // Ein paar Test ausfuehren und Message abfangen oder Status umsetzen
+ if ( pChild )
+ {
+ if( pChild->ImplIsAntiparallel() )
+ {
+ // - RTL - re-mirror frame pos at pChild
+ pChild->ImplReMirror( aMousePos );
+ }
+ // no mouse messages to system object windows ?
+ // !!!KA: Is it OK to comment this out? !!!
+// if ( pChild->ImplGetWindowImpl()->mpSysObj )
+// return 0;
+
+ // no mouse messages to disabled windows
+ // #106845# if the window was disabed during capturing we have to pass the mouse events to release capturing
+ if ( pSVData->maWinData.mpCaptureWin != pChild && (!pChild->IsEnabled() || !pChild->IsInputEnabled() || pChild->IsInModalMode() ) )
+ {
+ ImplHandleMouseFloatMode( pChild, aMousePos, nCode, nSVEvent, bMouseLeave );
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ {
+ ImplHandleMouseHelpRequest( pChild, aMousePos );
+ if( pWinFrameData->mpMouseMoveWin != pChild )
+ nMode |= MOUSE_ENTERWINDOW;
+ }
+
+ // Call the hook also, if Window is disabled
+ Point aChildPos = pChild->ImplFrameToOutput( aMousePos );
+ MouseEvent aMEvt( aChildPos, pWinFrameData->mnClickCount, nMode, nCode, nCode );
+ NotifyEvent aNEvt( nSVEvent, pChild, &aMEvt );
+ Application::CallEventHooks( aNEvt );
+
+ if( pChild->IsCallHandlersOnInputDisabled() )
+ {
+ pWinFrameData->mpMouseMoveWin = pChild;
+ pChild->ImplNotifyKeyMouseCommandEventListeners( aNEvt );
+ }
+
+ if ( nSVEvent == EVENT_MOUSEBUTTONDOWN )
+ {
+ Sound::Beep( SOUND_DISABLE, pChild );
+ return 1;
+ }
+ else
+ {
+ // Set normal MousePointer for disabled windows
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ ImplSetMousePointer( pChild );
+
+ return 0;
+ }
+ }
+
+ // End ExtTextInput-Mode, if the user click in the same TopLevel Window
+ if ( pSVData->maWinData.mpExtTextInputWin &&
+ ((nSVEvent == EVENT_MOUSEBUTTONDOWN) ||
+ (nSVEvent == EVENT_MOUSEBUTTONUP)) )
+ pSVData->maWinData.mpExtTextInputWin->EndExtTextInput( EXTTEXTINPUT_END_COMPLETE );
+ }
+
+ // determine mouse event data
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ {
+ // Testen, ob MouseMove an das gleiche Fenster geht und sich der
+ // Status nicht geaendert hat
+ if ( pChild )
+ {
+ Point aChildMousePos = pChild->ImplFrameToOutput( aMousePos );
+ if ( !bMouseLeave &&
+ (pChild == pWinFrameData->mpMouseMoveWin) &&
+ (aChildMousePos.X() == pWinFrameData->mnLastMouseWinX) &&
+ (aChildMousePos.Y() == pWinFrameData->mnLastMouseWinY) &&
+ (nOldCode == pWinFrameData->mnMouseCode) )
+ {
+ // Mouse-Pointer neu setzen, da er sich geaendet haben
+ // koennte, da ein Modus umgesetzt wurde
+ ImplSetMousePointer( pChild );
+ return 0;
+ }
+
+ pWinFrameData->mnLastMouseWinX = aChildMousePos.X();
+ pWinFrameData->mnLastMouseWinY = aChildMousePos.Y();
+ }
+
+ // mouse click
+ nClicks = pWinFrameData->mnClickCount;
+
+ // Gegebenenfalls den Start-Drag-Handler rufen.
+ // Achtung: Muss vor Move gerufen werden, da sonst bei schnellen
+ // Mausbewegungen die Applikationen in den Selektionszustand gehen.
+ Window* pMouseDownWin = pWinFrameData->mpMouseDownWin;
+ if ( pMouseDownWin )
+ {
+ // Testen, ob StartDrag-Modus uebereinstimmt. Wir vergleichen nur
+ // den Status der Maustasten, damit man mit Mod1 z.B. sofort
+ // in den Kopiermodus gehen kann.
+ const MouseSettings& rMSettings = pMouseDownWin->GetSettings().GetMouseSettings();
+ if ( (nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ==
+ (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) )
+ {
+ if ( !pMouseDownWin->ImplGetFrameData()->mbStartDragCalled )
+ {
+ long nDragW = rMSettings.GetStartDragWidth();
+ long nDragH = rMSettings.GetStartDragWidth();
+ //long nMouseX = nX;
+ //long nMouseY = nY;
+ long nMouseX = aMousePos.X(); // #106074# use the possibly re-mirrored coordinates (RTL) ! nX,nY are unmodified !
+ long nMouseY = aMousePos.Y();
+ if ( !(((nMouseX-nDragW) <= pMouseDownWin->ImplGetFrameData()->mnFirstMouseX) &&
+ ((nMouseX+nDragW) >= pMouseDownWin->ImplGetFrameData()->mnFirstMouseX)) ||
+ !(((nMouseY-nDragH) <= pMouseDownWin->ImplGetFrameData()->mnFirstMouseY) &&
+ ((nMouseY+nDragH) >= pMouseDownWin->ImplGetFrameData()->mnFirstMouseY)) )
+ {
+ pMouseDownWin->ImplGetFrameData()->mbStartDragCalled = TRUE;
+
+ // Check if drag source provides it's own recognizer
+ if( pMouseDownWin->ImplGetFrameData()->mbInternalDragGestureRecognizer )
+ {
+ // query DropTarget from child window
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragGestureRecognizer > xDragGestureRecognizer =
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragGestureRecognizer > ( pMouseDownWin->ImplGetWindowImpl()->mxDNDListenerContainer,
+ ::com::sun::star::uno::UNO_QUERY );
+
+ if( xDragGestureRecognizer.is() )
+ {
+ // retrieve mouse position relative to mouse down window
+ Point relLoc = pMouseDownWin->ImplFrameToOutput( Point(
+ pMouseDownWin->ImplGetFrameData()->mnFirstMouseX,
+ pMouseDownWin->ImplGetFrameData()->mnFirstMouseY ) );
+
+ // create a uno mouse event out of the available data
+ ::com::sun::star::awt::MouseEvent aMouseEvent(
+ static_cast < ::com::sun::star::uno::XInterface * > ( 0 ),
+#ifdef MACOSX
+ nCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3),
+#else
+ nCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2),
+#endif
+ nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE),
+ nMouseX,
+ nMouseY,
+ nClicks,
+ sal_False );
+
+ ULONG nCount = Application::ReleaseSolarMutex();
+
+ // FIXME: where do I get Action from ?
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource > xDragSource = pMouseDownWin->GetDragSource();
+
+ if( xDragSource.is() )
+ {
+ static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent( 0,
+ relLoc.X(), relLoc.Y(), xDragSource, ::com::sun::star::uno::makeAny( aMouseEvent ) );
+ }
+
+ Application::AcquireSolarMutex( nCount );
+ }
+ }
+ }
+ }
+ }
+ else
+ pMouseDownWin->ImplGetFrameData()->mbStartDragCalled = TRUE;
+ }
+
+ // test for mouseleave and mouseenter
+ Window* pMouseMoveWin = pWinFrameData->mpMouseMoveWin;
+ if ( pChild != pMouseMoveWin )
+ {
+ if ( pMouseMoveWin )
+ {
+ Point aLeaveMousePos = pMouseMoveWin->ImplFrameToOutput( aMousePos );
+ MouseEvent aMLeaveEvt( aLeaveMousePos, nClicks, nMode | MOUSE_LEAVEWINDOW, nCode, nCode );
+ NotifyEvent aNLeaveEvt( EVENT_MOUSEMOVE, pMouseMoveWin, &aMLeaveEvt );
+ ImplDelData aDelData;
+ ImplDelData aDelData2;
+ pWinFrameData->mbInMouseMove = TRUE;
+ pMouseMoveWin->ImplGetWinData()->mbMouseOver = FALSE;
+ pMouseMoveWin->ImplAddDel( &aDelData );
+ // Durch MouseLeave kann auch dieses Fenster zerstoert
+ // werden
+ if ( pChild )
+ pChild->ImplAddDel( &aDelData2 );
+ if ( !ImplCallPreNotify( aNLeaveEvt ) )
+ {
+ pMouseMoveWin->MouseMove( aMLeaveEvt );
+ // #82968#
+ if( !aDelData.IsDelete() )
+ aNLeaveEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNLeaveEvt );
+ }
+
+ pWinFrameData->mpMouseMoveWin = NULL;
+ pWinFrameData->mbInMouseMove = FALSE;
+
+ if ( pChild )
+ {
+ if ( aDelData2.IsDelete() )
+ pChild = NULL;
+ else
+ pChild->ImplRemoveDel( &aDelData2 );
+ }
+ if ( aDelData.IsDelete() )
+ return 1;
+ pMouseMoveWin->ImplRemoveDel( &aDelData );
+ }
+
+ nMode |= MOUSE_ENTERWINDOW;
+ }
+ pWinFrameData->mpMouseMoveWin = pChild;
+ if( pChild )
+ pChild->ImplGetWinData()->mbMouseOver = TRUE;
+
+ // MouseLeave
+ if ( !pChild )
+ return 0;
+ }
+ else
+ {
+ // mouse click
+ if ( nSVEvent == EVENT_MOUSEBUTTONDOWN )
+ {
+ const MouseSettings& rMSettings = pChild->GetSettings().GetMouseSettings();
+ ULONG nDblClkTime = rMSettings.GetDoubleClickTime();
+ long nDblClkW = rMSettings.GetDoubleClickWidth();
+ long nDblClkH = rMSettings.GetDoubleClickHeight();
+ //long nMouseX = nX;
+ //long nMouseY = nY;
+ long nMouseX = aMousePos.X(); // #106074# use the possibly re-mirrored coordinates (RTL) ! nX,nY are unmodified !
+ long nMouseY = aMousePos.Y();
+
+ if ( (pChild == pChild->ImplGetFrameData()->mpMouseDownWin) &&
+ (nCode == pChild->ImplGetFrameData()->mnFirstMouseCode) &&
+ ((nMsgTime-pChild->ImplGetFrameData()->mnMouseDownTime) < nDblClkTime) &&
+ ((nMouseX-nDblClkW) <= pChild->ImplGetFrameData()->mnFirstMouseX) &&
+ ((nMouseX+nDblClkW) >= pChild->ImplGetFrameData()->mnFirstMouseX) &&
+ ((nMouseY-nDblClkH) <= pChild->ImplGetFrameData()->mnFirstMouseY) &&
+ ((nMouseY+nDblClkH) >= pChild->ImplGetFrameData()->mnFirstMouseY) )
+ {
+ pChild->ImplGetFrameData()->mnClickCount++;
+ pChild->ImplGetFrameData()->mbStartDragCalled = TRUE;
+ }
+ else
+ {
+ pChild->ImplGetFrameData()->mpMouseDownWin = pChild;
+ pChild->ImplGetFrameData()->mnClickCount = 1;
+ pChild->ImplGetFrameData()->mnFirstMouseX = nMouseX;
+ pChild->ImplGetFrameData()->mnFirstMouseY = nMouseY;
+ pChild->ImplGetFrameData()->mnFirstMouseCode = nCode;
+ pChild->ImplGetFrameData()->mbStartDragCalled = !((nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ==
+ (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)));
+ }
+ pChild->ImplGetFrameData()->mnMouseDownTime = nMsgTime;
+ }
+ nClicks = pChild->ImplGetFrameData()->mnClickCount;
+
+ pSVData->maAppData.mnLastInputTime = Time::GetSystemTicks();
+ }
+
+ DBG_ASSERT( pChild, "ImplHandleMouseEvent: pChild == NULL" );
+
+ // create mouse event
+ Point aChildPos = pChild->ImplFrameToOutput( aMousePos );
+ MouseEvent aMEvt( aChildPos, nClicks, nMode, nCode, nCode );
+
+ // tracking window gets the mouse events
+ if ( pSVData->maWinData.mpTrackWin )
+ pChild = pSVData->maWinData.mpTrackWin;
+
+ // handle FloatingMode
+ if ( !pSVData->maWinData.mpTrackWin && pSVData->maWinData.mpFirstFloat )
+ {
+ ImplDelData aDelData;
+ pChild->ImplAddDel( &aDelData );
+ if ( ImplHandleMouseFloatMode( pChild, aMousePos, nCode, nSVEvent, bMouseLeave ) )
+ {
+ if ( !aDelData.IsDelete() )
+ {
+ pChild->ImplRemoveDel( &aDelData );
+ pChild->ImplGetFrameData()->mbStartDragCalled = TRUE;
+ }
+ return 1;
+ }
+ else
+ pChild->ImplRemoveDel( &aDelData );
+ }
+
+ // call handler
+ BOOL bDrag = FALSE;
+ BOOL bCallHelpRequest = TRUE;
+ DBG_ASSERT( pChild, "ImplHandleMouseEvent: pChild is NULL" );
+
+ ImplDelData aDelData;
+ NotifyEvent aNEvt( nSVEvent, pChild, &aMEvt );
+ pChild->ImplAddDel( &aDelData );
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ pChild->ImplGetFrameData()->mbInMouseMove = TRUE;
+
+ // bring window into foreground on mouseclick
+ if ( nSVEvent == EVENT_MOUSEBUTTONDOWN )
+ {
+ if( !pSVData->maWinData.mpFirstFloat && // totop for floating windows in popup would change the focus and would close them immediately
+ !(pChild->ImplGetFrameWindow()->GetStyle() & WB_OWNERDRAWDECORATION) ) // ownerdrawdecorated windows must never grab focus
+ pChild->ToTop();
+ if ( aDelData.IsDelete() )
+ return 1;
+ }
+
+ if ( ImplCallPreNotify( aNEvt ) || aDelData.IsDelete() )
+ nRet = 1;
+ else
+ {
+ nRet = 0;
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ {
+ if ( pSVData->maWinData.mpTrackWin )
+ {
+ TrackingEvent aTEvt( aMEvt );
+ pChild->Tracking( aTEvt );
+ if ( !aDelData.IsDelete() )
+ {
+ // When ScrollRepeat, we restart the timer
+ if ( pSVData->maWinData.mpTrackTimer &&
+ (pSVData->maWinData.mnTrackFlags & STARTTRACK_SCROLLREPEAT) )
+ pSVData->maWinData.mpTrackTimer->Start();
+ }
+ bCallHelpRequest = FALSE;
+ nRet = 1;
+ }
+ else
+ {
+ // Auto-ToTop
+ if ( !pSVData->maWinData.mpCaptureWin &&
+ (pChild->GetSettings().GetMouseSettings().GetOptions() & MOUSE_OPTION_AUTOFOCUS) )
+ pChild->ToTop( TOTOP_NOGRABFOCUS );
+
+ if( aDelData.IsDelete() )
+ bCallHelpRequest = FALSE;
+ else
+ {
+ // if the MouseMove handler changes the help window's visibility
+ // the HelpRequest handler should not be called anymore
+ Window* pOldHelpTextWin = pSVData->maHelpData.mpHelpWin;
+ pChild->ImplGetWindowImpl()->mbMouseMove = FALSE;
+ pChild->MouseMove( aMEvt );
+ if ( pOldHelpTextWin != pSVData->maHelpData.mpHelpWin )
+ bCallHelpRequest = FALSE;
+ }
+ }
+ }
+ else if ( nSVEvent == EVENT_MOUSEBUTTONDOWN )
+ {
+ if ( pSVData->maWinData.mpTrackWin &&
+ !(pSVData->maWinData.mnTrackFlags & STARTTRACK_MOUSEBUTTONDOWN) )
+ nRet = 1;
+ else
+ {
+ pChild->ImplGetWindowImpl()->mbMouseButtonDown = FALSE;
+ pChild->MouseButtonDown( aMEvt );
+ }
+ }
+ else
+ {
+ if ( pSVData->maWinData.mpTrackWin )
+ {
+ pChild->EndTracking();
+ nRet = 1;
+ }
+ else
+ {
+ pChild->ImplGetWindowImpl()->mbMouseButtonUp = FALSE;
+ pChild->MouseButtonUp( aMEvt );
+ }
+ }
+
+ // #82968#
+ if ( !aDelData.IsDelete() )
+ aNEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNEvt );
+ }
+
+ if ( aDelData.IsDelete() )
+ return 1;
+
+
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ pChild->ImplGetWindowImpl()->mpFrameData->mbInMouseMove = FALSE;
+
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ {
+ if ( bCallHelpRequest && !pSVData->maHelpData.mbKeyboardHelp )
+ ImplHandleMouseHelpRequest( pChild, pChild->OutputToScreenPixel( aMEvt.GetPosPixel() ) );
+ nRet = 1;
+ }
+ else if ( !nRet )
+ {
+ if ( nSVEvent == EVENT_MOUSEBUTTONDOWN )
+ {
+ if ( !pChild->ImplGetWindowImpl()->mbMouseButtonDown )
+ nRet = 1;
+ }
+ else
+ {
+ if ( !pChild->ImplGetWindowImpl()->mbMouseButtonUp )
+ nRet = 1;
+ }
+ }
+
+ pChild->ImplRemoveDel( &aDelData );
+
+ if ( nSVEvent == EVENT_MOUSEMOVE )
+ {
+ // set new mouse pointer
+ if ( !bMouseLeave )
+ ImplSetMousePointer( pChild );
+ }
+ else if ( (nSVEvent == EVENT_MOUSEBUTTONDOWN) || (nSVEvent == EVENT_MOUSEBUTTONUP) )
+ {
+ if ( !bDrag )
+ {
+ // Command-Events
+ if ( /*(nRet == 0) &&*/ (nClicks == 1) && (nSVEvent == EVENT_MOUSEBUTTONDOWN) &&
+ (nCode == MOUSE_MIDDLE) )
+ {
+ USHORT nMiddleAction = pChild->GetSettings().GetMouseSettings().GetMiddleButtonAction();
+ if ( nMiddleAction == MOUSE_MIDDLE_AUTOSCROLL )
+ nRet = !ImplCallCommand( pChild, COMMAND_STARTAUTOSCROLL, NULL, TRUE, &aChildPos );
+ else if ( nMiddleAction == MOUSE_MIDDLE_PASTESELECTION )
+ nRet = !ImplCallCommand( pChild, COMMAND_PASTESELECTION, NULL, TRUE, &aChildPos );
+ }
+ else
+ {
+ // ContextMenu
+ const MouseSettings& rMSettings = pChild->GetSettings().GetMouseSettings();
+ if ( (nCode == rMSettings.GetContextMenuCode()) &&
+ (nClicks == rMSettings.GetContextMenuClicks()) )
+ {
+ BOOL bContextMenu;
+ if ( rMSettings.GetContextMenuDown() )
+ bContextMenu = (nSVEvent == EVENT_MOUSEBUTTONDOWN);
+ else
+ bContextMenu = (nSVEvent == EVENT_MOUSEBUTTONUP);
+ if ( bContextMenu )
+ {
+ if( pSVData->maAppData.mpActivePopupMenu )
+ {
+ /* #i34277# there already is a context menu open
+ * that was probably just closed with EndPopupMode.
+ * We need to give the eventual corresponding
+ * PopupMenu::Execute a chance to end properly.
+ * Therefore delay context menu command and
+ * issue only after popping one frame of the
+ * Yield stack.
+ */
+ ContextMenuEvent* pEv = new ContextMenuEvent;
+ pEv->pWindow = pChild;
+ pEv->aChildPos = aChildPos;
+ pChild->ImplAddDel( &pEv->aDelData );
+ Application::PostUserEvent( Link( pEv, ContextMenuEventLink ) );
+ }
+ else
+ nRet = ! ImplCallCommand( pChild, COMMAND_CONTEXTMENU, NULL, TRUE, &aChildPos );
+ }
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static Window* ImplGetKeyInputWindow( Window* pWindow )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // determine last input time
+ pSVData->maAppData.mnLastInputTime = Time::GetSystemTicks();
+
+ // #127104# workaround for destroyed windows
+ if( pWindow->ImplGetWindowImpl() == NULL )
+ return 0;
+
+ // find window - is every time the window which has currently the
+ // focus or the last time the focus.
+ // the first floating window always has the focus
+ Window* pChild = pSVData->maWinData.mpFirstFloat;
+ if( !pChild || ( pChild->ImplGetWindowImpl()->mbFloatWin && !((FloatingWindow *)pChild)->GrabsFocus() ) )
+ pChild = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin;
+ else
+ {
+ // allow floaters to forward keyinput to some member
+ pChild = pChild->GetPreferredKeyInputWindow();
+ }
+
+ // no child - than no input
+ if ( !pChild )
+ return 0;
+
+ // We call also KeyInput if we haven't the focus, because on Unix
+ // system this is often the case when a Lookup Choise Window has
+ // the focus - because this windows send the KeyInput directly to
+ // the window without resetting the focus
+ DBG_ASSERTWARNING( pChild == pSVData->maWinData.mpFocusWin,
+ "ImplHandleKey: Keyboard-Input is sent to a frame without focus" );
+
+ // no keyinput to disabled windows
+ if ( !pChild->IsEnabled() || !pChild->IsInputEnabled() || pChild->IsInModalMode() )
+ return 0;
+
+ return pChild;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleKey( Window* pWindow, USHORT nSVEvent,
+ USHORT nKeyCode, USHORT nCharCode, USHORT nRepeat, BOOL bForward )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ KeyCode aKeyCode( nKeyCode, nKeyCode );
+ USHORT nEvCode = aKeyCode.GetCode();
+
+ // allow application key listeners to remove the key event
+ // but make sure we're not forwarding external KeyEvents, (ie where bForward is FALSE)
+ // becasue those are coming back from the listener itself and MUST be processed
+ KeyEvent aKeyEvent( (xub_Unicode)nCharCode, aKeyCode, nRepeat );
+ if( bForward )
+ {
+ USHORT nVCLEvent;
+ switch( nSVEvent )
+ {
+ case EVENT_KEYINPUT:
+ nVCLEvent = VCLEVENT_WINDOW_KEYINPUT;
+ break;
+ case EVENT_KEYUP:
+ nVCLEvent = VCLEVENT_WINDOW_KEYUP;
+ break;
+ default:
+ nVCLEvent = 0;
+ break;
+ }
+ if( nVCLEvent && pSVData->mpApp->HandleKey( nVCLEvent, pWindow, &aKeyEvent ) )
+ return 1;
+ }
+
+ // #i1820# use locale specific decimal separator
+ if( nEvCode == KEY_DECIMAL )
+ {
+ if( Application::GetSettings().GetMiscSettings().GetEnableLocalizedDecimalSep() )
+ {
+ String aSep( pWindow->GetSettings().GetLocaleDataWrapper().getNumDecimalSep() );
+ nCharCode = (USHORT) aSep.GetChar(0);
+ }
+ }
+
+ BOOL bCtrlF6 = (aKeyCode.GetCode() == KEY_F6) && aKeyCode.IsMod1();
+
+ // determine last input time
+ pSVData->maAppData.mnLastInputTime = Time::GetSystemTicks();
+
+ // handle tracking window
+ if ( nSVEvent == EVENT_KEYINPUT )
+ {
+#ifdef DBG_UTIL
+ // #105224# use Ctrl-Alt-Shift-D, Ctrl-Shift-D must be useable by app
+ if ( aKeyCode.IsShift() && aKeyCode.IsMod1() && (aKeyCode.IsMod2() || aKeyCode.IsMod3()) && (aKeyCode.GetCode() == KEY_D) )
+ {
+ DBGGUI_START();
+ return 1;
+ }
+#endif
+
+ if ( pSVData->maHelpData.mbExtHelpMode )
+ {
+ Help::EndExtHelp();
+ if ( nEvCode == KEY_ESCAPE )
+ return 1;
+ }
+ if ( pSVData->maHelpData.mpHelpWin )
+ ImplDestroyHelpWindow( false );
+
+ // AutoScrollMode
+ if ( pSVData->maWinData.mpAutoScrollWin )
+ {
+ pSVData->maWinData.mpAutoScrollWin->EndAutoScroll();
+ if ( nEvCode == KEY_ESCAPE )
+ return 1;
+ }
+
+ if ( pSVData->maWinData.mpTrackWin )
+ {
+ USHORT nOrigCode = aKeyCode.GetCode();
+
+ if ( (nOrigCode == KEY_ESCAPE) && !(pSVData->maWinData.mnTrackFlags & STARTTRACK_NOKEYCANCEL) )
+ {
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL | ENDTRACK_KEY );
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ if ( !(pLastLevelFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOKEYCLOSE) )
+ {
+ USHORT nEscCode = aKeyCode.GetCode();
+
+ if ( nEscCode == KEY_ESCAPE )
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ }
+ return 1;
+ }
+ else if ( nOrigCode == KEY_RETURN )
+ {
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_KEY );
+ return 1;
+ }
+ else if ( !(pSVData->maWinData.mnTrackFlags & STARTTRACK_KEYINPUT) )
+ return 1;
+ }
+
+ // handle FloatingMode
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ if ( !(pLastLevelFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOKEYCLOSE) )
+ {
+ USHORT nCode = aKeyCode.GetCode();
+
+ if ( (nCode == KEY_ESCAPE) || bCtrlF6)
+ {
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ if( !bCtrlF6 )
+ return 1;
+ }
+ }
+ }
+
+ // test for accel
+ if ( pSVData->maAppData.mpAccelMgr )
+ {
+ if ( pSVData->maAppData.mpAccelMgr->IsAccelKey( aKeyCode, nRepeat ) )
+ return 1;
+ }
+ }
+
+ // find window
+ Window* pChild = ImplGetKeyInputWindow( pWindow );
+ if ( !pChild )
+ return 0;
+
+ // --- RTL --- mirror cursor keys
+ if( (aKeyCode.GetCode() == KEY_LEFT || aKeyCode.GetCode() == KEY_RIGHT) &&
+ pChild->ImplHasMirroredGraphics() && pChild->IsRTLEnabled() )
+ aKeyCode = KeyCode( aKeyCode.GetCode() == KEY_LEFT ? KEY_RIGHT : KEY_LEFT, aKeyCode.GetModifier() );
+
+ // call handler
+ ImplDelData aDelData;
+ pChild->ImplAddDel( &aDelData );
+
+ KeyEvent aKeyEvt( (xub_Unicode)nCharCode, aKeyCode, nRepeat );
+ NotifyEvent aNotifyEvt( nSVEvent, pChild, &aKeyEvt );
+ BOOL bKeyPreNotify = (ImplCallPreNotify( aNotifyEvt ) != 0);
+ long nRet = 1;
+
+ if ( !bKeyPreNotify && !aDelData.IsDelete() )
+ {
+ if ( nSVEvent == EVENT_KEYINPUT )
+ {
+ pChild->ImplGetWindowImpl()->mbKeyInput = FALSE;
+ pChild->KeyInput( aKeyEvt );
+ }
+ else
+ {
+ pChild->ImplGetWindowImpl()->mbKeyUp = FALSE;
+ pChild->KeyUp( aKeyEvt );
+ }
+ // #82968#
+ if( !aDelData.IsDelete() )
+ aNotifyEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNotifyEvt );
+ }
+
+ if ( aDelData.IsDelete() )
+ return 1;
+
+ pChild->ImplRemoveDel( &aDelData );
+
+ if ( nSVEvent == EVENT_KEYINPUT )
+ {
+ if ( !bKeyPreNotify && pChild->ImplGetWindowImpl()->mbKeyInput )
+ {
+ USHORT nCode = aKeyCode.GetCode();
+
+ // #101999# is focus in or below toolbox
+ BOOL bToolboxFocus=FALSE;
+ if( (nCode == KEY_F1) && aKeyCode.IsShift() )
+ {
+ Window *pWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin;
+ while( pWin )
+ {
+ if( pWin->ImplGetWindowImpl()->mbToolBox )
+ {
+ bToolboxFocus = TRUE;
+ break;
+ }
+ else
+ pWin = pWin->GetParent();
+ }
+ }
+
+ // ContextMenu
+ if ( (nCode == KEY_CONTEXTMENU) || ((nCode == KEY_F10) && aKeyCode.IsShift() && !aKeyCode.IsMod1() && !aKeyCode.IsMod2() ) )
+ nRet = !ImplCallCommand( pChild, COMMAND_CONTEXTMENU, NULL, FALSE );
+ else if ( ( (nCode == KEY_F2) && aKeyCode.IsShift() ) || ( (nCode == KEY_F1) && aKeyCode.IsMod1() ) ||
+ // #101999# no active help when focus in toolbox, simulate BallonHelp instead
+ ( (nCode == KEY_F1) && aKeyCode.IsShift() && bToolboxFocus ) )
+ {
+ // TipHelp via Keyboard (Shift-F2 or Ctrl-F1)
+ // simulate mouseposition at center of window
+
+ Size aSize = pChild->GetOutputSize();
+ Point aPos = Point( aSize.getWidth()/2, aSize.getHeight()/2 );
+ aPos = pChild->OutputToScreenPixel( aPos );
+
+ HelpEvent aHelpEvent( aPos, HELPMODE_BALLOON );
+ aHelpEvent.SetKeyboardActivated( TRUE );
+ pSVData->maHelpData.mbSetKeyboardHelp = TRUE;
+ pChild->RequestHelp( aHelpEvent );
+ pSVData->maHelpData.mbSetKeyboardHelp = FALSE;
+ }
+ else if ( (nCode == KEY_F1) || (nCode == KEY_HELP) )
+ {
+ if ( !aKeyCode.GetModifier() )
+ {
+ if ( pSVData->maHelpData.mbContextHelp )
+ {
+ Point aMousePos = pChild->OutputToScreenPixel( pChild->GetPointerPosPixel() );
+ HelpEvent aHelpEvent( aMousePos, HELPMODE_CONTEXT );
+ pChild->RequestHelp( aHelpEvent );
+ }
+ else
+ nRet = 0;
+ }
+ else if ( aKeyCode.IsShift() )
+ {
+ if ( pSVData->maHelpData.mbExtHelp )
+ Help::StartExtHelp();
+ else
+ nRet = 0;
+ }
+ }
+ else
+ {
+ if ( ImplCallHotKey( aKeyCode ) )
+ nRet = 1;
+ else
+ nRet = 0;
+ }
+ }
+ }
+ else
+ {
+ if ( !bKeyPreNotify && pChild->ImplGetWindowImpl()->mbKeyUp )
+ nRet = 0;
+ }
+
+ // #105591# send keyinput to parent if we are a floating window and the key was not pocessed yet
+ if( !nRet && pWindow->ImplGetWindowImpl()->mbFloatWin && pWindow->GetParent() && (pWindow->ImplGetWindowImpl()->mpFrame != pWindow->GetParent()->ImplGetWindowImpl()->mpFrame) )
+ {
+ pChild = pWindow->GetParent();
+
+ // call handler
+ ImplDelData aChildDelData( pChild );
+ KeyEvent aKEvt( (xub_Unicode)nCharCode, aKeyCode, nRepeat );
+ NotifyEvent aNEvt( nSVEvent, pChild, &aKEvt );
+ BOOL bPreNotify = (ImplCallPreNotify( aNEvt ) != 0);
+ if ( aChildDelData.IsDelete() )
+ return 1;
+
+ if ( !bPreNotify )
+ {
+ if ( nSVEvent == EVENT_KEYINPUT )
+ {
+ pChild->ImplGetWindowImpl()->mbKeyInput = FALSE;
+ pChild->KeyInput( aKEvt );
+ }
+ else
+ {
+ pChild->ImplGetWindowImpl()->mbKeyUp = FALSE;
+ pChild->KeyUp( aKEvt );
+ }
+ // #82968#
+ if( !aChildDelData.IsDelete() )
+ aNEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNEvt );
+ if ( aChildDelData.IsDelete() )
+ return 1;
+ }
+
+ if( bPreNotify || !pChild->ImplGetWindowImpl()->mbKeyInput )
+ nRet = 1;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleExtTextInput( Window* pWindow,
+ const XubString& rText,
+ const USHORT* pTextAttr,
+ ULONG nCursorPos, USHORT nCursorFlags )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pChild = NULL;
+
+ int nTries = 200;
+ while( nTries-- )
+ {
+ pChild = pSVData->maWinData.mpExtTextInputWin;
+ if ( !pChild )
+ {
+ pChild = ImplGetKeyInputWindow( pWindow );
+ if ( !pChild )
+ return 0;
+ }
+ if( !pChild->ImplGetWindowImpl()->mpFrameData->mnFocusId )
+ break;
+ Application::Yield();
+ }
+
+ // If it is the first ExtTextInput call, we inform the information
+ // and allocate the data, which we must store in this mode
+ ImplWinData* pWinData = pChild->ImplGetWinData();
+ if ( !pChild->ImplGetWindowImpl()->mbExtTextInput )
+ {
+ pChild->ImplGetWindowImpl()->mbExtTextInput = TRUE;
+ if ( !pWinData->mpExtOldText )
+ pWinData->mpExtOldText = new UniString;
+ else
+ pWinData->mpExtOldText->Erase();
+ if ( pWinData->mpExtOldAttrAry )
+ {
+ delete [] pWinData->mpExtOldAttrAry;
+ pWinData->mpExtOldAttrAry = NULL;
+ }
+ pSVData->maWinData.mpExtTextInputWin = pChild;
+ ImplCallCommand( pChild, COMMAND_STARTEXTTEXTINPUT );
+ }
+
+ // be aware of being recursively called in StartExtTextInput
+ if ( !pChild->ImplGetWindowImpl()->mbExtTextInput )
+ return 0;
+
+ // Test for changes
+ BOOL bOnlyCursor = FALSE;
+ xub_StrLen nMinLen = Min( pWinData->mpExtOldText->Len(), rText.Len() );
+ xub_StrLen nDeltaStart = 0;
+ while ( nDeltaStart < nMinLen )
+ {
+ if ( pWinData->mpExtOldText->GetChar( nDeltaStart ) != rText.GetChar( nDeltaStart ) )
+ break;
+ nDeltaStart++;
+ }
+ if ( pWinData->mpExtOldAttrAry || pTextAttr )
+ {
+ if ( !pWinData->mpExtOldAttrAry || !pTextAttr )
+ nDeltaStart = 0;
+ else
+ {
+ xub_StrLen i = 0;
+ while ( i < nDeltaStart )
+ {
+ if ( pWinData->mpExtOldAttrAry[i] != pTextAttr[i] )
+ {
+ nDeltaStart = i;
+ break;
+ }
+ i++;
+ }
+ }
+ }
+ if ( (nDeltaStart >= nMinLen) &&
+ (pWinData->mpExtOldText->Len() == rText.Len()) )
+ bOnlyCursor = TRUE;
+
+ // Call Event and store the information
+ CommandExtTextInputData aData( rText, pTextAttr,
+ (xub_StrLen)nCursorPos, nCursorFlags,
+ nDeltaStart, pWinData->mpExtOldText->Len(),
+ bOnlyCursor );
+ *pWinData->mpExtOldText = rText;
+ if ( pWinData->mpExtOldAttrAry )
+ {
+ delete [] pWinData->mpExtOldAttrAry;
+ pWinData->mpExtOldAttrAry = NULL;
+ }
+ if ( pTextAttr )
+ {
+ pWinData->mpExtOldAttrAry = new USHORT[rText.Len()];
+ memcpy( pWinData->mpExtOldAttrAry, pTextAttr, rText.Len()*sizeof( USHORT ) );
+ }
+ return !ImplCallCommand( pChild, COMMAND_EXTTEXTINPUT, &aData );
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleEndExtTextInput( Window* /* pWindow */ )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pChild = pSVData->maWinData.mpExtTextInputWin;
+ long nRet = 0;
+
+ if ( pChild )
+ {
+ pChild->ImplGetWindowImpl()->mbExtTextInput = FALSE;
+ pSVData->maWinData.mpExtTextInputWin = NULL;
+ ImplWinData* pWinData = pChild->ImplGetWinData();
+ if ( pWinData->mpExtOldText )
+ {
+ delete pWinData->mpExtOldText;
+ pWinData->mpExtOldText = NULL;
+ }
+ if ( pWinData->mpExtOldAttrAry )
+ {
+ delete [] pWinData->mpExtOldAttrAry;
+ pWinData->mpExtOldAttrAry = NULL;
+ }
+ nRet = !ImplCallCommand( pChild, COMMAND_ENDEXTTEXTINPUT );
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleExtTextInputPos( Window* pWindow,
+ Rectangle& rRect, long& rInputWidth,
+ bool * pVertical )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pChild = pSVData->maWinData.mpExtTextInputWin;
+
+ if ( !pChild )
+ pChild = ImplGetKeyInputWindow( pWindow );
+ else
+ {
+ // Test, if the Window is related to the frame
+ if ( !pWindow->ImplIsWindowOrChild( pChild ) )
+ pChild = ImplGetKeyInputWindow( pWindow );
+ }
+
+ if ( pChild )
+ {
+ ImplCallCommand( pChild, COMMAND_CURSORPOS );
+ const Rectangle* pRect = pChild->GetCursorRect();
+ if ( pRect )
+ rRect = pChild->ImplLogicToDevicePixel( *pRect );
+ else
+ {
+ Cursor* pCursor = pChild->GetCursor();
+ if ( pCursor )
+ {
+ Point aPos = pChild->ImplLogicToDevicePixel( pCursor->GetPos() );
+ Size aSize = pChild->LogicToPixel( pCursor->GetSize() );
+ if ( !aSize.Width() )
+ aSize.Width() = pChild->GetSettings().GetStyleSettings().GetCursorSize();
+ rRect = Rectangle( aPos, aSize );
+ }
+ else
+ rRect = Rectangle( Point( pChild->GetOutOffXPixel(), pChild->GetOutOffYPixel() ), Size() );
+ }
+ rInputWidth = pChild->ImplLogicWidthToDevicePixel( pChild->GetCursorExtTextInputWidth() );
+ if ( !rInputWidth )
+ rInputWidth = rRect.GetWidth();
+ }
+ if (pVertical != 0)
+ *pVertical
+ = pChild != 0 && pChild->GetInputContext().GetFont().IsVertical();
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleInputContextChange( Window* pWindow, LanguageType eNewLang )
+{
+ Window* pChild = ImplGetKeyInputWindow( pWindow );
+ CommandInputContextData aData( eNewLang );
+ return !ImplCallCommand( pChild, COMMAND_INPUTCONTEXTCHANGE, &aData );
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplCallWheelCommand( Window* pWindow, const Point& rPos,
+ const CommandWheelData* pWheelData )
+{
+ Point aCmdMousePos = pWindow->ImplFrameToOutput( rPos );
+ CommandEvent aCEvt( aCmdMousePos, COMMAND_WHEEL, TRUE, pWheelData );
+ NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
+ ImplDelData aDelData( pWindow );
+ BOOL bPreNotify = (ImplCallPreNotify( aNCmdEvt ) != 0);
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ if ( !bPreNotify )
+ {
+ pWindow->ImplGetWindowImpl()->mbCommand = FALSE;
+ pWindow->Command( aCEvt );
+ if ( aDelData.IsDelete() )
+ return FALSE;
+ if ( pWindow->ImplGetWindowImpl()->mbCommand )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleWheelEvent( Window* pWindow, const SalWheelMouseEvent& rEvt )
+{
+ ImplDelData aDogTag( pWindow );
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpAutoScrollWin )
+ pSVData->maWinData.mpAutoScrollWin->EndAutoScroll();
+ if ( pSVData->maHelpData.mpHelpWin )
+ ImplDestroyHelpWindow( true );
+ if( aDogTag.IsDelete() )
+ return 0;
+
+ USHORT nMode;
+ USHORT nCode = rEvt.mnCode;
+ bool bHorz = rEvt.mbHorz;
+ bool bPixel = rEvt.mbDeltaIsPixel;
+ if ( nCode & KEY_MOD1 )
+ nMode = COMMAND_WHEEL_ZOOM;
+ else if ( nCode & KEY_MOD2 )
+ nMode = COMMAND_WHEEL_DATAZOOM;
+ else
+ {
+ nMode = COMMAND_WHEEL_SCROLL;
+ // #i85450# interpret shift-wheel as horizontal wheel action
+ if( (nCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)) == KEY_SHIFT )
+ bHorz = true;
+ }
+
+ CommandWheelData aWheelData( rEvt.mnDelta, rEvt.mnNotchDelta, rEvt.mnScrollLines, nMode, nCode, bHorz, bPixel );
+ Point aMousePos( rEvt.mnX, rEvt.mnY );
+ BOOL bRet = TRUE;
+
+ // first check any floating window ( eg. drop down listboxes)
+ bool bIsFloat = false;
+ Window *pMouseWindow = NULL;
+ if ( pSVData->maWinData.mpFirstFloat && !pSVData->maWinData.mpCaptureWin &&
+ !pSVData->maWinData.mpFirstFloat->ImplIsFloatPopupModeWindow( pWindow ) )
+ {
+ USHORT nHitTest = IMPL_FLOATWIN_HITTEST_OUTSIDE;
+ pMouseWindow = pSVData->maWinData.mpFirstFloat->ImplFloatHitTest( pWindow, aMousePos, nHitTest );
+ }
+ // then try the window directly beneath the mouse
+ if( !pMouseWindow )
+ pMouseWindow = pWindow->ImplFindWindow( aMousePos );
+ else
+ {
+ // transform coordinates to float window frame coordinates
+ pMouseWindow = pMouseWindow->ImplFindWindow(
+ pMouseWindow->OutputToScreenPixel(
+ pMouseWindow->AbsoluteScreenToOutputPixel(
+ pWindow->OutputToAbsoluteScreenPixel(
+ pWindow->ScreenToOutputPixel( aMousePos ) ) ) ) );
+ bIsFloat = true;
+ }
+
+ if ( pMouseWindow &&
+ pMouseWindow->IsEnabled() && pMouseWindow->IsInputEnabled() && ! pMouseWindow->IsInModalMode() )
+ {
+ // transform coordinates to float window frame coordinates
+ Point aRelMousePos( pMouseWindow->OutputToScreenPixel(
+ pMouseWindow->AbsoluteScreenToOutputPixel(
+ pWindow->OutputToAbsoluteScreenPixel(
+ pWindow->ScreenToOutputPixel( aMousePos ) ) ) ) );
+ bRet = ImplCallWheelCommand( pMouseWindow, aRelMousePos, &aWheelData );
+ }
+
+ // if the commad was not handled try the focus window
+ if ( bRet )
+ {
+ Window* pFocusWindow = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin;
+ if ( pFocusWindow && (pFocusWindow != pMouseWindow) &&
+ (pFocusWindow == pSVData->maWinData.mpFocusWin) )
+ {
+ // no wheel-messages to disabled windows
+ if ( pFocusWindow->IsEnabled() && pFocusWindow->IsInputEnabled() && ! pFocusWindow->IsInModalMode() )
+ {
+ // transform coordinates to focus window frame coordinates
+ Point aRelMousePos( pFocusWindow->OutputToScreenPixel(
+ pFocusWindow->AbsoluteScreenToOutputPixel(
+ pWindow->OutputToAbsoluteScreenPixel(
+ pWindow->ScreenToOutputPixel( aMousePos ) ) ) ) );
+ bRet = ImplCallWheelCommand( pFocusWindow, aRelMousePos, &aWheelData );
+ }
+ }
+ }
+
+ // close floaters
+ if( ! bIsFloat && pSVData->maWinData.mpFirstFloat )
+ {
+ FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ if( pLastLevelFloat )
+ {
+ ULONG nPopupFlags = pLastLevelFloat->GetPopupModeFlags();
+ if ( nPopupFlags & FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE )
+ {
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ }
+ }
+
+ return !bRet;
+}
+
+// -----------------------------------------------------------------------
+#define IMPL_PAINT_CHECKRTL ((USHORT)0x0020)
+
+static void ImplHandlePaint( Window* pWindow, const Rectangle& rBoundRect, bool bImmediateUpdate )
+{
+ // give up background save when sytem paints arrive
+ Window* pSaveBackWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFirstBackWin;
+ while ( pSaveBackWin )
+ {
+ Window* pNext = pSaveBackWin->ImplGetWindowImpl()->mpOverlapData->mpNextBackWin;
+ Rectangle aRect( Point( pSaveBackWin->GetOutOffXPixel(), pSaveBackWin->GetOutOffYPixel() ),
+ Size( pSaveBackWin->GetOutputWidthPixel(), pSaveBackWin->GetOutputHeightPixel() ) );
+ if ( aRect.IsOver( rBoundRect ) )
+ pSaveBackWin->ImplDeleteOverlapBackground();
+ pSaveBackWin = pNext;
+ }
+
+ // system paint events must be checked for re-mirroring
+ pWindow->ImplGetWindowImpl()->mnPaintFlags |= IMPL_PAINT_CHECKRTL;
+
+ // trigger paint for all windows that live in the new paint region
+ Region aRegion( rBoundRect );
+ pWindow->ImplInvalidateOverlapFrameRegion( aRegion );
+ if( bImmediateUpdate )
+ {
+ // #i87663# trigger possible pending resize notifications
+ // (GetSizePixel does that for us)
+ pWindow->GetSizePixel();
+ // force drawing inmmediately
+ pWindow->Update();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void KillOwnPopups( Window* pWindow )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window *pParent = pWindow->ImplGetWindowImpl()->mpFrameWindow;
+ Window *pChild = pSVData->maWinData.mpFirstFloat;
+ if ( pChild && pParent->ImplIsWindowOrChild( pChild, TRUE ) )
+ {
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplHandleResize( Window* pWindow, long nNewWidth, long nNewHeight )
+{
+ if( pWindow->GetStyle() & (WB_MOVEABLE|WB_SIZEABLE) )
+ {
+ KillOwnPopups( pWindow );
+ if( pWindow->ImplGetWindow() != ImplGetSVData()->maHelpData.mpHelpWin )
+ ImplDestroyHelpWindow( true );
+ }
+
+ if (
+ (nNewWidth > 0 && nNewHeight > 0) ||
+ pWindow->ImplGetWindow()->ImplGetWindowImpl()->mbAllResize
+ )
+ {
+ if ( (nNewWidth != pWindow->GetOutputWidthPixel()) || (nNewHeight != pWindow->GetOutputHeightPixel()) )
+ {
+ pWindow->mnOutWidth = nNewWidth;
+ pWindow->mnOutHeight = nNewHeight;
+ pWindow->ImplGetWindowImpl()->mbWaitSystemResize = FALSE;
+ if ( pWindow->IsReallyVisible() )
+ pWindow->ImplSetClipFlag();
+ if ( pWindow->IsVisible() || pWindow->ImplGetWindow()->ImplGetWindowImpl()->mbAllResize ||
+ ( pWindow->ImplGetWindowImpl()->mbFrame && pWindow->ImplGetWindowImpl()->mpClientWindow ) ) // propagate resize for system border windows
+ {
+ bool bStartTimer = true;
+ // use resize buffering for user resizes
+ // ownerdraw decorated windows and floating windows can be resized immediately (i.e. synchronously)
+ if( pWindow->ImplGetWindowImpl()->mbFrame && (pWindow->GetStyle() & WB_SIZEABLE)
+ && !(pWindow->GetStyle() & WB_OWNERDRAWDECORATION) // synchronous resize for ownerdraw decorated windows (toolbars)
+ && !pWindow->ImplGetWindowImpl()->mbFloatWin ) // synchronous resize for floating windows, #i43799#
+ {
+ if( pWindow->ImplGetWindowImpl()->mpClientWindow )
+ {
+ // #i42750# presentation wants to be informed about resize
+ // as early as possible
+ WorkWindow* pWorkWindow = dynamic_cast<WorkWindow*>(pWindow->ImplGetWindowImpl()->mpClientWindow);
+ if( pWorkWindow && pWorkWindow->IsPresentationMode() )
+ bStartTimer = false;
+ }
+ }
+ else
+ bStartTimer = false;
+
+ if( bStartTimer )
+ pWindow->ImplGetWindowImpl()->mpFrameData->maResizeTimer.Start();
+ else
+ pWindow->ImplCallResize(); // otherwise menues cannot be positioned
+ }
+ else
+ pWindow->ImplGetWindowImpl()->mbCallResize = TRUE;
+ }
+ }
+
+ pWindow->ImplGetWindowImpl()->mpFrameData->mbNeedSysWindow = (nNewWidth < IMPL_MIN_NEEDSYSWIN) ||
+ (nNewHeight < IMPL_MIN_NEEDSYSWIN);
+ BOOL bMinimized = (nNewWidth <= 0) || (nNewHeight <= 0);
+ if( bMinimized != pWindow->ImplGetWindowImpl()->mpFrameData->mbMinimized )
+ pWindow->ImplGetWindowImpl()->mpFrameWindow->ImplNotifyIconifiedState( bMinimized );
+ pWindow->ImplGetWindowImpl()->mpFrameData->mbMinimized = bMinimized;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleMove( Window* pWindow )
+{
+ if( pWindow->ImplGetWindowImpl()->mbFrame && pWindow->ImplIsFloatingWindow() && pWindow->IsReallyVisible() )
+ {
+ static_cast<FloatingWindow*>(pWindow)->EndPopupMode( FLOATWIN_POPUPMODEEND_TEAROFF );
+ pWindow->ImplCallMove();
+ }
+
+ if( pWindow->GetStyle() & (WB_MOVEABLE|WB_SIZEABLE) )
+ {
+ KillOwnPopups( pWindow );
+ if( pWindow->ImplGetWindow() != ImplGetSVData()->maHelpData.mpHelpWin )
+ ImplDestroyHelpWindow( true );
+ }
+
+ if ( pWindow->IsVisible() )
+ pWindow->ImplCallMove();
+ else
+ pWindow->ImplGetWindowImpl()->mbCallMove = TRUE; // make sure the framepos will be updated on the next Show()
+
+ if ( pWindow->ImplGetWindowImpl()->mbFrame && pWindow->ImplGetWindowImpl()->mpClientWindow )
+ pWindow->ImplGetWindowImpl()->mpClientWindow->ImplCallMove(); // notify client to update geometry
+
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleMoveResize( Window* pWindow, long nNewWidth, long nNewHeight )
+{
+ ImplHandleMove( pWindow );
+ ImplHandleResize( pWindow, nNewWidth, nNewHeight );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplActivateFloatingWindows( Window* pWindow, BOOL bActive )
+{
+ // Zuerst alle ueberlappenden Fenster ueberpruefen
+ Window* pTempWindow = pWindow->ImplGetWindowImpl()->mpFirstOverlap;
+ while ( pTempWindow )
+ {
+ if ( !pTempWindow->GetActivateMode() )
+ {
+ if ( (pTempWindow->GetType() == WINDOW_BORDERWINDOW) &&
+ (pTempWindow->ImplGetWindow()->GetType() == WINDOW_FLOATINGWINDOW) )
+ ((ImplBorderWindow*)pTempWindow)->SetDisplayActive( bActive );
+ }
+
+ ImplActivateFloatingWindows( pTempWindow, bActive );
+ pTempWindow = pTempWindow->ImplGetWindowImpl()->mpNext;
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( Window, ImplAsyncFocusHdl, void*, EMPTYARG )
+{
+ ImplGetWindowImpl()->mpFrameData->mnFocusId = 0;
+
+ // Wenn Status erhalten geblieben ist, weil wir den Focus in der
+ // zwischenzeit schon wiederbekommen haben, brauchen wir auch
+ // nichts machen
+ BOOL bHasFocus = ImplGetWindowImpl()->mpFrameData->mbHasFocus || ImplGetWindowImpl()->mpFrameData->mbSysObjFocus;
+
+ // Dann die zeitverzoegerten Funktionen ausfuehren
+ if ( bHasFocus )
+ {
+ // Alle FloatingFenster deaktiv zeichnen
+ if ( ImplGetWindowImpl()->mpFrameData->mbStartFocusState != bHasFocus )
+ ImplActivateFloatingWindows( this, bHasFocus );
+
+ if ( ImplGetWindowImpl()->mpFrameData->mpFocusWin )
+ {
+ BOOL bHandled = FALSE;
+ if ( ImplGetWindowImpl()->mpFrameData->mpFocusWin->IsInputEnabled() &&
+ ! ImplGetWindowImpl()->mpFrameData->mpFocusWin->IsInModalMode() )
+ {
+ if ( ImplGetWindowImpl()->mpFrameData->mpFocusWin->IsEnabled() )
+ {
+ ImplGetWindowImpl()->mpFrameData->mpFocusWin->GrabFocus();
+ bHandled = TRUE;
+ }
+ else if( ImplGetWindowImpl()->mpFrameData->mpFocusWin->ImplHasDlgCtrl() )
+ {
+ // #109094# if the focus is restored to a disabled dialog control (was disabled meanwhile)
+ // try to move it to the next control
+ ImplGetWindowImpl()->mpFrameData->mpFocusWin->ImplDlgCtrlNextWindow();
+ bHandled = TRUE;
+ }
+ }
+ if ( !bHandled )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pTopLevelWindow = ImplGetWindowImpl()->mpFrameData->mpFocusWin->ImplGetFirstOverlapWindow();
+ if ( ( ! pTopLevelWindow->IsInputEnabled() || pTopLevelWindow->IsInModalMode() )
+ && pSVData->maWinData.mpLastExecuteDlg )
+ pSVData->maWinData.mpLastExecuteDlg->ToTop( TOTOP_RESTOREWHENMIN | TOTOP_GRABFOCUSONLY);
+ else
+ pTopLevelWindow->GrabFocus();
+ }
+ }
+ else
+ GrabFocus();
+ }
+ else
+ {
+ Window* pFocusWin = ImplGetWindowImpl()->mpFrameData->mpFocusWin;
+ if ( pFocusWin )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maWinData.mpFocusWin == pFocusWin )
+ {
+ // FocusWindow umsetzen
+ Window* pOverlapWindow = pFocusWin->ImplGetFirstOverlapWindow();
+ pOverlapWindow->ImplGetWindowImpl()->mpLastFocusWindow = pFocusWin;
+ pSVData->maWinData.mpFocusWin = NULL;
+
+ if ( pFocusWin->ImplGetWindowImpl()->mpCursor )
+ pFocusWin->ImplGetWindowImpl()->mpCursor->ImplHide();
+
+ // Deaktivate rufen
+ Window* pOldFocusWindow = pFocusWin;
+ if ( pOldFocusWindow )
+ {
+ Window* pOldOverlapWindow = pOldFocusWindow->ImplGetFirstOverlapWindow();
+ Window* pOldRealWindow = pOldOverlapWindow->ImplGetWindow();
+
+ pOldOverlapWindow->ImplGetWindowImpl()->mbActive = FALSE;
+ pOldOverlapWindow->Deactivate();
+ if ( pOldRealWindow != pOldOverlapWindow )
+ {
+ pOldRealWindow->ImplGetWindowImpl()->mbActive = FALSE;
+ pOldRealWindow->Deactivate();
+ }
+ }
+
+ // TrackingMode is ended in ImplHandleLoseFocus
+// To avoid problems with the Unix IME
+// pFocusWin->EndExtTextInput( EXTTEXTINPUT_END_COMPLETE );
+
+ // XXX #102010# hack for accessibility: do not close the menu,
+ // even after focus lost
+ static const char* pEnv = getenv("SAL_FLOATWIN_NOAPPFOCUSCLOSE");
+ if( !(pEnv && *pEnv) )
+ {
+ NotifyEvent aNEvt( EVENT_LOSEFOCUS, pFocusWin );
+ if ( !ImplCallPreNotify( aNEvt ) )
+ pFocusWin->LoseFocus();
+ pFocusWin->ImplCallDeactivateListeners( NULL );
+ GetpApp()->FocusChanged();
+ }
+ // XXX
+ }
+ }
+
+ // Alle FloatingFenster deaktiv zeichnen
+ if ( ImplGetWindowImpl()->mpFrameData->mbStartFocusState != bHasFocus )
+ ImplActivateFloatingWindows( this, bHasFocus );
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleGetFocus( Window* pWindow )
+{
+ pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus = TRUE;
+
+ // Focus-Events zeitverzoegert ausfuehren, damit bei SystemChildFenstern
+ // nicht alles flackert, wenn diese den Focus bekommen
+ if ( !pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId )
+ {
+ bool bCallDirect = ImplGetSVData()->mbIsTestTool;
+ pWindow->ImplGetWindowImpl()->mpFrameData->mbStartFocusState = !pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus;
+ if( ! bCallDirect )
+ Application::PostUserEvent( pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId, LINK( pWindow, Window, ImplAsyncFocusHdl ) );
+ Window* pFocusWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin;
+ if ( pFocusWin && pFocusWin->ImplGetWindowImpl()->mpCursor )
+ pFocusWin->ImplGetWindowImpl()->mpCursor->ImplShow();
+ if( bCallDirect )
+ pWindow->ImplAsyncFocusHdl( NULL );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleLoseFocus( Window* pWindow )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Wenn Frame den Focus verliert, brechen wir auch ein AutoScroll ab
+ if ( pSVData->maWinData.mpAutoScrollWin )
+ pSVData->maWinData.mpAutoScrollWin->EndAutoScroll();
+
+ // Wenn Frame den Focus verliert, brechen wir auch ein Tracking ab
+ if ( pSVData->maWinData.mpTrackWin )
+ {
+ if ( pSVData->maWinData.mpTrackWin->ImplGetWindowImpl()->mpFrameWindow == pWindow )
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL );
+ }
+
+ // handle FloatingMode
+ // hier beenden wir immer den PopupModus, auch dann, wenn NOFOCUSCLOSE
+ // gesetzt ist, damit wir nicht beim Wechsel noch Fenster stehen lassen
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+
+ pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus = FALSE;
+
+ // Focus-Events zeitverzoegert ausfuehren, damit bei SystemChildFenstern
+ // nicht alles flackert, wenn diese den Focus bekommen
+ bool bCallDirect = ImplGetSVData()->mbIsTestTool;
+ if ( !pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId )
+ {
+ pWindow->ImplGetWindowImpl()->mpFrameData->mbStartFocusState = !pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus;
+ if( ! bCallDirect )
+ Application::PostUserEvent( pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId, LINK( pWindow, Window, ImplAsyncFocusHdl ) );
+ }
+
+ Window* pFocusWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin;
+ if ( pFocusWin && pFocusWin->ImplGetWindowImpl()->mpCursor )
+ pFocusWin->ImplGetWindowImpl()->mpCursor->ImplHide();
+ if( bCallDirect )
+ pWindow->ImplAsyncFocusHdl( NULL );
+}
+
+// -----------------------------------------------------------------------
+struct DelayedCloseEvent
+{
+ Window* pWindow;
+ ImplDelData aDelData;
+};
+
+static long DelayedCloseEventLink( void* pCEvent, void* )
+{
+ DelayedCloseEvent* pEv = (DelayedCloseEvent*)pCEvent;
+
+ if( ! pEv->aDelData.IsDelete() )
+ {
+ pEv->pWindow->ImplRemoveDel( &pEv->aDelData );
+ // dispatch to correct window type
+ if( pEv->pWindow->IsSystemWindow() )
+ ((SystemWindow*)pEv->pWindow)->Close();
+ else if( pEv->pWindow->ImplIsDockingWindow() )
+ ((DockingWindow*)pEv->pWindow)->Close();
+ }
+ delete pEv;
+
+ return 0;
+}
+
+void ImplHandleClose( Window* pWindow )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ bool bWasPopup = false;
+ if( pWindow->ImplIsFloatingWindow() &&
+ static_cast<FloatingWindow*>(pWindow)->ImplIsInPrivatePopupMode() )
+ {
+ bWasPopup = true;
+ }
+
+ // on Close stop all floating modes and end popups
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ FloatingWindow* pLastLevelFloat;
+ pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
+ pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ if ( pSVData->maHelpData.mbExtHelpMode )
+ Help::EndExtHelp();
+ if ( pSVData->maHelpData.mpHelpWin )
+ ImplDestroyHelpWindow( false );
+ // AutoScrollMode
+ if ( pSVData->maWinData.mpAutoScrollWin )
+ pSVData->maWinData.mpAutoScrollWin->EndAutoScroll();
+
+ if ( pSVData->maWinData.mpTrackWin )
+ pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL | ENDTRACK_KEY );
+
+ if( ! bWasPopup )
+ {
+ Window *pWin = pWindow->ImplGetWindow();
+ // check whether close is allowed
+ if ( !pWin->IsEnabled() || !pWin->IsInputEnabled() || pWin->IsInModalMode() )
+ Sound::Beep( SOUND_DISABLE, pWin );
+ else
+ {
+ DelayedCloseEvent* pEv = new DelayedCloseEvent;
+ pEv->pWindow = pWin;
+ pWin->ImplAddDel( &pEv->aDelData );
+ Application::PostUserEvent( Link( pEv, DelayedCloseEventLink ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleUserEvent( ImplSVEvent* pSVEvent )
+{
+ if ( pSVEvent )
+ {
+ if ( pSVEvent->mbCall && !pSVEvent->maDelData.IsDelete() )
+ {
+ if ( pSVEvent->mpWindow )
+ {
+ pSVEvent->mpWindow->ImplRemoveDel( &(pSVEvent->maDelData) );
+ if ( pSVEvent->mpLink )
+ pSVEvent->mpLink->Call( pSVEvent->mpData );
+ else
+ pSVEvent->mpWindow->UserEvent( pSVEvent->mnEvent, pSVEvent->mpData );
+ }
+ else
+ {
+ if ( pSVEvent->mpLink )
+ pSVEvent->mpLink->Call( pSVEvent->mpData );
+ else
+ GetpApp()->UserEvent( pSVEvent->mnEvent, pSVEvent->mpData );
+ }
+ }
+
+ delete pSVEvent->mpLink;
+ delete pSVEvent;
+ }
+}
+
+// =======================================================================
+
+static USHORT ImplGetMouseMoveMode( SalMouseEvent* pEvent )
+{
+ USHORT nMode = 0;
+ if ( !pEvent->mnCode )
+ nMode |= MOUSE_SIMPLEMOVE;
+ if ( (pEvent->mnCode & MOUSE_LEFT) && !(pEvent->mnCode & KEY_MOD1) )
+ nMode |= MOUSE_DRAGMOVE;
+ if ( (pEvent->mnCode & MOUSE_LEFT) && (pEvent->mnCode & KEY_MOD1) )
+ nMode |= MOUSE_DRAGCOPY;
+ return nMode;
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplGetMouseButtonMode( SalMouseEvent* pEvent )
+{
+ USHORT nMode = 0;
+ if ( pEvent->mnButton == MOUSE_LEFT )
+ nMode |= MOUSE_SIMPLECLICK;
+ if ( (pEvent->mnButton == MOUSE_LEFT) && !(pEvent->mnCode & (MOUSE_MIDDLE | MOUSE_RIGHT)) )
+ nMode |= MOUSE_SELECT;
+ if ( (pEvent->mnButton == MOUSE_LEFT) && (pEvent->mnCode & KEY_MOD1) &&
+ !(pEvent->mnCode & (MOUSE_MIDDLE | MOUSE_RIGHT | KEY_SHIFT)) )
+ nMode |= MOUSE_MULTISELECT;
+ if ( (pEvent->mnButton == MOUSE_LEFT) && (pEvent->mnCode & KEY_SHIFT) &&
+ !(pEvent->mnCode & (MOUSE_MIDDLE | MOUSE_RIGHT | KEY_MOD1)) )
+ nMode |= MOUSE_RANGESELECT;
+ return nMode;
+}
+
+// -----------------------------------------------------------------------
+
+inline long ImplHandleSalMouseLeave( Window* pWindow, SalMouseEvent* pEvent )
+{
+ return ImplHandleMouseEvent( pWindow, EVENT_MOUSEMOVE, TRUE,
+ pEvent->mnX, pEvent->mnY,
+ pEvent->mnTime, pEvent->mnCode,
+ ImplGetMouseMoveMode( pEvent ) );
+}
+
+// -----------------------------------------------------------------------
+
+inline long ImplHandleSalMouseMove( Window* pWindow, SalMouseEvent* pEvent )
+{
+ return ImplHandleMouseEvent( pWindow, EVENT_MOUSEMOVE, FALSE,
+ pEvent->mnX, pEvent->mnY,
+ pEvent->mnTime, pEvent->mnCode,
+ ImplGetMouseMoveMode( pEvent ) );
+}
+
+// -----------------------------------------------------------------------
+
+inline long ImplHandleSalMouseButtonDown( Window* pWindow, SalMouseEvent* pEvent )
+{
+ return ImplHandleMouseEvent( pWindow, EVENT_MOUSEBUTTONDOWN, FALSE,
+ pEvent->mnX, pEvent->mnY,
+ pEvent->mnTime,
+#ifdef MACOSX
+ pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
+#else
+ pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
+#endif
+ ImplGetMouseButtonMode( pEvent ) );
+}
+
+// -----------------------------------------------------------------------
+
+inline long ImplHandleSalMouseButtonUp( Window* pWindow, SalMouseEvent* pEvent )
+{
+ return ImplHandleMouseEvent( pWindow, EVENT_MOUSEBUTTONUP, FALSE,
+ pEvent->mnX, pEvent->mnY,
+ pEvent->mnTime,
+#ifdef MACOSX
+ pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
+#else
+ pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
+#endif
+ ImplGetMouseButtonMode( pEvent ) );
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleSalMouseActivate( Window* /*pWindow*/, SalMouseActivateEvent* /*pEvent*/ )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleMenuEvent( Window* pWindow, SalMenuEvent* pEvent, USHORT nEvent )
+{
+ // Find SystemWindow and its Menubar and let it dispatch the command
+ long nRet = 0;
+ Window *pWin = pWindow->ImplGetWindowImpl()->mpFirstChild;
+ while ( pWin )
+ {
+ if ( pWin->ImplGetWindowImpl()->mbSysWin )
+ break;
+ pWin = pWin->ImplGetWindowImpl()->mpNext;
+ }
+ if( pWin )
+ {
+ MenuBar *pMenuBar = ((SystemWindow*) pWin)->GetMenuBar();
+ if( pMenuBar )
+ {
+ switch( nEvent )
+ {
+ case SALEVENT_MENUACTIVATE:
+ nRet = pMenuBar->HandleMenuActivateEvent( (Menu*) pEvent->mpMenu ) ? 1 : 0;
+ break;
+ case SALEVENT_MENUDEACTIVATE:
+ nRet = pMenuBar->HandleMenuDeActivateEvent( (Menu*) pEvent->mpMenu ) ? 1 : 0;
+ break;
+ case SALEVENT_MENUHIGHLIGHT:
+ nRet = pMenuBar->HandleMenuHighlightEvent( (Menu*) pEvent->mpMenu, pEvent->mnId ) ? 1 : 0;
+ break;
+ case SALEVENT_MENUBUTTONCOMMAND:
+ nRet = pMenuBar->HandleMenuButtonEvent( (Menu*) pEvent->mpMenu, pEvent->mnId ) ? 1 : 0;
+ break;
+ case SALEVENT_MENUCOMMAND:
+ nRet = pMenuBar->HandleMenuCommandEvent( (Menu*) pEvent->mpMenu, pEvent->mnId ) ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSalKeyMod( Window* pWindow, SalKeyModEvent* pEvent )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ Window* pTrackWin = pSVData->maWinData.mpTrackWin;
+ if ( pTrackWin )
+ pWindow = pTrackWin;
+#ifdef MACOSX
+ USHORT nOldCode = pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3);
+#else
+ USHORT nOldCode = pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2);
+#endif
+ USHORT nNewCode = pEvent->mnCode;
+ if ( nOldCode != nNewCode )
+ {
+#ifdef MACOSX
+ nNewCode |= pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & ~(KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3);
+#else
+ nNewCode |= pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & ~(KEY_SHIFT | KEY_MOD1 | KEY_MOD2);
+#endif
+ pWindow->ImplGetWindowImpl()->mpFrameWindow->ImplCallMouseMove( nNewCode, TRUE );
+ }
+
+ // #105224# send commandevent to allow special treatment of Ctrl-LeftShift/Ctrl-RightShift etc.
+
+ // find window
+ Window* pChild = ImplGetKeyInputWindow( pWindow );
+ if ( !pChild )
+ return;
+
+ // send modkey events only if useful data is available
+ if( pEvent->mnModKeyCode != 0 )
+ {
+ CommandModKeyData data( pEvent->mnModKeyCode );
+ ImplCallCommand( pChild, COMMAND_MODKEYCHANGE, &data );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleInputLanguageChange( Window* pWindow )
+{
+ // find window
+ Window* pChild = ImplGetKeyInputWindow( pWindow );
+ if ( !pChild )
+ return;
+
+ ImplCallCommand( pChild, COMMAND_INPUTLANGUAGECHANGE );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSalSettings( Window* pWindow, USHORT nEvent )
+{
+ // Application Notification werden nur fuer das erste Window ausgeloest
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pWindow != pSVData->maWinData.mpFirstFrame )
+ return;
+
+ Application* pApp = GetpApp();
+ if ( !pApp )
+ return;
+
+ if ( nEvent == SALEVENT_SETTINGSCHANGED )
+ {
+ AllSettings aSettings = pApp->GetSettings();
+ pApp->MergeSystemSettings( aSettings );
+ pApp->SystemSettingsChanging( aSettings, pWindow );
+ pApp->SetSettings( aSettings );
+ }
+ else
+ {
+ USHORT nType;
+ switch ( nEvent )
+ {
+ case SALEVENT_VOLUMECHANGED:
+ nType = 0;
+ break;
+ case SALEVENT_PRINTERCHANGED:
+ ImplDeletePrnQueueList();
+ nType = DATACHANGED_PRINTER;
+ break;
+ case SALEVENT_DISPLAYCHANGED:
+ nType = DATACHANGED_DISPLAY;
+ break;
+ case SALEVENT_FONTCHANGED:
+ OutputDevice::ImplUpdateAllFontData( TRUE );
+ nType = DATACHANGED_FONTS;
+ break;
+ case SALEVENT_DATETIMECHANGED:
+ nType = DATACHANGED_DATETIME;
+ break;
+ case SALEVENT_KEYBOARDCHANGED:
+ nType = 0;
+ break;
+ default:
+ nType = 0;
+ break;
+ }
+
+ if ( nType )
+ {
+ DataChangedEvent aDCEvt( nType );
+ pApp->DataChanged( aDCEvt );
+ pApp->NotifyAllWindows( aDCEvt );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSalExtTextInputPos( Window* pWindow, SalExtTextInputPosEvent* pEvt )
+{
+ Rectangle aCursorRect;
+ ImplHandleExtTextInputPos( pWindow, aCursorRect, pEvt->mnExtWidth, &pEvt->mbVertical );
+ if ( aCursorRect.IsEmpty() )
+ {
+ pEvt->mnX = -1;
+ pEvt->mnY = -1;
+ pEvt->mnWidth = -1;
+ pEvt->mnHeight = -1;
+ }
+ else
+ {
+ pEvt->mnX = aCursorRect.Left();
+ pEvt->mnY = aCursorRect.Top();
+ pEvt->mnWidth = aCursorRect.GetWidth();
+ pEvt->mnHeight = aCursorRect.GetHeight();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleShowDialog( Window* pWindow, int nDialogId )
+{
+ if( ! pWindow )
+ return FALSE;
+
+ if( pWindow->GetType() == WINDOW_BORDERWINDOW )
+ {
+ Window* pWrkWin = pWindow->GetWindow( WINDOW_CLIENT );
+ if( pWrkWin )
+ pWindow = pWrkWin;
+ }
+ CommandDialogData aCmdData( nDialogId );
+ return ImplCallCommand( pWindow, COMMAND_SHOWDIALOG, &aCmdData );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSurroundingTextRequest( Window *pWindow,
+ XubString& rText,
+ Selection &rSelRange )
+{
+ Window* pChild = ImplGetKeyInputWindow( pWindow );
+
+ if ( !pChild )
+ {
+ rText = XubString::EmptyString();
+ rSelRange.setMin( 0 );
+ rSelRange.setMax( 0 );
+ }
+ else
+ {
+
+ rText = pChild->GetSurroundingText();
+ Selection aSel = pChild->GetSurroundingTextSelection();
+ rSelRange.setMin( aSel.Min() );
+ rSelRange.setMax( aSel.Max() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSalSurroundingTextRequest( Window *pWindow,
+ SalSurroundingTextRequestEvent *pEvt )
+{
+ Selection aSelRange;
+ ImplHandleSurroundingTextRequest( pWindow, pEvt->maText, aSelRange );
+
+ aSelRange.Justify();
+
+ if( aSelRange.Min() < 0 )
+ pEvt->mnStart = 0;
+ else if( aSelRange.Min() > pEvt->maText.Len() )
+ pEvt->mnStart = pEvt->maText.Len();
+ else
+ pEvt->mnStart = aSelRange.Min();
+
+ if( aSelRange.Max() < 0 )
+ pEvt->mnStart = 0;
+ else if( aSelRange.Max() > pEvt->maText.Len() )
+ pEvt->mnEnd = pEvt->maText.Len();
+ else
+ pEvt->mnEnd = aSelRange.Max();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSurroundingTextSelectionChange( Window *pWindow,
+ ULONG nStart,
+ ULONG nEnd )
+{
+ Window* pChild = ImplGetKeyInputWindow( pWindow );
+ if( pChild )
+ {
+ CommandSelectionChangeData data( nStart, nEnd );
+ ImplCallCommand( pChild, COMMAND_SELECTIONCHANGE, &data );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleStartReconversion( Window *pWindow )
+{
+ Window* pChild = ImplGetKeyInputWindow( pWindow );
+ if( pChild )
+ ImplCallCommand( pChild, COMMAND_PREPARERECONVERSION );
+}
+
+// -----------------------------------------------------------------------
+
+long ImplWindowFrameProc( Window* pWindow, SalFrame* /*pFrame*/,
+ USHORT nEvent, const void* pEvent )
+{
+ DBG_TESTSOLARMUTEX();
+
+ long nRet = 0;
+
+ // #119709# for some unknown reason it is possible to receive events (in this case key events)
+ // although the corresponding VCL window must have been destroyed already
+ // at least ImplGetWindowImpl() was NULL in these cases, so check this here
+ if( pWindow->ImplGetWindowImpl() == NULL )
+ return 0;
+
+ switch ( nEvent )
+ {
+ case SALEVENT_MOUSEMOVE:
+ nRet = ImplHandleSalMouseMove( pWindow, (SalMouseEvent*)pEvent );
+ break;
+ case SALEVENT_EXTERNALMOUSEMOVE:
+ {
+ MouseEvent* pMouseEvt = (MouseEvent*) pEvent;
+ SalMouseEvent aSalMouseEvent;
+
+ aSalMouseEvent.mnTime = Time::GetSystemTicks();
+ aSalMouseEvent.mnX = pMouseEvt->GetPosPixel().X();
+ aSalMouseEvent.mnY = pMouseEvt->GetPosPixel().Y();
+ aSalMouseEvent.mnButton = 0;
+ aSalMouseEvent.mnCode = pMouseEvt->GetButtons() | pMouseEvt->GetModifier();
+
+ nRet = ImplHandleSalMouseMove( pWindow, &aSalMouseEvent );
+ }
+ break;
+ case SALEVENT_MOUSELEAVE:
+ nRet = ImplHandleSalMouseLeave( pWindow, (SalMouseEvent*)pEvent );
+ break;
+ case SALEVENT_MOUSEBUTTONDOWN:
+ nRet = ImplHandleSalMouseButtonDown( pWindow, (SalMouseEvent*)pEvent );
+ break;
+ case SALEVENT_EXTERNALMOUSEBUTTONDOWN:
+ {
+ MouseEvent* pMouseEvt = (MouseEvent*) pEvent;
+ SalMouseEvent aSalMouseEvent;
+
+ aSalMouseEvent.mnTime = Time::GetSystemTicks();
+ aSalMouseEvent.mnX = pMouseEvt->GetPosPixel().X();
+ aSalMouseEvent.mnY = pMouseEvt->GetPosPixel().Y();
+ aSalMouseEvent.mnButton = pMouseEvt->GetButtons();
+ aSalMouseEvent.mnCode = pMouseEvt->GetButtons() | pMouseEvt->GetModifier();
+
+ nRet = ImplHandleSalMouseButtonDown( pWindow, &aSalMouseEvent );
+ }
+ break;
+ case SALEVENT_MOUSEBUTTONUP:
+ nRet = ImplHandleSalMouseButtonUp( pWindow, (SalMouseEvent*)pEvent );
+ break;
+ case SALEVENT_EXTERNALMOUSEBUTTONUP:
+ {
+ MouseEvent* pMouseEvt = (MouseEvent*) pEvent;
+ SalMouseEvent aSalMouseEvent;
+
+ aSalMouseEvent.mnTime = Time::GetSystemTicks();
+ aSalMouseEvent.mnX = pMouseEvt->GetPosPixel().X();
+ aSalMouseEvent.mnY = pMouseEvt->GetPosPixel().Y();
+ aSalMouseEvent.mnButton = pMouseEvt->GetButtons();
+ aSalMouseEvent.mnCode = pMouseEvt->GetButtons() | pMouseEvt->GetModifier();
+
+ nRet = ImplHandleSalMouseButtonUp( pWindow, &aSalMouseEvent );
+ }
+ break;
+ case SALEVENT_MOUSEACTIVATE:
+ nRet = ImplHandleSalMouseActivate( pWindow, (SalMouseActivateEvent*)pEvent );
+ break;
+ case SALEVENT_KEYINPUT:
+ {
+ SalKeyEvent* pKeyEvt = (SalKeyEvent*)pEvent;
+ nRet = ImplHandleKey( pWindow, EVENT_KEYINPUT,
+ pKeyEvt->mnCode, pKeyEvt->mnCharCode, pKeyEvt->mnRepeat, TRUE );
+ }
+ break;
+ case SALEVENT_EXTERNALKEYINPUT:
+ {
+ KeyEvent* pKeyEvt = (KeyEvent*) pEvent;
+ nRet = ImplHandleKey( pWindow, EVENT_KEYINPUT,
+ pKeyEvt->GetKeyCode().GetFullCode(), pKeyEvt->GetCharCode(), pKeyEvt->GetRepeat(), FALSE );
+ }
+ break;
+ case SALEVENT_KEYUP:
+ {
+ SalKeyEvent* pKeyEvt = (SalKeyEvent*)pEvent;
+ nRet = ImplHandleKey( pWindow, EVENT_KEYUP,
+ pKeyEvt->mnCode, pKeyEvt->mnCharCode, pKeyEvt->mnRepeat, TRUE );
+ }
+ break;
+ case SALEVENT_EXTERNALKEYUP:
+ {
+ KeyEvent* pKeyEvt = (KeyEvent*) pEvent;
+ nRet = ImplHandleKey( pWindow, EVENT_KEYUP,
+ pKeyEvt->GetKeyCode().GetFullCode(), pKeyEvt->GetCharCode(), pKeyEvt->GetRepeat(), FALSE );
+ }
+ break;
+ case SALEVENT_KEYMODCHANGE:
+ ImplHandleSalKeyMod( pWindow, (SalKeyModEvent*)pEvent );
+ break;
+
+ case SALEVENT_INPUTLANGUAGECHANGE:
+ ImplHandleInputLanguageChange( pWindow );
+ break;
+
+ case SALEVENT_MENUACTIVATE:
+ case SALEVENT_MENUDEACTIVATE:
+ case SALEVENT_MENUHIGHLIGHT:
+ case SALEVENT_MENUCOMMAND:
+ case SALEVENT_MENUBUTTONCOMMAND:
+ nRet = ImplHandleMenuEvent( pWindow, (SalMenuEvent*)pEvent, nEvent );
+ break;
+
+ case SALEVENT_WHEELMOUSE:
+ nRet = ImplHandleWheelEvent( pWindow, *(const SalWheelMouseEvent*)pEvent);
+ break;
+
+ case SALEVENT_PAINT:
+ {
+ SalPaintEvent* pPaintEvt = (SalPaintEvent*)pEvent;
+
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ // --- RTL --- (mirror paint rect)
+ SalFrame* pSalFrame = pWindow->ImplGetWindowImpl()->mpFrame;
+ pPaintEvt->mnBoundX = pSalFrame->maGeometry.nWidth-pPaintEvt->mnBoundWidth-pPaintEvt->mnBoundX;
+ }
+
+ Rectangle aBoundRect( Point( pPaintEvt->mnBoundX, pPaintEvt->mnBoundY ),
+ Size( pPaintEvt->mnBoundWidth, pPaintEvt->mnBoundHeight ) );
+ ImplHandlePaint( pWindow, aBoundRect, pPaintEvt->mbImmediateUpdate );
+ }
+ break;
+
+ case SALEVENT_MOVE:
+ ImplHandleMove( pWindow );
+ break;
+
+ case SALEVENT_RESIZE:
+ {
+ long nNewWidth;
+ long nNewHeight;
+ pWindow->ImplGetWindowImpl()->mpFrame->GetClientSize( nNewWidth, nNewHeight );
+ ImplHandleResize( pWindow, nNewWidth, nNewHeight );
+ }
+ break;
+
+ case SALEVENT_MOVERESIZE:
+ {
+ SalFrameGeometry g = pWindow->ImplGetWindowImpl()->mpFrame->GetGeometry();
+ ImplHandleMoveResize( pWindow, g.nWidth, g.nHeight );
+ }
+ break;
+
+ case SALEVENT_CLOSEPOPUPS:
+ {
+ KillOwnPopups( pWindow );
+ }
+ break;
+
+ case SALEVENT_GETFOCUS:
+ ImplHandleGetFocus( pWindow );
+ break;
+ case SALEVENT_LOSEFOCUS:
+ ImplHandleLoseFocus( pWindow );
+ break;
+
+ case SALEVENT_CLOSE:
+ ImplHandleClose( pWindow );
+ break;
+
+ case SALEVENT_SHUTDOWN:
+ {
+ static bool bInQueryExit = false;
+ if( !bInQueryExit )
+ {
+ bInQueryExit = true;
+ if ( GetpApp()->QueryExit() )
+ {
+ // Message-Schleife beenden
+ Application::Quit();
+ return FALSE;
+ }
+ else
+ {
+ bInQueryExit = false;
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ case SALEVENT_SETTINGSCHANGED:
+ case SALEVENT_VOLUMECHANGED:
+ case SALEVENT_PRINTERCHANGED:
+ case SALEVENT_DISPLAYCHANGED:
+ case SALEVENT_FONTCHANGED:
+ case SALEVENT_DATETIMECHANGED:
+ case SALEVENT_KEYBOARDCHANGED:
+ ImplHandleSalSettings( pWindow, nEvent );
+ break;
+
+ case SALEVENT_USEREVENT:
+ ImplHandleUserEvent( (ImplSVEvent*)pEvent );
+ break;
+
+ case SALEVENT_EXTTEXTINPUT:
+ {
+ SalExtTextInputEvent* pEvt = (SalExtTextInputEvent*)pEvent;
+ nRet = ImplHandleExtTextInput( pWindow,
+ pEvt->maText, pEvt->mpTextAttr,
+ pEvt->mnCursorPos, pEvt->mnCursorFlags );
+ }
+ break;
+ case SALEVENT_ENDEXTTEXTINPUT:
+ nRet = ImplHandleEndExtTextInput( pWindow );
+ break;
+ case SALEVENT_EXTTEXTINPUTPOS:
+ ImplHandleSalExtTextInputPos( pWindow, (SalExtTextInputPosEvent*)pEvent );
+ break;
+ case SALEVENT_INPUTCONTEXTCHANGE:
+ nRet = ImplHandleInputContextChange( pWindow, ((SalInputContextChangeEvent*)pEvent)->meLanguage );
+ break;
+ case SALEVENT_SHOWDIALOG:
+ {
+ int nDialogID = static_cast<int>(reinterpret_cast<sal_IntPtr>(pEvent));
+ nRet = ImplHandleShowDialog( pWindow, nDialogID );
+ }
+ break;
+ case SALEVENT_SURROUNDINGTEXTREQUEST:
+ ImplHandleSalSurroundingTextRequest( pWindow, (SalSurroundingTextRequestEvent*)pEvent );
+ break;
+ case SALEVENT_SURROUNDINGTEXTSELECTIONCHANGE:
+ {
+ SalSurroundingTextSelectionChangeEvent* pEvt
+ = (SalSurroundingTextSelectionChangeEvent*)pEvent;
+ ImplHandleSurroundingTextSelectionChange( pWindow,
+ pEvt->mnStart,
+ pEvt->mnEnd );
+ }
+ case SALEVENT_STARTRECONVERSION:
+ ImplHandleStartReconversion( pWindow );
+ break;
+#ifdef DBG_UTIL
+ default:
+ DBG_ERROR1( "ImplWindowFrameProc(): unknown event (%lu)", (ULONG)nEvent );
+ break;
+#endif
+ }
+
+ return nRet;
+}
diff --git a/vcl/source/window/wrkwin.cxx b/vcl/source/window/wrkwin.cxx
new file mode 100644
index 000000000000..8fb2f2f8346a
--- /dev/null
+++ b/vcl/source/window/wrkwin.cxx
@@ -0,0 +1,323 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_SVSYS_HXX
+#include <svsys.h>
+#endif
+#include <vcl/salframe.hxx>
+#include <tools/debug.hxx>
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/brdwin.hxx>
+#include <vcl/window.h>
+#include <vcl/wrkwin.hxx>
+#include <vcl/sysdata.hxx>
+
+// =======================================================================
+
+#define WORKWIN_WINDOWSTATE_FULLSCREEN ((ULONG)0x00010000)
+#define WORKWIN_WINDOWSTATE_ALL ((ULONG)0x00FF0000)
+
+// =======================================================================
+
+void WorkWindow::ImplInitWorkWindowData()
+{
+ mnIcon = 0; // Should be removed in the next top level update - now in SystemWindow
+
+ mnPresentationFlags = 0;
+ mbPresentationMode = FALSE;
+ mbPresentationVisible = FALSE;
+ mbPresentationFull = FALSE;
+ mbFullScreenMode = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void WorkWindow::ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData )
+{
+ USHORT nFrameStyle = BORDERWINDOW_STYLE_FRAME;
+ if ( nStyle & WB_APP )
+ nFrameStyle |= BORDERWINDOW_STYLE_APP;
+
+ ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, pSystemParentData, nStyle, nFrameStyle );
+ Window::ImplInit( pBorderWin, nStyle & (WB_3DLOOK | WB_CLIPCHILDREN | WB_DIALOGCONTROL | WB_SYSTEMFLOATWIN), NULL );
+ pBorderWin->mpWindowImpl->mpClientWindow = this;
+ pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
+ mpWindowImpl->mpBorderWindow = pBorderWin;
+// mpWindowImpl->mpRealParent = pParent; // !!! Muesste eigentlich gesetzt werden, aber wegen Fehlern mit dem MenuBar erstmal nicht gesetzt !!!
+
+ if ( nStyle & WB_APP )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ DBG_ASSERT( !pSVData->maWinData.mpAppWin, "WorkWindow::WorkWindow(): More than one window with style WB_APP" );
+ pSVData->maWinData.mpAppWin = this;
+ }
+
+ SetActivateMode( ACTIVATE_MODE_GRABFOCUS );
+}
+
+// -----------------------------------------------------------------------
+
+void WorkWindow::ImplInit( Window* pParent, WinBits nStyle, const ::com::sun::star::uno::Any& aSystemWorkWindowToken )
+{
+ if( aSystemWorkWindowToken.hasValue() )
+ {
+ ::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
+ aSystemWorkWindowToken >>= aSeq;
+ SystemParentData* pData = (SystemParentData*)aSeq.getArray();
+ DBG_ASSERT( aSeq.getLength() == sizeof( SystemParentData ) && pData->nSize == sizeof( SystemParentData ), "WorkWindow::WorkWindow( Window*, const Any&, WinBits ) called with invalid Any" );
+ // init with style 0 as does WorkWindow::WorkWindow( SystemParentData* );
+ ImplInit( pParent, 0, pData );
+ }
+ else
+ ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+WorkWindow::WorkWindow( WindowType nType ) :
+ SystemWindow( nType )
+{
+ ImplInitWorkWindowData();
+}
+
+// -----------------------------------------------------------------------
+
+WorkWindow::WorkWindow( Window* pParent, WinBits nStyle ) :
+ SystemWindow( WINDOW_WORKWINDOW )
+{
+ ImplInitWorkWindowData();
+ ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+WorkWindow::WorkWindow( Window* pParent, const ResId& rResId ) :
+ SystemWindow( WINDOW_WORKWINDOW )
+{
+ ImplInitWorkWindowData();
+ rResId.SetRT( RSC_WORKWIN );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+}
+
+// -----------------------------------------------------------------------
+
+WorkWindow::WorkWindow( Window* pParent, const ::com::sun::star::uno::Any& aSystemWorkWindowToken, WinBits nStyle ) :
+ SystemWindow( WINDOW_WORKWINDOW )
+{
+ ImplInitWorkWindowData();
+ mbSysChild = TRUE;
+ ImplInit( pParent, nStyle, aSystemWorkWindowToken );
+}
+
+// -----------------------------------------------------------------------
+
+WorkWindow::WorkWindow( SystemParentData* pParent ) :
+ SystemWindow( WINDOW_WORKWINDOW )
+{
+ ImplInitWorkWindowData();
+ mbSysChild = TRUE;
+ ImplInit( NULL, 0, pParent );
+}
+
+// -----------------------------------------------------------------------
+
+void WorkWindow::ImplLoadRes( const ResId& rResId )
+{
+ SystemWindow::ImplLoadRes( rResId );
+
+ ReadLongRes();
+ if ( !(rResId.GetWinBits() & WB_HIDE) && (RSC_WORKWIN == rResId.GetRT()) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+WorkWindow::~WorkWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpAppWin == this )
+ {
+ pSVData->maWinData.mpAppWin = NULL;
+ Application::Quit();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WorkWindow::ShowFullScreenMode( BOOL bFullScreenMode, sal_Int32 nDisplay )
+{
+ if ( !mbFullScreenMode == !bFullScreenMode )
+ return;
+
+ if( (nDisplay < 0)
+ || (nDisplay >= static_cast<sal_Int32>(Application::GetScreenCount()) ) )
+ {
+ nDisplay = GetScreenNumber();
+ }
+
+ mbFullScreenMode = bFullScreenMode != 0;
+ if ( !mbSysChild )
+ {
+ mpWindowImpl->mpFrameWindow->mpWindowImpl->mbWaitSystemResize = TRUE;
+ ImplGetFrame()->ShowFullScreen( bFullScreenMode, nDisplay );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WorkWindow::StartPresentationMode( BOOL bPresentation, USHORT nFlags, sal_Int32 nDisplay )
+{
+ if ( !bPresentation == !mbPresentationMode )
+ return;
+
+ if ( bPresentation )
+ {
+ mbPresentationMode = TRUE;
+ mbPresentationVisible = IsVisible();
+ mbPresentationFull = mbFullScreenMode;
+ mnPresentationFlags = nFlags;
+
+ if ( !(mnPresentationFlags & PRESENTATION_NOFULLSCREEN) )
+ ShowFullScreenMode( TRUE, nDisplay );
+ if ( !mbSysChild )
+ {
+ if ( mnPresentationFlags & PRESENTATION_HIDEALLAPPS )
+ mpWindowImpl->mpFrame->SetAlwaysOnTop( TRUE );
+ if ( !(mnPresentationFlags & PRESENTATION_NOAUTOSHOW) )
+ ToTop();
+ mpWindowImpl->mpFrame->StartPresentation( TRUE );
+ }
+
+ if ( !(mnPresentationFlags & PRESENTATION_NOAUTOSHOW) )
+ Show();
+ }
+ else
+ {
+ Show( mbPresentationVisible );
+ if ( !mbSysChild )
+ {
+ mpWindowImpl->mpFrame->StartPresentation( FALSE );
+ if ( mnPresentationFlags & PRESENTATION_HIDEALLAPPS )
+ mpWindowImpl->mpFrame->SetAlwaysOnTop( FALSE );
+ }
+ ShowFullScreenMode( mbPresentationFull, nDisplay );
+
+ mbPresentationMode = FALSE;
+ mbPresentationVisible = FALSE;
+ mbPresentationFull = FALSE;
+ mnPresentationFlags = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WorkWindow::IsMinimized() const
+{
+ //return mpWindowImpl->mpFrameData->mbMinimized;
+ SalFrameState aState;
+ mpWindowImpl->mpFrame->GetWindowState(&aState);
+ return (( aState.mnState & SAL_FRAMESTATE_MINIMIZED ) != 0);
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WorkWindow::SetPluginParent( SystemParentData* pParent )
+{
+ DBG_ASSERT( ! mbPresentationMode && ! mbFullScreenMode, "SetPluginParent in fullscreen or presentation mode !" );
+
+ bool bWasDnd = Window::ImplStopDnd();
+
+ BOOL bShown = IsVisible();
+ Show( FALSE );
+ BOOL bRet = mpWindowImpl->mpFrame->SetPluginParent( pParent );
+ Show( bShown );
+
+ if( bWasDnd )
+ Window::ImplStartDnd();
+
+ return bRet;
+}
+
+void WorkWindow::ImplSetFrameState( ULONG aFrameState )
+{
+ SalFrameState aState;
+ aState.mnMask = SAL_FRAMESTATE_MASK_STATE;
+ aState.mnState = aFrameState;
+ mpWindowImpl->mpFrame->SetWindowState( &aState );
+}
+
+
+void WorkWindow::Minimize()
+{
+ ImplSetFrameState( SAL_FRAMESTATE_MINIMIZED );
+}
+
+void WorkWindow::Restore()
+{
+ ImplSetFrameState( SAL_FRAMESTATE_NORMAL );
+}
+
+BOOL WorkWindow::Close()
+{
+ BOOL bCanClose = SystemWindow::Close();
+
+ // Ist es das Applikationsfenster, dann beende die Applikation
+ if ( bCanClose && ( ImplGetSVData()->maWinData.mpAppWin == this ) )
+ GetpApp()->Quit();
+
+ return bCanClose;
+}
+
+void WorkWindow::Maximize( BOOL bMaximize )
+{
+ ImplSetFrameState( bMaximize ? SAL_FRAMESTATE_MAXIMIZED : SAL_FRAMESTATE_NORMAL );
+}
+
+BOOL WorkWindow::IsMaximized() const
+{
+ BOOL bRet = FALSE;
+
+ SalFrameState aState;
+ if( mpWindowImpl->mpFrame->GetWindowState( &aState ) )
+ {
+ if( aState.mnState & (SAL_FRAMESTATE_MAXIMIZED |
+ SAL_FRAMESTATE_MAXIMIZED_HORZ |
+ SAL_FRAMESTATE_MAXIMIZED_VERT ) )
+ bRet = TRUE;
+ }
+ return bRet;
+}